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