blob: 3440b646f910d5792b65137a04c179185e657176 [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
5// Package syntax provides a Skylark parser and abstract syntax tree.
6package syntax
7
8// A Node is a node in a Skylark syntax tree.
9type 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
67// A File represents a Skylark file.
68type 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
73 // set by resolver:
74 Locals []*Ident // this file's (comprehension-)local variables
75}
76
77func (x *File) Span() (start, end Position) {
78 if len(x.Stmts) == 0 {
79 return
80 }
81 start, _ = x.Stmts[0].Span()
82 _, end = x.Stmts[len(x.Stmts)-1].Span()
83 return start, end
84}
85
86// A Stmt is a Skylark statement.
87type Stmt interface {
88 Node
89 stmt()
90}
91
92func (*AssignStmt) stmt() {}
93func (*BranchStmt) stmt() {}
94func (*DefStmt) stmt() {}
95func (*ExprStmt) stmt() {}
96func (*ForStmt) stmt() {}
97func (*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
119// A Function represents the common parts of LambdaExpr and DefStmt.
120type Function struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100121 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400122 StartPos Position // position of DEF or LAMBDA token
123 Params []Expr // param = ident | ident=expr | *ident | **ident
124 Body []Stmt
125
126 // set by resolver:
127 HasVarargs bool // whether params includes *args (convenience)
128 HasKwargs bool // whether params includes **kwargs (convenience)
129 Locals []*Ident // this function's local variables, parameters first
130 FreeVars []*Ident // enclosing local variables to capture in closure
131}
132
133func (x *Function) Span() (start, end Position) {
134 _, end = x.Body[len(x.Body)-1].Span()
135 return x.StartPos, end
136}
137
138// A DefStmt represents a function definition.
139type DefStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100140 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400141 Def Position
142 Name *Ident
143 Function
144}
145
146func (x *DefStmt) Span() (start, end Position) {
147 _, end = x.Function.Body[len(x.Body)-1].Span()
148 return x.Def, end
149}
150
151// An ExprStmt is an expression evaluated for side effects.
152type ExprStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100153 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400154 X Expr
155}
156
157func (x *ExprStmt) Span() (start, end Position) {
158 return x.X.Span()
159}
160
161// An IfStmt is a conditional: If Cond: True; else: False.
162// 'elseif' is desugared into a chain of IfStmts.
163type IfStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100164 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400165 If Position // IF or ELIF
166 Cond Expr
167 True []Stmt
168 ElsePos Position // ELSE or ELIF
169 False []Stmt // optional
170}
171
172func (x *IfStmt) Span() (start, end Position) {
173 body := x.False
174 if body == nil {
175 body = x.True
176 }
177 _, end = body[len(body)-1].Span()
178 return x.If, end
179}
180
181// A LoadStmt loads another module and binds names from it:
182// load(Module, "x", y="foo").
183//
184// The AST is slightly unfaithful to the concrete syntax here because
185// Skylark's load statement, so that it can be implemented in Python,
186// binds some names (like y above) with an identifier and some (like x)
187// without. For consistency we create fake identifiers for all the
188// strings.
189type LoadStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100190 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400191 Load Position
192 Module *Literal // a string
193 From []*Ident // name defined in loading module
194 To []*Ident // name in loaded module
195 Rparen Position
196}
197
198func (x *LoadStmt) Span() (start, end Position) {
199 return x.Load, x.Rparen
200}
201
alandonovanab191a02018-03-02 10:20:44 -0500202// ModuleName returns the name of the module loaded by this statement.
203func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
204
Alan Donovan312d1a52017-10-02 10:10:28 -0400205// A BranchStmt changes the flow of control: break, continue, pass.
206type BranchStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100207 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400208 Token Token // = BREAK | CONTINUE | PASS
209 TokenPos Position
210}
211
212func (x *BranchStmt) Span() (start, end Position) {
213 return x.TokenPos, x.TokenPos.add(x.Token.String())
214}
215
216// A ReturnStmt returns from a function.
217type ReturnStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100218 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400219 Return Position
220 Result Expr // may be nil
221}
222
223func (x *ReturnStmt) Span() (start, end Position) {
224 if x.Result == nil {
225 return x.Return, x.Return.add("return")
226 }
227 _, end = x.Result.Span()
228 return x.Return, end
229}
230
231// An Expr is a Skylark expression.
232type Expr interface {
233 Node
234 expr()
235}
236
237func (*BinaryExpr) expr() {}
238func (*CallExpr) expr() {}
239func (*Comprehension) expr() {}
240func (*CondExpr) expr() {}
241func (*DictEntry) expr() {}
242func (*DictExpr) expr() {}
243func (*DotExpr) expr() {}
244func (*Ident) expr() {}
245func (*IndexExpr) expr() {}
246func (*LambdaExpr) expr() {}
247func (*ListExpr) expr() {}
248func (*Literal) expr() {}
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100249func (*ParenExpr) expr() {}
Alan Donovan312d1a52017-10-02 10:10:28 -0400250func (*SliceExpr) expr() {}
251func (*TupleExpr) expr() {}
252func (*UnaryExpr) expr() {}
253
254// An Ident represents an identifier.
255type Ident struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100256 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400257 NamePos Position
258 Name string
259
260 // set by resolver:
261
262 Scope uint8 // one of resolve.{Undefined,Local,Free,Global,Builtin}
263 Index int // index into enclosing {DefStmt,File}.Locals (if scope==Local) or DefStmt.FreeVars (if scope==Free)
264}
265
266func (x *Ident) Span() (start, end Position) {
267 return x.NamePos, x.NamePos.add(x.Name)
268}
269
270// A Literal represents a literal string or number.
271type Literal struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100272 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400273 Token Token // = STRING | INT
274 TokenPos Position
275 Raw string // uninterpreted text
Mohamed Elqdusy69e96152018-01-22 20:00:29 +0100276 Value interface{} // = string | int64 | *big.Int
Alan Donovan312d1a52017-10-02 10:10:28 -0400277}
278
279func (x *Literal) Span() (start, end Position) {
280 return x.TokenPos, x.TokenPos.add(x.Raw)
281}
282
Laurent Le Brun28ceca72018-02-26 15:01:53 +0100283// A ParenExpr represents a parenthesized expression: (X).
284type ParenExpr struct {
285 commentsRef
286 Lparen Position
287 X Expr
288 Rparen Position
289}
290
291func (x *ParenExpr) Span() (start, end Position) {
292 return x.Lparen, x.Rparen.add(")")
293}
294
Alan Donovan312d1a52017-10-02 10:10:28 -0400295// A CallExpr represents a function call expression: Fn(Args).
296type CallExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100297 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400298 Fn Expr
299 Lparen Position
300 Args []Expr
301 Rparen Position
302}
303
304func (x *CallExpr) Span() (start, end Position) {
305 start, _ = x.Fn.Span()
306 return start, x.Rparen.add(")")
307}
308
309// A DotExpr represents a field or method selector: X.Name.
310type DotExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100311 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400312 X Expr
313 Dot Position
314 NamePos Position
315 Name *Ident
316}
317
318func (x *DotExpr) Span() (start, end Position) {
319 start, _ = x.X.Span()
320 _, end = x.Name.Span()
321 return
322}
323
324// A Comprehension represents a list or dict comprehension:
325// [Body for ... if ...] or {Body for ... if ...}
326type Comprehension struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100327 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400328 Curly bool // {x:y for ...} or {x for ...}, not [x for ...]
329 Lbrack Position
330 Body Expr
331 Clauses []Node // = *ForClause | *IfClause
332 Rbrack Position
333}
334
335func (x *Comprehension) Span() (start, end Position) {
336 return x.Lbrack, x.Rbrack.add("]")
337}
338
339// A ForStmt represents a loop: for Vars in X: Body.
340type ForStmt struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100341 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400342 For Position
343 Vars Expr // name, or tuple of names
344 X Expr
345 Body []Stmt
346}
347
348func (x *ForStmt) Span() (start, end Position) {
349 _, end = x.Body[len(x.Body)-1].Span()
350 return x.For, end
351}
352
353// A ForClause represents a for clause in a list comprehension: for Vars in X.
354type ForClause struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100355 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400356 For Position
357 Vars Expr // name, or tuple of names
358 In Position
359 X Expr
360}
361
362func (x *ForClause) Span() (start, end Position) {
363 _, end = x.X.Span()
364 return x.For, end
365}
366
367// An IfClause represents an if clause in a list comprehension: if Cond.
368type IfClause struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100369 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400370 If Position
371 Cond Expr
372}
373
374func (x *IfClause) Span() (start, end Position) {
375 _, end = x.Cond.Span()
376 return x.If, end
377}
378
379// A DictExpr represents a dictionary literal: { List }.
380type DictExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100381 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400382 Lbrace Position
383 List []Expr // all *DictEntrys
384 Rbrace Position
385}
386
387func (x *DictExpr) Span() (start, end Position) {
388 return x.Lbrace, x.Rbrace.add("}")
389}
390
391// A DictEntry represents a dictionary entry: Key: Value.
392// Used only within a DictExpr.
393type DictEntry struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100394 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400395 Key Expr
396 Colon Position
397 Value Expr
398}
399
400func (x *DictEntry) Span() (start, end Position) {
401 start, _ = x.Key.Span()
402 _, end = x.Value.Span()
403 return start, end
404}
405
406// A LambdaExpr represents an inline function abstraction.
407//
408// Although they may be added in future, lambda expressions are not
409// currently part of the Skylark spec, so their use is controlled by the
410// resolver.AllowLambda flag.
411type LambdaExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100412 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400413 Lambda Position
414 Function
415}
416
417func (x *LambdaExpr) Span() (start, end Position) {
418 _, end = x.Function.Body[len(x.Body)-1].Span()
419 return x.Lambda, end
420}
421
422// A ListExpr represents a list literal: [ List ].
423type ListExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100424 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400425 Lbrack Position
426 List []Expr
427 Rbrack Position
428}
429
430func (x *ListExpr) Span() (start, end Position) {
431 return x.Lbrack, x.Rbrack.add("]")
432}
433
434// CondExpr represents the conditional: X if COND else ELSE.
435type CondExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100436 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400437 If Position
438 Cond Expr
439 True Expr
440 ElsePos Position
441 False Expr
442}
443
444func (x *CondExpr) Span() (start, end Position) {
445 start, _ = x.True.Span()
446 _, end = x.False.Span()
447 return start, end
448}
449
450// A TupleExpr represents a tuple literal: (List).
451type TupleExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100452 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400453 Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty
454 List []Expr
455 Rparen Position
456}
457
458func (x *TupleExpr) Span() (start, end Position) {
459 if x.Lparen.IsValid() {
460 return x.Lparen, x.Rparen
461 } else {
462 return Start(x.List[0]), End(x.List[len(x.List)-1])
463 }
464}
465
466// A UnaryExpr represents a unary expression: Op X.
467type 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
471 X Expr
472}
473
474func (x *UnaryExpr) Span() (start, end Position) {
475 _, end = x.X.Span()
476 return x.OpPos, end
477}
478
479// A BinaryExpr represents a binary expression: X Op Y.
480type BinaryExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100481 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400482 X Expr
483 OpPos Position
484 Op Token
485 Y Expr
486}
487
488func (x *BinaryExpr) Span() (start, end Position) {
489 start, _ = x.X.Span()
490 _, end = x.Y.Span()
491 return start, end
492}
493
494// A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step].
495type SliceExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100496 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400497 X Expr
498 Lbrack Position
499 Lo, Hi, Step Expr // all optional
500 Rbrack Position
501}
502
503func (x *SliceExpr) Span() (start, end Position) {
504 start, _ = x.X.Span()
505 return start, x.Rbrack
506}
507
508// An IndexExpr represents an index expression: X[Y].
509type IndexExpr struct {
Laurent Le Brun689fc222018-02-22 19:37:18 +0100510 commentsRef
Alan Donovan312d1a52017-10-02 10:10:28 -0400511 X Expr
512 Lbrack Position
513 Y Expr
514 Rbrack Position
515}
516
517func (x *IndexExpr) Span() (start, end Position) {
518 start, _ = x.X.Span()
519 return start, x.Rbrack
520}