1
16
17
18
19
20
21 package convertast
22
23 import (
24 "fmt"
25 "strconv"
26 "strings"
27
28 "github.com/bazelbuild/buildtools/build"
29 "go.starlark.net/syntax"
30 )
31
32 func ConvFile(f *syntax.File) *build.File {
33 stmts := []build.Expr{}
34 for _, stmt := range f.Stmts {
35 stmts = append(stmts, convStmt(stmt))
36 }
37
38 return &build.File{
39 Type: build.TypeDefault,
40 Stmt: stmts,
41 Comments: convComments(f.Comments()),
42 }
43 }
44
45 func convStmt(stmt syntax.Stmt) build.Expr {
46 switch stmt := stmt.(type) {
47 case *syntax.ExprStmt:
48 s := convExpr(stmt.X)
49 *s.Comment() = convComments(stmt.Comments())
50 return s
51 case *syntax.BranchStmt:
52 return &build.BranchStmt{
53 Token: stmt.Token.String(),
54 Comments: convComments(stmt.Comments()),
55 }
56 case *syntax.LoadStmt:
57 load := &build.LoadStmt{
58 Module: convExpr(stmt.Module).(*build.StringExpr),
59 ForceCompact: singleLine(stmt),
60 }
61 for _, ident := range stmt.From {
62 load.From = append(load.From, convExpr(ident).(*build.Ident))
63 }
64 for _, ident := range stmt.To {
65 load.To = append(load.To, convExpr(ident).(*build.Ident))
66 }
67 return load
68 case *syntax.AssignStmt:
69 return &build.AssignExpr{
70 Op: stmt.Op.String(),
71 LHS: convExpr(stmt.LHS),
72 RHS: convExpr(stmt.RHS),
73 Comments: convComments(stmt.Comments()),
74 }
75 case *syntax.IfStmt:
76 return &build.IfStmt{
77 Cond: convExpr(stmt.Cond),
78 True: convStmts(stmt.True),
79 False: convStmts(stmt.False),
80 Comments: convComments(stmt.Comments()),
81 }
82 case *syntax.DefStmt:
83 return &build.DefStmt{
84 Name: stmt.Name.Name,
85 Comments: convComments(stmt.Comments()),
86 Function: build.Function{
87 Params: convExprs(stmt.Params),
88 Body: convStmts(stmt.Body),
89 },
90 }
91 case *syntax.ForStmt:
92 return &build.ForStmt{
93 Vars: convExpr(stmt.Vars),
94 X: convExpr(stmt.X),
95 Comments: convComments(stmt.Comments()),
96 Body: convStmts(stmt.Body),
97 }
98 case *syntax.ReturnStmt:
99 return &build.ReturnStmt{
100 Comments: convComments(stmt.Comments()),
101 Result: convExpr(stmt.Result),
102 }
103 }
104 panic("unreachable")
105 }
106
107 func convStmts(list []syntax.Stmt) []build.Expr {
108 res := []build.Expr{}
109 for _, i := range list {
110 res = append(res, convStmt(i))
111 }
112 return res
113 }
114
115 func convExprs(list []syntax.Expr) []build.Expr {
116 res := []build.Expr{}
117 for _, i := range list {
118 res = append(res, convExpr(i))
119 }
120 return res
121 }
122
123 func convCommentList(list []syntax.Comment, txt string) []build.Comment {
124 res := []build.Comment{}
125 for _, c := range list {
126 res = append(res, build.Comment{Token: c.Text})
127 }
128 return res
129 }
130
131 func convComments(c *syntax.Comments) build.Comments {
132 if c == nil {
133 return build.Comments{}
134 }
135 return build.Comments{
136 Before: convCommentList(c.Before, "before"),
137 Suffix: convCommentList(c.Suffix, "suffix"),
138 After: convCommentList(c.After, "after"),
139 }
140 }
141
142
143 func singleLine(n syntax.Node) bool {
144 start, end := n.Span()
145 return start.Line == end.Line
146 }
147
148 func convClauses(list []syntax.Node) []build.Expr {
149 res := []build.Expr{}
150 for _, c := range list {
151 switch stmt := c.(type) {
152 case *syntax.ForClause:
153 res = append(res, &build.ForClause{
154 Vars: convExpr(stmt.Vars),
155 X: convExpr(stmt.X),
156 })
157 case *syntax.IfClause:
158 res = append(res, &build.IfClause{
159 Cond: convExpr(stmt.Cond),
160 })
161 }
162 }
163 return res
164 }
165
166 func convExpr(e syntax.Expr) build.Expr {
167 if e == nil {
168 return nil
169 }
170 switch e := e.(type) {
171 case *syntax.Literal:
172 switch e.Token {
173 case syntax.INT:
174 return &build.LiteralExpr{
175 Token: strconv.FormatInt(e.Value.(int64), 10),
176 Comments: convComments(e.Comments())}
177 case syntax.FLOAT:
178 return &build.LiteralExpr{
179 Token: e.Raw,
180 Comments: convComments(e.Comments())}
181 case syntax.STRING:
182 return &build.StringExpr{
183 Value: e.Value.(string),
184 TripleQuote: strings.HasPrefix(e.Raw, "\"\"\""),
185 Comments: convComments(e.Comments())}
186 }
187 case *syntax.Ident:
188 return &build.Ident{Name: e.Name, Comments: convComments(e.Comments())}
189 case *syntax.BinaryExpr:
190 _, lhsEnd := e.X.Span()
191 rhsBegin, _ := e.Y.Span()
192 if e.Op.String() == "=" {
193 return &build.AssignExpr{
194 LHS: convExpr(e.X),
195 RHS: convExpr(e.Y),
196 Op: e.Op.String(),
197 LineBreak: lhsEnd.Line != rhsBegin.Line,
198 Comments: convComments(e.Comments())}
199 }
200 return &build.BinaryExpr{
201 X: convExpr(e.X),
202 Y: convExpr(e.Y),
203 Op: e.Op.String(),
204 LineBreak: lhsEnd.Line != rhsBegin.Line,
205 Comments: convComments(e.Comments())}
206 case *syntax.UnaryExpr:
207 return &build.UnaryExpr{Op: e.Op.String(), X: convExpr(e.X)}
208 case *syntax.SliceExpr:
209 return &build.SliceExpr{X: convExpr(e.X), From: convExpr(e.Lo), To: convExpr(e.Hi), Step: convExpr(e.Step)}
210 case *syntax.DotExpr:
211 return &build.DotExpr{X: convExpr(e.X), Name: e.Name.Name}
212 case *syntax.CallExpr:
213 args := []build.Expr{}
214 for _, a := range e.Args {
215 args = append(args, convExpr(a))
216 }
217 return &build.CallExpr{
218 X: convExpr(e.Fn),
219 List: args,
220 ForceCompact: singleLine(e),
221 }
222 case *syntax.ListExpr:
223 list := []build.Expr{}
224 for _, i := range e.List {
225 list = append(list, convExpr(i))
226 }
227 return &build.ListExpr{List: list, Comments: convComments(e.Comments())}
228 case *syntax.DictExpr:
229 list := []*build.KeyValueExpr{}
230 for i := range e.List {
231 entry := e.List[i].(*syntax.DictEntry)
232 list = append(list, &build.KeyValueExpr{
233 Key: convExpr(entry.Key),
234 Value: convExpr(entry.Value),
235 Comments: convComments(entry.Comments()),
236 })
237 }
238 return &build.DictExpr{List: list, Comments: convComments(e.Comments())}
239 case *syntax.CondExpr:
240 return &build.ConditionalExpr{
241 Then: convExpr(e.True),
242 Test: convExpr(e.Cond),
243 Else: convExpr(e.False),
244 Comments: convComments(e.Comments()),
245 }
246 case *syntax.Comprehension:
247 return &build.Comprehension{
248 Body: convExpr(e.Body),
249 Clauses: convClauses(e.Clauses),
250 Comments: convComments(e.Comments()),
251 Curly: e.Curly,
252 }
253 case *syntax.ParenExpr:
254 return &build.ParenExpr{
255 X: convExpr(e.X),
256 Comments: convComments(e.Comments()),
257 }
258 case *syntax.TupleExpr:
259 return &build.TupleExpr{
260 List: convExprs(e.List),
261 NoBrackets: !e.Lparen.IsValid(),
262 Comments: convComments(e.Comments()),
263 ForceCompact: singleLine(e),
264 }
265 case *syntax.IndexExpr:
266 return &build.IndexExpr{
267 X: convExpr(e.X),
268 Y: convExpr(e.Y),
269 Comments: convComments(e.Comments()),
270 }
271 case *syntax.LambdaExpr:
272 return &build.LambdaExpr{
273 Comments: convComments(e.Comments()),
274 Function: build.Function{
275 Params: convExprs(e.Params),
276 Body: []build.Expr{convExpr(e.Body)},
277 },
278 }
279 default:
280 panic(fmt.Sprintf("other expr: %T %+v", e, e))
281 }
282 panic("unreachable")
283 }
284
View as plain text