github.com/lab47/exprcore@v0.0.0-20210525052339-fb7d6bd9331e/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 exprcore parser and abstract syntax tree. 6 package syntax // import "github.com/lab47/exprcore/syntax" 7 8 // A Node is a node in a exprcore 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 exprcore 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 exprcore 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 func (*ProtoEntry) stmt() {} 101 func (*ImportStmt) stmt() {} 102 103 // An AssignStmt represents an assignment: 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 type ShellExpr struct { 122 commentsRef 123 Shell Position 124 Content []Expr // param = ident | ident=expr | * | *ident | **ident 125 } 126 127 func (x *ShellExpr) Span() (start, end Position) { 128 _, end = x.Content[len(x.Content)-1].Span() 129 return x.Shell, end 130 } 131 132 // A DefStmt represents a function definition. 133 type DefStmt struct { 134 commentsRef 135 Def Position 136 Name *Ident 137 Params []Expr // param = ident | ident=expr | * | *ident | **ident 138 Body []Stmt 139 140 Function interface{} // a *resolve.Function, set by resolver 141 } 142 143 func (x *DefStmt) Span() (start, end Position) { 144 _, end = x.Body[len(x.Body)-1].Span() 145 return x.Def, end 146 } 147 148 // An ExprStmt is an expression evaluated for side effects. 149 type ExprStmt struct { 150 commentsRef 151 X Expr 152 } 153 154 func (x *ExprStmt) Span() (start, end Position) { 155 return x.X.Span() 156 } 157 158 // An IfStmt is a conditional: If Cond: True; else: False. 159 // 'elseif' is desugared into a chain of IfStmts. 160 type IfStmt struct { 161 commentsRef 162 If Position // IF or ELIF 163 Cond Expr 164 True []Stmt 165 ElsePos Position // ELSE or ELIF 166 False []Stmt // optional 167 } 168 169 func (x *IfStmt) Span() (start, end Position) { 170 body := x.False 171 if body == nil { 172 body = x.True 173 } 174 _, end = body[len(body)-1].Span() 175 return x.If, end 176 } 177 178 // A LoadStmt loads another module and binds names from it: 179 // load(Module, "x", y="foo"). 180 // 181 // The AST is slightly unfaithful to the concrete syntax here because 182 // exprcore's load statement, so that it can be implemented in Python, 183 // binds some names (like y above) with an identifier and some (like x) 184 // without. For consistency we create fake identifiers for all the 185 // strings. 186 type LoadStmt struct { 187 commentsRef 188 Load Position 189 Module *Literal // a string 190 From []*Ident // name defined in loading module 191 To []*Ident // name in loaded module 192 Rparen Position 193 } 194 195 func (x *LoadStmt) Span() (start, end Position) { 196 return x.Load, x.Rparen 197 } 198 199 // ModuleName returns the name of the module loaded by this statement. 200 func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) } 201 202 type ImportPackage struct { 203 Namespace *Literal 204 PackageName *Literal 205 BindingName *Ident 206 Args []*BinaryExpr 207 } 208 209 type ImportStmt struct { 210 commentsRef 211 Load Position 212 Imports []*ImportPackage 213 Rparen Position 214 } 215 216 func (x *ImportStmt) Span() (start, end Position) { 217 return x.Load, x.Rparen 218 } 219 220 // A BranchStmt changes the flow of control: break, continue, pass. 221 type BranchStmt struct { 222 commentsRef 223 Token Token // = BREAK | CONTINUE | PASS 224 TokenPos Position 225 } 226 227 func (x *BranchStmt) Span() (start, end Position) { 228 return x.TokenPos, x.TokenPos.add(x.Token.String()) 229 } 230 231 // A ReturnStmt returns from a function. 232 type ReturnStmt struct { 233 commentsRef 234 Return Position 235 Result Expr // may be nil 236 } 237 238 func (x *ReturnStmt) Span() (start, end Position) { 239 if x.Result == nil { 240 return x.Return, x.Return.add("return") 241 } 242 _, end = x.Result.Span() 243 return x.Return, end 244 } 245 246 // An Expr is a exprcore expression. 247 type Expr interface { 248 Node 249 expr() 250 } 251 252 func (*BinaryExpr) expr() {} 253 func (*CallExpr) expr() {} 254 func (*Comprehension) expr() {} 255 func (*CondExpr) expr() {} 256 func (*DictEntry) expr() {} 257 func (*DictExpr) expr() {} 258 func (*DotExpr) expr() {} 259 func (*Ident) expr() {} 260 func (*IndexExpr) expr() {} 261 func (*LambdaExpr) expr() {} 262 func (*ListExpr) expr() {} 263 func (*Literal) expr() {} 264 func (*ParenExpr) expr() {} 265 func (*SliceExpr) expr() {} 266 func (*TupleExpr) expr() {} 267 func (*UnaryExpr) expr() {} 268 func (*AtExpr) expr() {} 269 func (*ProtoExpr) expr() {} 270 func (*ProtoEntry) expr() {} 271 func (*ShellExpr) expr() {} 272 273 // An Ident represents an identifier. 274 type Ident struct { 275 commentsRef 276 NamePos Position 277 Name string 278 279 Binding interface{} // a *resolver.Binding, set by resolver 280 } 281 282 func (x *Ident) Span() (start, end Position) { 283 return x.NamePos, x.NamePos.add(x.Name) 284 } 285 286 // A Literal represents a literal string or number. 287 type Literal struct { 288 commentsRef 289 Token Token // = STRING | INT 290 TokenPos Position 291 Raw string // uninterpreted text 292 Value interface{} // = string | int64 | *big.Int 293 } 294 295 func (x *Literal) Span() (start, end Position) { 296 return x.TokenPos, x.TokenPos.add(x.Raw) 297 } 298 299 // A ParenExpr represents a parenthesized expression: (X). 300 type ParenExpr struct { 301 commentsRef 302 Lparen Position 303 X Expr 304 Rparen Position 305 } 306 307 func (x *ParenExpr) Span() (start, end Position) { 308 return x.Lparen, x.Rparen.add(")") 309 } 310 311 // A CallExpr represents a function call expression: Fn(Args). 312 type CallExpr struct { 313 commentsRef 314 Fn Expr 315 Lparen Position 316 Args []Expr // arg = expr | ident=expr | *expr | **expr 317 Rparen Position 318 } 319 320 func (x *CallExpr) Span() (start, end Position) { 321 start, _ = x.Fn.Span() 322 return start, x.Rparen.add(")") 323 } 324 325 // A DotExpr represents a field or method selector: X.Name. 326 type DotExpr struct { 327 commentsRef 328 X Expr 329 Dot Position 330 NamePos Position 331 Name *Ident 332 } 333 334 func (x *DotExpr) Span() (start, end Position) { 335 start, _ = x.X.Span() 336 _, end = x.Name.Span() 337 return 338 } 339 340 // A Comprehension represents a list or dict comprehension: 341 // [Body for ... if ...] or {Body for ... if ...} 342 type Comprehension struct { 343 commentsRef 344 Curly bool // {x:y for ...} or {x for ...}, not [x for ...] 345 Lbrack Position 346 Body Expr 347 Clauses []Node // = *ForClause | *IfClause 348 Rbrack Position 349 } 350 351 func (x *Comprehension) Span() (start, end Position) { 352 return x.Lbrack, x.Rbrack.add("]") 353 } 354 355 // A ForStmt represents a loop: for Vars in X: Body. 356 type ForStmt struct { 357 commentsRef 358 For Position 359 Vars Expr // name, or tuple of names 360 X Expr 361 Body []Stmt 362 } 363 364 func (x *ForStmt) Span() (start, end Position) { 365 _, end = x.Body[len(x.Body)-1].Span() 366 return x.For, end 367 } 368 369 // A WhileStmt represents a while loop: while X: Body. 370 type WhileStmt struct { 371 commentsRef 372 While Position 373 Cond Expr 374 Body []Stmt 375 } 376 377 func (x *WhileStmt) Span() (start, end Position) { 378 _, end = x.Body[len(x.Body)-1].Span() 379 return x.While, end 380 } 381 382 // A ForClause represents a for clause in a list comprehension: for Vars in X. 383 type ForClause struct { 384 commentsRef 385 For Position 386 Vars Expr // name, or tuple of names 387 In Position 388 X Expr 389 } 390 391 func (x *ForClause) Span() (start, end Position) { 392 _, end = x.X.Span() 393 return x.For, end 394 } 395 396 // An IfClause represents an if clause in a list comprehension: if Cond. 397 type IfClause struct { 398 commentsRef 399 If Position 400 Cond Expr 401 } 402 403 func (x *IfClause) Span() (start, end Position) { 404 _, end = x.Cond.Span() 405 return x.If, end 406 } 407 408 // A DictExpr represents a dictionary literal: { List }. 409 type DictExpr struct { 410 commentsRef 411 Lbrace Position 412 List []Expr // all *DictEntrys 413 Rbrace Position 414 } 415 416 func (x *DictExpr) Span() (start, end Position) { 417 return x.Lbrace, x.Rbrace.add("}") 418 } 419 420 // A DictEntry represents a dictionary entry: Key: Value. 421 // Used only within a DictExpr. 422 type DictEntry struct { 423 commentsRef 424 Key Expr 425 Colon Position 426 Value Expr 427 } 428 429 func (x *DictEntry) Span() (start, end Position) { 430 start, _ = x.Key.Span() 431 _, end = x.Value.Span() 432 return start, end 433 } 434 435 // A ProtoExpr represents a prototype literal: %{ List }. 436 type ProtoExpr struct { 437 commentsRef 438 Lbrace Position 439 List []Stmt // all *ProtoEntrys 440 Rbrace Position 441 } 442 443 func (x *ProtoExpr) Span() (start, end Position) { 444 return x.Lbrace, x.Rbrace.add("}") 445 } 446 447 // A ProtoEntry represents a dictionary entry: Key: Value. 448 // Used only within a ProtoExpr. 449 type ProtoEntry struct { 450 commentsRef 451 Key Expr 452 Colon Position 453 Value Stmt 454 } 455 456 func (x *ProtoEntry) Span() (start, end Position) { 457 start, _ = x.Key.Span() 458 _, end = x.Value.Span() 459 return start, end 460 } 461 462 // A LambdaExpr represents an inline function abstraction. 463 // 464 // Although they may be added in future, lambda expressions are not 465 // currently part of the exprcore spec, so their use is controlled by the 466 // resolver.AllowLambda flag. 467 type LambdaExpr struct { 468 commentsRef 469 Lambda Position 470 Params []Expr // param = ident | ident=expr | * | *ident | **ident 471 Body Expr 472 Stmts []Stmt 473 474 Function interface{} // a *resolve.Function, set by resolver 475 } 476 477 func (x *LambdaExpr) Span() (start, end Position) { 478 if x.Body != nil { 479 _, end = x.Body.Span() 480 } else if x.Stmts != nil { 481 _, end = x.Stmts[len(x.Stmts)-1].Span() 482 } 483 return x.Lambda, end 484 } 485 486 // A ListExpr represents a list literal: [ List ]. 487 type ListExpr struct { 488 commentsRef 489 Lbrack Position 490 List []Expr 491 Rbrack Position 492 } 493 494 func (x *ListExpr) Span() (start, end Position) { 495 return x.Lbrack, x.Rbrack.add("]") 496 } 497 498 // CondExpr represents the conditional: X if COND else ELSE. 499 type CondExpr struct { 500 commentsRef 501 If Position 502 Cond Expr 503 True Expr 504 ElsePos Position 505 False Expr 506 } 507 508 func (x *CondExpr) Span() (start, end Position) { 509 start, _ = x.True.Span() 510 _, end = x.False.Span() 511 return start, end 512 } 513 514 // A TupleExpr represents a tuple literal: (List). 515 type TupleExpr struct { 516 commentsRef 517 Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty 518 List []Expr 519 Rparen Position 520 } 521 522 func (x *TupleExpr) Span() (start, end Position) { 523 if x.Lparen.IsValid() { 524 return x.Lparen, x.Rparen 525 } else { 526 return Start(x.List[0]), End(x.List[len(x.List)-1]) 527 } 528 } 529 530 // A UnaryExpr represents a unary expression: Op X. 531 // 532 // As a special case, UnaryOp{Op:Star} may also represent 533 // the star parameter in def f(*args) or def f(*, x). 534 type UnaryExpr struct { 535 commentsRef 536 OpPos Position 537 Op Token 538 X Expr // may be nil if Op==STAR 539 } 540 541 func (x *UnaryExpr) Span() (start, end Position) { 542 if x.X != nil { 543 _, end = x.X.Span() 544 } else { 545 end = x.OpPos.add("*") 546 } 547 return x.OpPos, end 548 } 549 550 // A AtExpr represents @ ident 551 type AtExpr struct { 552 commentsRef 553 OpPos Position 554 Name string 555 NamePos Position 556 } 557 558 func (x *AtExpr) Span() (start, end Position) { 559 return x.OpPos, x.NamePos.add(x.Name) 560 } 561 562 // A BinaryExpr represents a binary expression: X Op Y. 563 // 564 // As a special case, BinaryExpr{Op:EQ} may also 565 // represent a named argument in a call f(k=v) 566 // or a named parameter in a function declaration 567 // def f(param=default). 568 type BinaryExpr struct { 569 commentsRef 570 X Expr 571 OpPos Position 572 Op Token 573 Y Expr 574 } 575 576 func (x *BinaryExpr) Span() (start, end Position) { 577 start, _ = x.X.Span() 578 _, end = x.Y.Span() 579 return start, end 580 } 581 582 // A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step]. 583 type SliceExpr struct { 584 commentsRef 585 X Expr 586 Lbrack Position 587 Lo, Hi, Step Expr // all optional 588 Rbrack Position 589 } 590 591 func (x *SliceExpr) Span() (start, end Position) { 592 start, _ = x.X.Span() 593 return start, x.Rbrack 594 } 595 596 // An IndexExpr represents an index expression: X[Y]. 597 type IndexExpr struct { 598 commentsRef 599 X Expr 600 Lbrack Position 601 Y Expr 602 Rbrack Position 603 } 604 605 func (x *IndexExpr) Span() (start, end Position) { 606 start, _ = x.X.Span() 607 return start, x.Rbrack 608 }