github.com/k14s/starlark-go@v0.0.0-20200720175618-3a5c849cc368/syntax/syntax.go (about) 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. 6 package syntax // import "github.com/k14s/starlark-go/syntax" 7 8 // A Node is a node in a Starlark syntax tree. 9 type 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. 24 type Comment struct { 25 Start Position 26 Text string // without trailing newline 27 } 28 29 // Comments collects the comments associated with an expression. 30 type 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. 42 type 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. 46 func (cr commentsRef) Comments() *Comments { return cr.ref } 47 48 // AllocComments enables comments to be associated with a syntax node. 49 func (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. 56 func Start(n Node) Position { 57 start, _ := n.Span() 58 return start 59 } 60 61 // End returns the end position of the expression. 62 func End(n Node) Position { 63 _, end := n.Span() 64 return end 65 } 66 67 // A File represents a Starlark file. 68 type File struct { 69 commentsRef 70 Path string 71 Stmts []Stmt 72 73 Module interface{} // a *resolve.Module, set by resolver 74 } 75 76 func (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. 86 type Stmt interface { 87 Node 88 stmt() 89 } 90 91 func (*AssignStmt) stmt() {} 92 func (*BranchStmt) stmt() {} 93 func (*DefStmt) stmt() {} 94 func (*ExprStmt) stmt() {} 95 func (*ForStmt) stmt() {} 96 func (*WhileStmt) stmt() {} 97 func (*IfStmt) stmt() {} 98 func (*LoadStmt) stmt() {} 99 func (*ReturnStmt) stmt() {} 100 101 // An AssignStmt represents an assignment: 102 // x = 0 103 // x, y = y, x 104 // x += 1 105 type AssignStmt struct { 106 commentsRef 107 OpPos Position 108 Op Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ 109 LHS Expr 110 RHS Expr 111 } 112 113 func (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. 120 type 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 130 func (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. 136 type ExprStmt struct { 137 commentsRef 138 X Expr 139 } 140 141 func (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. 147 type 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 156 func (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. 173 type 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 182 func (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. 187 func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) } 188 189 // A BranchStmt changes the flow of control: break, continue, pass. 190 type BranchStmt struct { 191 commentsRef 192 Token Token // = BREAK | CONTINUE | PASS 193 TokenPos Position 194 } 195 196 func (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. 201 type ReturnStmt struct { 202 commentsRef 203 Return Position 204 Result Expr // may be nil 205 } 206 207 func (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. 216 type Expr interface { 217 Node 218 expr() 219 } 220 221 func (*BinaryExpr) expr() {} 222 func (*CallExpr) expr() {} 223 func (*Comprehension) expr() {} 224 func (*CondExpr) expr() {} 225 func (*DictEntry) expr() {} 226 func (*DictExpr) expr() {} 227 func (*DotExpr) expr() {} 228 func (*Ident) expr() {} 229 func (*IndexExpr) expr() {} 230 func (*LambdaExpr) expr() {} 231 func (*ListExpr) expr() {} 232 func (*Literal) expr() {} 233 func (*ParenExpr) expr() {} 234 func (*SliceExpr) expr() {} 235 func (*TupleExpr) expr() {} 236 func (*UnaryExpr) expr() {} 237 238 // An Ident represents an identifier. 239 type Ident struct { 240 commentsRef 241 NamePos Position 242 Name string 243 244 Binding interface{} // a *resolver.Binding, set by resolver 245 } 246 247 func (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. 252 type Literal struct { 253 commentsRef 254 Token Token // = STRING | INT 255 TokenPos Position 256 Raw string // uninterpreted text 257 Value interface{} // = string | int64 | *big.Int 258 } 259 260 func (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). 265 type ParenExpr struct { 266 commentsRef 267 Lparen Position 268 X Expr 269 Rparen Position 270 } 271 272 func (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). 277 type CallExpr struct { 278 commentsRef 279 Fn Expr 280 Lparen Position 281 Args []Expr // arg = expr | ident=expr | *expr | **expr 282 Rparen Position 283 } 284 285 func (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. 291 type DotExpr struct { 292 commentsRef 293 X Expr 294 Dot Position 295 NamePos Position 296 Name *Ident 297 } 298 299 func (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 ...} 307 type 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 316 func (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. 321 type ForStmt struct { 322 commentsRef 323 For Position 324 Vars Expr // name, or tuple of names 325 X Expr 326 Body []Stmt 327 } 328 329 func (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. 335 type WhileStmt struct { 336 commentsRef 337 While Position 338 Cond Expr 339 Body []Stmt 340 } 341 342 func (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. 348 type ForClause struct { 349 commentsRef 350 For Position 351 Vars Expr // name, or tuple of names 352 In Position 353 X Expr 354 } 355 356 func (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. 362 type IfClause struct { 363 commentsRef 364 If Position 365 Cond Expr 366 } 367 368 func (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 }. 374 type DictExpr struct { 375 commentsRef 376 Lbrace Position 377 List []Expr // all *DictEntrys 378 Rbrace Position 379 } 380 381 func (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. 387 type DictEntry struct { 388 commentsRef 389 Key Expr 390 Colon Position 391 Value Expr 392 } 393 394 func (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. 405 type 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 414 func (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 ]. 420 type ListExpr struct { 421 commentsRef 422 Lbrack Position 423 List []Expr 424 Rbrack Position 425 } 426 427 func (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. 432 type CondExpr struct { 433 commentsRef 434 If Position 435 Cond Expr 436 True Expr 437 ElsePos Position 438 False Expr 439 } 440 441 func (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). 448 type 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 455 func (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). 467 type UnaryExpr struct { 468 commentsRef 469 OpPos Position 470 Op Token 471 X Expr // may be nil if Op==STAR 472 } 473 474 func (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). 489 type BinaryExpr struct { 490 commentsRef 491 X Expr 492 OpPos Position 493 Op Token 494 Y Expr 495 } 496 497 func (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]. 504 type SliceExpr struct { 505 commentsRef 506 X Expr 507 Lbrack Position 508 Lo, Hi, Step Expr // all optional 509 Rbrack Position 510 } 511 512 func (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]. 518 type IndexExpr struct { 519 commentsRef 520 X Expr 521 Lbrack Position 522 Y Expr 523 Rbrack Position 524 } 525 526 func (x *IndexExpr) Span() (start, end Position) { 527 start, _ = x.X.Span() 528 return start, x.Rbrack 529 }