• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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 Starlark parser and abstract syntax tree.
6package syntax // import "go.starlark.net/syntax"
7
8// A Node is a node in a Starlark syntax tree.
9type Node interface {
10	// Span returns the start and end position of the expression.
11	Span() (start, end Position)
12
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	}
53}
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 Starlark file.
68type File struct {
69	commentsRef
70	Path  string
71	Stmts []Stmt
72
73	Module interface{} // a *resolve.Module, set by resolver
74}
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
85// A Stmt is a Starlark statement.
86type Stmt interface {
87	Node
88	stmt()
89}
90
91func (*AssignStmt) stmt() {}
92func (*BranchStmt) stmt() {}
93func (*DefStmt) stmt()    {}
94func (*ExprStmt) stmt()   {}
95func (*ForStmt) stmt()    {}
96func (*WhileStmt) 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 {
106	commentsRef
107	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 DefStmt represents a function definition.
120type DefStmt struct {
121	commentsRef
122	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
128}
129
130func (x *DefStmt) Span() (start, end Position) {
131	_, end = x.Body[len(x.Body)-1].Span()
132	return x.Def, end
133}
134
135// An ExprStmt is an expression evaluated for side effects.
136type ExprStmt struct {
137	commentsRef
138	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 {
148	commentsRef
149	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
169// Starlark's load statement, so that it can be implemented in Python,
170// 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 {
174	commentsRef
175	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
186// ModuleName returns the name of the module loaded by this statement.
187func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
188
189// A BranchStmt changes the flow of control: break, continue, pass.
190type BranchStmt struct {
191	commentsRef
192	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 {
202	commentsRef
203	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
215// An Expr is a Starlark expression.
216type 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()       {}
233func (*ParenExpr) expr()     {}
234func (*SliceExpr) expr()     {}
235func (*TupleExpr) expr()     {}
236func (*UnaryExpr) expr()     {}
237
238// An Ident represents an identifier.
239type Ident struct {
240	commentsRef
241	NamePos Position
242	Name    string
243
244	Binding interface{} // a *resolver.Binding, set by resolver
245}
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 {
253	commentsRef
254	Token    Token // = STRING | BYTES | INT | FLOAT
255	TokenPos Position
256	Raw      string      // uninterpreted text
257	Value    interface{} // = string | int64 | *big.Int | float64
258}
259
260func (x *Literal) Span() (start, end Position) {
261	return x.TokenPos, x.TokenPos.add(x.Raw)
262}
263
264// 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
276// A CallExpr represents a function call expression: Fn(Args).
277type CallExpr struct {
278	commentsRef
279	Fn     Expr
280	Lparen Position
281	Args   []Expr // arg = expr | ident=expr | *expr | **expr
282	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 {
292	commentsRef
293	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 {
308	commentsRef
309	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 {
322	commentsRef
323	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
334// 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
347// A ForClause represents a for clause in a list comprehension: for Vars in X.
348type ForClause struct {
349	commentsRef
350	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 {
363	commentsRef
364	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 {
375	commentsRef
376	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 {
388	commentsRef
389	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
403// currently part of the Starlark spec, so their use is controlled by the
404// resolver.AllowLambda flag.
405type LambdaExpr struct {
406	commentsRef
407	Lambda Position
408	Params []Expr // param = ident | ident=expr | * | *ident | **ident
409	Body   Expr
410
411	Function interface{} // a *resolve.Function, set by resolver
412}
413
414func (x *LambdaExpr) Span() (start, end Position) {
415	_, end = x.Body.Span()
416	return x.Lambda, end
417}
418
419// A ListExpr represents a list literal: [ List ].
420type ListExpr struct {
421	commentsRef
422	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 {
433	commentsRef
434	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 {
449	commentsRef
450	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.
464//
465// As a special case, UnaryOp{Op:Star} may also represent
466// the star parameter in def f(*args) or def f(*, x).
467type UnaryExpr struct {
468	commentsRef
469	OpPos Position
470	Op    Token
471	X     Expr // may be nil if Op==STAR
472}
473
474func (x *UnaryExpr) Span() (start, end Position) {
475	if x.X != nil {
476		_, end = x.X.Span()
477	} else {
478		end = x.OpPos.add("*")
479	}
480	return x.OpPos, end
481}
482
483// A BinaryExpr represents a binary expression: X Op Y.
484//
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).
489type BinaryExpr struct {
490	commentsRef
491	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 {
505	commentsRef
506	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 {
519	commentsRef
520	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}
530