blob: 20b28bb606f020711fa91409ef29b57730c09d89 [file] [log] [blame]
Alan Donovan312d1a52017-10-02 10:10:28 -04001// Copyright 2017 The Bazel Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Alan Donovane3deafe2018-10-23 11:05:09 -04005// Package syntax provides a Starlark parser and abstract syntax tree.
Alan Donovan551f3002018-11-01 09:44:00 -04006package syntax // import "go.starlark.net/syntax"
Alan Donovan312d1a52017-10-02 10:10:28 -04007
Alan Donovane3deafe2018-10-23 11:05:09 -04008// A Node is a node in a Starlark syntax tree.
Alan Donovan312d1a52017-10-02 10:10:28 -04009type Node interface {
10 // Span returns the start and end position of the expression.
11 Span() (start, end Position)
Laurent Le Brun689fc222018-02-22 19:37:18 +010012
13 // Comments returns the comments associated with this node.
14 // It returns nil if RetainComments was not specified during parsing,
15 // or if AllocComments was not called.
16 Comments() *Comments
17
18 // AllocComments allocates a new Comments node if there was none.
19 // This makes possible to add new comments using Comments() method.
20 AllocComments()
21}
22
23// A Comment represents a single # comment.
24type Comment struct {
25 Start Position
26 Text string // without trailing newline
27}
28
29// Comments collects the comments associated with an expression.
30type Comments struct {
31 Before []Comment // whole-line comments before this expression
32 Suffix []Comment // end-of-line comments after this expression (up to 1)
33
34 // For top-level expressions only, After lists whole-line
35 // comments following the expression.
36 After []Comment
37}
38
39// A commentsRef is a possibly-nil reference to a set of comments.
40// A commentsRef is embedded in each type of syntax node,
41// and provides its Comments and AllocComments methods.
42type commentsRef struct{ ref *Comments }
43
44// Comments returns the comments associated with a syntax node,
45// or nil if AllocComments has not yet been called.
46func (cr commentsRef) Comments() *Comments { return cr.ref }
47
48// AllocComments enables comments to be associated with a syntax node.
49func (cr *commentsRef) AllocComments() {
50 if cr.ref == nil {
51 cr.ref = new(Comments)
52 }
Alan Donovan312d1a52017-10-02 10:10:28 -040053}
54
55// Start returns the start position of the expression.
56func Start(n Node) Position {
57 start, _ := n.Span()
58 return start
59}
60
61// End returns the end position of the expression.
62func End(n Node) Position {
63 _, end := n.Span()
64 return end
65}
66
Alan Donovane3deafe2018-10-23 11:05:09 -040067// A File represents a Starlark file.
Alan Donovan312d1a52017-10-02 10:10:28 -040068type File struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +010069 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -040070 Path string
71 Stmts []Stmt
72
alandonovan6ddc71c2019-06-04 09:08:55 -040073 Module interface{} // a *resolve.Module, set by resolver
Alan Donovan312d1a52017-10-02 10:10:28 -040074}
75
76func (x *File) Span() (start, end Position) {
77 if len(x.Stmts) == 0 {
78 return
79 }
80 start, _ = x.Stmts[0].Span()
81 _, end = x.Stmts[len(x.Stmts)-1].Span()
82 return start, end
83}
84
Alan Donovane3deafe2018-10-23 11:05:09 -040085// A Stmt is a Starlark statement.
Alan Donovan312d1a52017-10-02 10:10:28 -040086type Stmt interface {
87 Node
88 stmt()
89}
90
91func (*AssignStmt) stmt() {}
92func (*BranchStmt) stmt() {}
93func (*DefStmt) stmt() {}
94func (*ExprStmt) stmt() {}
95func (*ForStmt) stmt() {}
Alessandro Arzilli678bafe2018-12-07 17:28:35 +010096func (*WhileStmt) stmt() {}
Alan Donovan312d1a52017-10-02 10:10:28 -040097func (*IfStmt) stmt() {}
98func (*LoadStmt) stmt() {}
99func (*ReturnStmt) stmt() {}
100
101// An AssignStmt represents an assignment:
102// x = 0
103// x, y = y, x
104// x += 1
105type AssignStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100106 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400107 OpPos Position
108 Op Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ
109 LHS Expr
110 RHS Expr
111}
112
113func (x *AssignStmt) Span() (start, end Position) {
114 start, _ = x.LHS.Span()
115 _, end = x.RHS.Span()
116 return
117}
118
Alan Donovan312d1a52017-10-02 10:10:28 -0400119// A DefStmt represents a function definition.
120type DefStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100121 commentsRef
alandonovan6ddc71c2019-06-04 09:08:55 -0400122 Def Position
123 Name *Ident
124 Params []Expr // param = ident | ident=expr | * | *ident | **ident
125 Body []Stmt
126
127 Function interface{} // a *resolve.Function, set by resolver
Alan Donovan312d1a52017-10-02 10:10:28 -0400128}
129
130func (x *DefStmt) Span() (start, end Position) {
alandonovan6ddc71c2019-06-04 09:08:55 -0400131 _, end = x.Body[len(x.Body)-1].Span()
Alan Donovan312d1a52017-10-02 10:10:28 -0400132 return x.Def, end
133}
134
135// An ExprStmt is an expression evaluated for side effects.
136type ExprStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100137 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400138 X Expr
139}
140
141func (x *ExprStmt) Span() (start, end Position) {
142 return x.X.Span()
143}
144
145// An IfStmt is a conditional: If Cond: True; else: False.
146// 'elseif' is desugared into a chain of IfStmts.
147type IfStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100148 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400149 If Position // IF or ELIF
150 Cond Expr
151 True []Stmt
152 ElsePos Position // ELSE or ELIF
153 False []Stmt // optional
154}
155
156func (x *IfStmt) Span() (start, end Position) {
157 body := x.False
158 if body == nil {
159 body = x.True
160 }
161 _, end = body[len(body)-1].Span()
162 return x.If, end
163}
164
165// A LoadStmt loads another module and binds names from it:
166// load(Module, "x", y="foo").
167//
168// The AST is slightly unfaithful to the concrete syntax here because
Alan Donovane3deafe2018-10-23 11:05:09 -0400169// Starlark's load statement, so that it can be implemented in Python,
Alan Donovan312d1a52017-10-02 10:10:28 -0400170// binds some names (like y above) with an identifier and some (like x)
171// without. For consistency we create fake identifiers for all the
172// strings.
173type LoadStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100174 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400175 Load Position
176 Module *Literal // a string
177 From []*Ident // name defined in loading module
178 To []*Ident // name in loaded module
179 Rparen Position
180}
181
182func (x *LoadStmt) Span() (start, end Position) {
183 return x.Load, x.Rparen
184}
185
alandonovanab191a02018-03-02 10:20:44 -0500186// ModuleName returns the name of the module loaded by this statement.
187func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
188
Alan Donovan312d1a52017-10-02 10:10:28 -0400189// A BranchStmt changes the flow of control: break, continue, pass.
190type BranchStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100191 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400192 Token Token // = BREAK | CONTINUE | PASS
193 TokenPos Position
194}
195
196func (x *BranchStmt) Span() (start, end Position) {
197 return x.TokenPos, x.TokenPos.add(x.Token.String())
198}
199
200// A ReturnStmt returns from a function.
201type ReturnStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100202 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400203 Return Position
204 Result Expr // may be nil
205}
206
207func (x *ReturnStmt) Span() (start, end Position) {
208 if x.Result == nil {
209 return x.Return, x.Return.add("return")
210 }
211 _, end = x.Result.Span()
212 return x.Return, end
213}
214
Alan Donovane3deafe2018-10-23 11:05:09 -0400215// An Expr is a Starlark expression.
Alan Donovan312d1a52017-10-02 10:10:28 -0400216type Expr interface {
217 Node
218 expr()
219}
220
221func (*BinaryExpr) expr() {}
222func (*CallExpr) expr() {}
223func (*Comprehension) expr() {}
224func (*CondExpr) expr() {}
225func (*DictEntry) expr() {}
226func (*DictExpr) expr() {}
227func (*DotExpr) expr() {}
228func (*Ident) expr() {}
229func (*IndexExpr) expr() {}
230func (*LambdaExpr) expr() {}
231func (*ListExpr) expr() {}
232func (*Literal) expr() {}
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100233func (*ParenExpr) expr() {}
Alan Donovan312d1a52017-10-02 10:10:28 -0400234func (*SliceExpr) expr() {}
235func (*TupleExpr) expr() {}
236func (*UnaryExpr) expr() {}
237
238// An Ident represents an identifier.
239type Ident struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100240 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400241 NamePos Position
242 Name string
243
alandonovan6ddc71c2019-06-04 09:08:55 -0400244 Binding interface{} // a *resolver.Binding, set by resolver
Alan Donovan312d1a52017-10-02 10:10:28 -0400245}
246
247func (x *Ident) Span() (start, end Position) {
248 return x.NamePos, x.NamePos.add(x.Name)
249}
250
251// A Literal represents a literal string or number.
252type Literal struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100253 commentsRef
alandonovanebe61bd2021-02-12 16:57:32 -0500254 Token Token // = STRING | BYTES | INT | FLOAT
Alan Donovan312d1a52017-10-02 10:10:28 -0400255 TokenPos Position
256 Raw string // uninterpreted text
alandonovan28488fa2021-01-25 14:35:08 -0500257 Value interface{} // = string | int64 | *big.Int | float64
Alan Donovan312d1a52017-10-02 10:10:28 -0400258}
259
260func (x *Literal) Span() (start, end Position) {
261 return x.TokenPos, x.TokenPos.add(x.Raw)
262}
263
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100264// A ParenExpr represents a parenthesized expression: (X).
265type ParenExpr struct {
266 commentsRef
267 Lparen Position
268 X Expr
269 Rparen Position
270}
271
272func (x *ParenExpr) Span() (start, end Position) {
273 return x.Lparen, x.Rparen.add(")")
274}
275
Alan Donovan312d1a52017-10-02 10:10:28 -0400276// A CallExpr represents a function call expression: Fn(Args).
277type CallExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100278 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400279 Fn Expr
280 Lparen Position
alandonovan93f3e0c2018-03-30 10:42:28 -0400281 Args []Expr // arg = expr | ident=expr | *expr | **expr
Alan Donovan312d1a52017-10-02 10:10:28 -0400282 Rparen Position
283}
284
285func (x *CallExpr) Span() (start, end Position) {
286 start, _ = x.Fn.Span()
287 return start, x.Rparen.add(")")
288}
289
290// A DotExpr represents a field or method selector: X.Name.
291type DotExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100292 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400293 X Expr
294 Dot Position
295 NamePos Position
296 Name *Ident
297}
298
299func (x *DotExpr) Span() (start, end Position) {
300 start, _ = x.X.Span()
301 _, end = x.Name.Span()
302 return
303}
304
305// A Comprehension represents a list or dict comprehension:
306// [Body for ... if ...] or {Body for ... if ...}
307type Comprehension struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100308 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400309 Curly bool // {x:y for ...} or {x for ...}, not [x for ...]
310 Lbrack Position
311 Body Expr
312 Clauses []Node // = *ForClause | *IfClause
313 Rbrack Position
314}
315
316func (x *Comprehension) Span() (start, end Position) {
317 return x.Lbrack, x.Rbrack.add("]")
318}
319
320// A ForStmt represents a loop: for Vars in X: Body.
321type ForStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100322 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400323 For Position
324 Vars Expr // name, or tuple of names
325 X Expr
326 Body []Stmt
327}
328
329func (x *ForStmt) Span() (start, end Position) {
330 _, end = x.Body[len(x.Body)-1].Span()
331 return x.For, end
332}
333
Alessandro Arzilli678bafe2018-12-07 17:28:35 +0100334// A WhileStmt represents a while loop: while X: Body.
335type WhileStmt struct {
336 commentsRef
337 While Position
338 Cond Expr
339 Body []Stmt
340}
341
342func (x *WhileStmt) Span() (start, end Position) {
343 _, end = x.Body[len(x.Body)-1].Span()
344 return x.While, end
345}
346
Alan Donovan312d1a52017-10-02 10:10:28 -0400347// A ForClause represents a for clause in a list comprehension: for Vars in X.
348type ForClause struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100349 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400350 For Position
351 Vars Expr // name, or tuple of names
352 In Position
353 X Expr
354}
355
356func (x *ForClause) Span() (start, end Position) {
357 _, end = x.X.Span()
358 return x.For, end
359}
360
361// An IfClause represents an if clause in a list comprehension: if Cond.
362type IfClause struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100363 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400364 If Position
365 Cond Expr
366}
367
368func (x *IfClause) Span() (start, end Position) {
369 _, end = x.Cond.Span()
370 return x.If, end
371}
372
373// A DictExpr represents a dictionary literal: { List }.
374type DictExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100375 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400376 Lbrace Position
377 List []Expr // all *DictEntrys
378 Rbrace Position
379}
380
381func (x *DictExpr) Span() (start, end Position) {
382 return x.Lbrace, x.Rbrace.add("}")
383}
384
385// A DictEntry represents a dictionary entry: Key: Value.
386// Used only within a DictExpr.
387type DictEntry struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100388 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400389 Key Expr
390 Colon Position
391 Value Expr
392}
393
394func (x *DictEntry) Span() (start, end Position) {
395 start, _ = x.Key.Span()
396 _, end = x.Value.Span()
397 return start, end
398}
399
400// A LambdaExpr represents an inline function abstraction.
401//
402// Although they may be added in future, lambda expressions are not
Alan Donovane3deafe2018-10-23 11:05:09 -0400403// currently part of the Starlark spec, so their use is controlled by the
Alan Donovan312d1a52017-10-02 10:10:28 -0400404// resolver.AllowLambda flag.
405type LambdaExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100406 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400407 Lambda Position
alandonovan6ddc71c2019-06-04 09:08:55 -0400408 Params []Expr // param = ident | ident=expr | * | *ident | **ident
409 Body Expr
410
411 Function interface{} // a *resolve.Function, set by resolver
Alan Donovan312d1a52017-10-02 10:10:28 -0400412}
413
414func (x *LambdaExpr) Span() (start, end Position) {
alandonovan6ddc71c2019-06-04 09:08:55 -0400415 _, end = x.Body.Span()
Alan Donovan312d1a52017-10-02 10:10:28 -0400416 return x.Lambda, end
417}
418
419// A ListExpr represents a list literal: [ List ].
420type ListExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100421 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400422 Lbrack Position
423 List []Expr
424 Rbrack Position
425}
426
427func (x *ListExpr) Span() (start, end Position) {
428 return x.Lbrack, x.Rbrack.add("]")
429}
430
431// CondExpr represents the conditional: X if COND else ELSE.
432type CondExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100433 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400434 If Position
435 Cond Expr
436 True Expr
437 ElsePos Position
438 False Expr
439}
440
441func (x *CondExpr) Span() (start, end Position) {
442 start, _ = x.True.Span()
443 _, end = x.False.Span()
444 return start, end
445}
446
447// A TupleExpr represents a tuple literal: (List).
448type TupleExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100449 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400450 Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty
451 List []Expr
452 Rparen Position
453}
454
455func (x *TupleExpr) Span() (start, end Position) {
456 if x.Lparen.IsValid() {
457 return x.Lparen, x.Rparen
458 } else {
459 return Start(x.List[0]), End(x.List[len(x.List)-1])
460 }
461}
462
463// A UnaryExpr represents a unary expression: Op X.
alandonovan34a33192019-02-22 14:25:09 -0500464//
alandonovan1174b262019-02-25 11:01:09 -0500465// As a special case, UnaryOp{Op:Star} may also represent
466// the star parameter in def f(*args) or def f(*, x).
Alan Donovan312d1a52017-10-02 10:10:28 -0400467type UnaryExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100468 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400469 OpPos Position
470 Op Token
alandonovan34a33192019-02-22 14:25:09 -0500471 X Expr // may be nil if Op==STAR
Alan Donovan312d1a52017-10-02 10:10:28 -0400472}
473
474func (x *UnaryExpr) Span() (start, end Position) {
alandonovan34a33192019-02-22 14:25:09 -0500475 if x.X != nil {
476 _, end = x.X.Span()
477 } else {
478 end = x.OpPos.add("*")
479 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400480 return x.OpPos, end
481}
482
483// A BinaryExpr represents a binary expression: X Op Y.
alandonovan1174b262019-02-25 11:01:09 -0500484//
485// As a special case, BinaryExpr{Op:EQ} may also
486// represent a named argument in a call f(k=v)
487// or a named parameter in a function declaration
488// def f(param=default).
Alan Donovan312d1a52017-10-02 10:10:28 -0400489type BinaryExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100490 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400491 X Expr
492 OpPos Position
493 Op Token
494 Y Expr
495}
496
497func (x *BinaryExpr) Span() (start, end Position) {
498 start, _ = x.X.Span()
499 _, end = x.Y.Span()
500 return start, end
501}
502
503// A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step].
504type SliceExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100505 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400506 X Expr
507 Lbrack Position
508 Lo, Hi, Step Expr // all optional
509 Rbrack Position
510}
511
512func (x *SliceExpr) Span() (start, end Position) {
513 start, _ = x.X.Span()
514 return start, x.Rbrack
515}
516
517// An IndexExpr represents an index expression: X[Y].
518type IndexExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100519 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400520 X Expr
521 Lbrack Position
522 Y Expr
523 Rbrack Position
524}
525
526func (x *IndexExpr) Span() (start, end Position) {
527 start, _ = x.X.Span()
528 return start, x.Rbrack
529}