blob: dbca35a8f5c7ba9d937554a444671facaa17aa8e [file] [log] [blame]
Andres Moralesda8706f2015-04-29 12:46:49 -07001package main
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "path"
8 "strings"
9
10 bpparser "github.com/google/blueprint/parser"
11)
12
13type androidMkWriter struct {
14 *bufio.Writer
15
16 file *bpparser.File
17 path string
18}
19
20func (w *androidMkWriter) valueToString(value bpparser.Value) string {
21 if value.Variable != "" {
22 return fmt.Sprintf("$(%s)", value.Variable)
23 } else {
24 switch value.Type {
25 case bpparser.Bool:
26 return fmt.Sprintf(`"%t"`, value.BoolValue)
27 case bpparser.String:
28 return fmt.Sprintf(`"%s"`, value.StringValue)
29 case bpparser.List:
30 return fmt.Sprintf("\\\n%s\n", w.listToMkString(value.ListValue))
31 case bpparser.Map:
32 w.errorf("maps not supported in assignment")
33 return "ERROR: unsupported type map in assignment"
34 }
35 }
36
37 return ""
38}
39
40func (w *androidMkWriter) listToMkString(list []bpparser.Value) string {
41 lines := make([]string, 0, len(list))
42 for _, tok := range list {
43 lines = append(lines, fmt.Sprintf("\t\"%s\"", tok.StringValue))
44 }
45
46 return strings.Join(lines, " \\\n")
47}
48
49func (w *androidMkWriter) errorf(format string, values ...interface{}) {
50 s := fmt.Sprintf(format, values)
51 w.WriteString("# ANDROIDBP ERROR:\n")
52 for _, line := range strings.Split(s, "\n") {
53 fmt.Fprintf(w, "# %s\n", line)
54 }
55}
56
57func (w *androidMkWriter) handleComment(comment *bpparser.Comment) {
58 for _, c := range comment.Comment {
59 mkComment := strings.Replace(c, "//", "#", 1)
60 // TODO: handle /* comments?
61 fmt.Fprintf(w, "%s\n", mkComment)
62 }
63}
64
65func (w *androidMkWriter) handleModule(module *bpparser.Module) {
66 if moduleName, ok := moduleTypes[module.Type.Name]; ok {
67 w.WriteString("include $(CLEAR_VARS)\n")
68 standardProps := make([]string, 0, len(module.Properties))
69 //condProps := make([]string, len(module.Properties))
70 for _, prop := range module.Properties {
71 if mkProp, ok := standardProperties[prop.Name.Name]; ok {
72 standardProps = append(standardProps, fmt.Sprintf("%s := %s", mkProp.string,
73 w.valueToString(prop.Value)))
74 }
75 }
76
77 mkModule := strings.Join(standardProps, "\n")
78 w.WriteString(mkModule)
79
80 fmt.Fprintf(w, "include $(%s)\n\n", moduleName)
81 } else {
82 w.errorf("Unsupported module %s", module.Type.Name)
83 }
84}
85
86func (w *androidMkWriter) handleAssignment(assignment *bpparser.Assignment) {
87 assigner := ":="
88 if assignment.Assigner != "=" {
89 assigner = assignment.Assigner
90 }
91 fmt.Fprintf(w, "%s %s %s\n", assignment.Name.Name, assigner,
92 w.valueToString(assignment.OrigValue))
93}
94
95func (w *androidMkWriter) iter() <-chan interface{} {
96 ch := make(chan interface{}, len(w.file.Comments)+len(w.file.Defs))
97 go func() {
98 commIdx := 0
99 defsIdx := 0
100 for defsIdx < len(w.file.Defs) || commIdx < len(w.file.Comments) {
101 if defsIdx == len(w.file.Defs) {
102 ch <- w.file.Comments[commIdx]
103 commIdx++
104 } else if commIdx == len(w.file.Comments) {
105 ch <- w.file.Defs[defsIdx]
106 defsIdx++
107 } else {
108 commentsPos := 0
109 defsPos := 0
110
111 def := w.file.Defs[defsIdx]
112 switch def := def.(type) {
113 case *bpparser.Module:
114 defsPos = def.LbracePos.Line
115 case *bpparser.Assignment:
116 defsPos = def.Pos.Line
117 }
118
119 comment := w.file.Comments[commIdx]
120 commentsPos = comment.Pos.Line
121
122 if commentsPos < defsPos {
123 commIdx++
124 ch <- comment
125 } else {
126 defsIdx++
127 ch <- def
128 }
129 }
130 }
131 close(ch)
132 }()
133 return ch
134}
135
136func (w *androidMkWriter) write() {
137 outFilePath := fmt.Sprintf("%s/Android.mk.out", w.path)
138 fmt.Printf("Writing %s\n", outFilePath)
139
140 f, err := os.Create(outFilePath)
141 if err != nil {
142 panic(err)
143 }
144
145 defer func() {
146 if err := f.Close(); err != nil {
147 panic(err)
148 }
149 }()
150
151 w.Writer = bufio.NewWriter(f)
152
153 for block := range w.iter() {
154 switch block := block.(type) {
155 case *bpparser.Module:
156 w.handleModule(block)
157 case *bpparser.Assignment:
158 w.handleAssignment(block)
159 case bpparser.Comment:
160 w.handleComment(&block)
161 }
162 }
163
164 if err = w.Flush(); err != nil {
165 panic(err)
166 }
167}
168
169func main() {
170 if len(os.Args) < 2 {
171 fmt.Println("No filename supplied")
172 return
173 }
174
175 reader, err := os.Open(os.Args[1])
176 if err != nil {
177 fmt.Println(err.Error())
178 return
179 }
180
181 scope := bpparser.NewScope(nil)
182 file, errs := bpparser.Parse(os.Args[1], reader, scope)
183 if len(errs) > 0 {
184 fmt.Println("%d errors parsing %s", len(errs), os.Args[1])
185 fmt.Println(errs)
186 return
187 }
188
189 writer := &androidMkWriter{
190 file: file,
191 path: path.Dir(os.Args[1]),
192 }
193
194 writer.write()
195}