go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/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 "go.starlark.net/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 Options *FileOptions 75 } 76 77 func (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 Starlark statement. 87 type Stmt interface { 88 Node 89 stmt() 90 } 91 92 func (*AssignStmt) stmt() {} 93 func (*BranchStmt) stmt() {} 94 func (*DefStmt) stmt() {} 95 func (*ExprStmt) stmt() {} 96 func (*ForStmt) stmt() {} 97 func (*WhileStmt) stmt() {} 98 func (*IfStmt) stmt() {} 99 func (*LoadStmt) stmt() {} 100 func (*ReturnStmt) stmt() {} 101 102 // An AssignStmt represents an assignment: 103 // 104 // x = 0 105 // x, y = y, x 106 // x += 1 107 type AssignStmt struct { 108 commentsRef 109 OpPos Position 110 Op Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ 111 LHS Expr 112 RHS Expr 113 } 114 115 func (x *AssignStmt) Span() (start, end Position) { 116 start, _ = x.LHS.Span() 117 _, end = x.RHS.Span() 118 return 119 } 120 121 // A DefStmt represents a function definition. 122 type DefStmt struct { 123 commentsRef 124 Def Position 125 Name *Ident 126 Lparen Position 127 Params []Expr // param = ident | ident=expr | * | *ident | **ident 128 Rparen Position 129 Body []Stmt 130 131 Function interface{} // a *resolve.Function, set by resolver 132 } 133 134 func (x *DefStmt) Span() (start, end Position) { 135 _, end = x.Body[len(x.Body)-1].Span() 136 return x.Def, end 137 } 138 139 // An ExprStmt is an expression evaluated for side effects. 140 type ExprStmt struct { 141 commentsRef 142 X Expr 143 } 144 145 func (x *ExprStmt) Span() (start, end Position) { 146 return x.X.Span() 147 } 148 149 // An IfStmt is a conditional: If Cond: True; else: False. 150 // 'elseif' is desugared into a chain of IfStmts. 151 type IfStmt struct { 152 commentsRef 153 If Position // IF or ELIF 154 Cond Expr 155 True []Stmt 156 ElsePos Position // ELSE or ELIF 157 False []Stmt // optional 158 } 159 160 func (x *IfStmt) Span() (start, end Position) { 161 body := x.False 162 if body == nil { 163 body = x.True 164 } 165 _, end = body[len(body)-1].Span() 166 return x.If, end 167 } 168 169 // A LoadStmt loads another module and binds names from it: 170 // load(Module, "x", y="foo"). 171 // 172 // The AST is slightly unfaithful to the concrete syntax here because 173 // Starlark's load statement, so that it can be implemented in Python, 174 // binds some names (like y above) with an identifier and some (like x) 175 // without. For consistency we create fake identifiers for all the 176 // strings. 177 type LoadStmt struct { 178 commentsRef 179 Load Position 180 Module *Literal // a string 181 From []*Ident // name defined in loading module 182 To []*Ident // name in loaded module 183 Rparen Position 184 } 185 186 func (x *LoadStmt) Span() (start, end Position) { 187 return x.Load, x.Rparen 188 } 189 190 // ModuleName returns the name of the module loaded by this statement. 191 func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) } 192 193 // A BranchStmt changes the flow of control: break, continue, pass. 194 type BranchStmt struct { 195 commentsRef 196 Token Token // = BREAK | CONTINUE | PASS 197 TokenPos Position 198 } 199 200 func (x *BranchStmt) Span() (start, end Position) { 201 return x.TokenPos, x.TokenPos.add(x.Token.String()) 202 } 203 204 // A ReturnStmt returns from a function. 205 type ReturnStmt struct { 206 commentsRef 207 Return Position 208 Result Expr // may be nil 209 } 210 211 func (x *ReturnStmt) Span() (start, end Position) { 212 if x.Result == nil { 213 return x.Return, x.Return.add("return") 214 } 215 _, end = x.Result.Span() 216 return x.Return, end 217 } 218 219 // An Expr is a Starlark expression. 220 type Expr interface { 221 Node 222 expr() 223 } 224 225 func (*BinaryExpr) expr() {} 226 func (*CallExpr) expr() {} 227 func (*Comprehension) expr() {} 228 func (*CondExpr) expr() {} 229 func (*DictEntry) expr() {} 230 func (*DictExpr) expr() {} 231 func (*DotExpr) expr() {} 232 func (*Ident) expr() {} 233 func (*IndexExpr) expr() {} 234 func (*LambdaExpr) expr() {} 235 func (*ListExpr) expr() {} 236 func (*Literal) expr() {} 237 func (*ParenExpr) expr() {} 238 func (*SliceExpr) expr() {} 239 func (*TupleExpr) expr() {} 240 func (*UnaryExpr) expr() {} 241 242 // An Ident represents an identifier. 243 type Ident struct { 244 commentsRef 245 NamePos Position 246 Name string 247 248 Binding interface{} // a *resolver.Binding, set by resolver 249 } 250 251 func (x *Ident) Span() (start, end Position) { 252 return x.NamePos, x.NamePos.add(x.Name) 253 } 254 255 // A Literal represents a literal string or number. 256 type Literal struct { 257 commentsRef 258 Token Token // = STRING | BYTES | INT | FLOAT 259 TokenPos Position 260 Raw string // uninterpreted text 261 Value interface{} // = string | int64 | *big.Int | float64 262 } 263 264 func (x *Literal) Span() (start, end Position) { 265 return x.TokenPos, x.TokenPos.add(x.Raw) 266 } 267 268 // A ParenExpr represents a parenthesized expression: (X). 269 type ParenExpr struct { 270 commentsRef 271 Lparen Position 272 X Expr 273 Rparen Position 274 } 275 276 func (x *ParenExpr) Span() (start, end Position) { 277 return x.Lparen, x.Rparen.add(")") 278 } 279 280 // A CallExpr represents a function call expression: Fn(Args). 281 type CallExpr struct { 282 commentsRef 283 Fn Expr 284 Lparen Position 285 Args []Expr // arg = expr | ident=expr | *expr | **expr 286 Rparen Position 287 } 288 289 func (x *CallExpr) Span() (start, end Position) { 290 start, _ = x.Fn.Span() 291 return start, x.Rparen.add(")") 292 } 293 294 // A DotExpr represents a field or method selector: X.Name. 295 type DotExpr struct { 296 commentsRef 297 X Expr 298 Dot Position 299 NamePos Position 300 Name *Ident 301 } 302 303 func (x *DotExpr) Span() (start, end Position) { 304 start, _ = x.X.Span() 305 _, end = x.Name.Span() 306 return 307 } 308 309 // A Comprehension represents a list or dict comprehension: 310 // [Body for ... if ...] or {Body for ... if ...} 311 type Comprehension struct { 312 commentsRef 313 Curly bool // {x:y for ...} or {x for ...}, not [x for ...] 314 Lbrack Position 315 Body Expr 316 Clauses []Node // = *ForClause | *IfClause 317 Rbrack Position 318 } 319 320 func (x *Comprehension) Span() (start, end Position) { 321 return x.Lbrack, x.Rbrack.add("]") 322 } 323 324 // A ForStmt represents a loop: for Vars in X: Body. 325 type ForStmt struct { 326 commentsRef 327 For Position 328 Vars Expr // name, or tuple of names 329 X Expr 330 Body []Stmt 331 } 332 333 func (x *ForStmt) Span() (start, end Position) { 334 _, end = x.Body[len(x.Body)-1].Span() 335 return x.For, end 336 } 337 338 // A WhileStmt represents a while loop: while X: Body. 339 type WhileStmt struct { 340 commentsRef 341 While Position 342 Cond Expr 343 Body []Stmt 344 } 345 346 func (x *WhileStmt) Span() (start, end Position) { 347 _, end = x.Body[len(x.Body)-1].Span() 348 return x.While, end 349 } 350 351 // A ForClause represents a for clause in a list comprehension: for Vars in X. 352 type ForClause struct { 353 commentsRef 354 For Position 355 Vars Expr // name, or tuple of names 356 In Position 357 X Expr 358 } 359 360 func (x *ForClause) Span() (start, end Position) { 361 _, end = x.X.Span() 362 return x.For, end 363 } 364 365 // An IfClause represents an if clause in a list comprehension: if Cond. 366 type IfClause struct { 367 commentsRef 368 If Position 369 Cond Expr 370 } 371 372 func (x *IfClause) Span() (start, end Position) { 373 _, end = x.Cond.Span() 374 return x.If, end 375 } 376 377 // A DictExpr represents a dictionary literal: { List }. 378 type DictExpr struct { 379 commentsRef 380 Lbrace Position 381 List []Expr // all *DictEntrys 382 Rbrace Position 383 } 384 385 func (x *DictExpr) Span() (start, end Position) { 386 return x.Lbrace, x.Rbrace.add("}") 387 } 388 389 // A DictEntry represents a dictionary entry: Key: Value. 390 // Used only within a DictExpr. 391 type DictEntry struct { 392 commentsRef 393 Key Expr 394 Colon Position 395 Value Expr 396 } 397 398 func (x *DictEntry) Span() (start, end Position) { 399 start, _ = x.Key.Span() 400 _, end = x.Value.Span() 401 return start, end 402 } 403 404 // A LambdaExpr represents an inline function abstraction. 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 }