github.com/cheshirekow/buildtools@v0.0.0-20200224190056-5d637702fe81/build/syntax.go (about) 1 /* 2 Copyright 2016 Google Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package build implements parsing and printing of BUILD files. 18 package build 19 20 // Syntax data structure definitions. 21 22 import ( 23 "strings" 24 "unicode/utf8" 25 ) 26 27 // A Position describes the position between two bytes of input. 28 type Position struct { 29 Line int // line in input (starting at 1) 30 LineRune int // rune in line (starting at 1) 31 Byte int // byte in input (starting at 0) 32 } 33 34 // add returns the position at the end of s, assuming it starts at p. 35 func (p Position) add(s string) Position { 36 p.Byte += len(s) 37 if n := strings.Count(s, "\n"); n > 0 { 38 p.Line += n 39 s = s[strings.LastIndex(s, "\n")+1:] 40 p.LineRune = 1 41 } 42 p.LineRune += utf8.RuneCountInString(s) 43 return p 44 } 45 46 // An Expr represents an input element. 47 type Expr interface { 48 // Span returns the start and end position of the expression, 49 // excluding leading or trailing comments. 50 Span() (start, end Position) 51 52 // Comment returns the comments attached to the expression. 53 // This method would normally be named 'Comments' but that 54 // would interfere with embedding a type of the same name. 55 Comment() *Comments 56 } 57 58 // A Comment represents a single # comment. 59 type Comment struct { 60 Start Position 61 Token string // without trailing newline 62 } 63 64 // Comments collects the comments associated with an expression. 65 type Comments struct { 66 Before []Comment // whole-line comments before this expression 67 Suffix []Comment // end-of-line comments after this expression 68 69 // For top-level expressions only, After lists whole-line 70 // comments following the expression. 71 After []Comment 72 } 73 74 // Comment returns the receiver. This isn't useful by itself, but 75 // a Comments struct is embedded into all the expression 76 // implementation types, and this gives each of those a Comment 77 // method to satisfy the Expr interface. 78 func (c *Comments) Comment() *Comments { 79 return c 80 } 81 82 // stmtsEnd returns the end position of the last non-nil statement 83 func stmtsEnd(stmts []Expr) Position { 84 for i := len(stmts) - 1; i >= 0; i-- { 85 if stmts[i] != nil { 86 _, end := stmts[i].Span() 87 return end 88 } 89 } 90 return Position{} 91 } 92 93 // A File represents an entire BUILD or .bzl file. 94 type File struct { 95 Path string // file path, relative to workspace directory 96 Pkg string // optional; the package of the file 97 Type FileType 98 Comments 99 Stmt []Expr 100 } 101 102 // DisplayPath returns the filename if it's not empty, "<stdin>" otherwise 103 func (f *File) DisplayPath() string { 104 if f.Path == "" { 105 return "<stdin>" 106 } 107 return f.Path 108 } 109 110 func (f *File) Span() (start, end Position) { 111 if len(f.Stmt) == 0 { 112 p := Position{Line: 1, LineRune: 1} 113 return p, p 114 } 115 start = Position{} 116 end = stmtsEnd(f.Stmt) 117 return start, end 118 } 119 120 // A CommentBlock represents a top-level block of comments separate 121 // from any rule. 122 type CommentBlock struct { 123 Comments 124 Start Position 125 } 126 127 func (x *CommentBlock) Span() (start, end Position) { 128 return x.Start, x.Start 129 } 130 131 // An Ident represents an identifier. 132 type Ident struct { 133 Comments 134 NamePos Position 135 Name string 136 } 137 138 func (x *Ident) Span() (start, end Position) { 139 return x.NamePos, x.NamePos.add(x.Name) 140 } 141 142 // BranchStmt represents a `pass`, `break`, or `continue` statement. 143 type BranchStmt struct { 144 Comments 145 Token string // pass, break, continue 146 TokenPos Position 147 } 148 149 func (x *BranchStmt) Span() (start, end Position) { 150 return x.TokenPos, x.TokenPos.add(x.Token) 151 } 152 153 func (x *Ident) asString() *StringExpr { 154 _, end := x.Span() 155 return &StringExpr{ 156 Comments: x.Comments, 157 Start: x.NamePos, 158 Value: x.Name, 159 End: end, 160 } 161 } 162 163 // A LiteralExpr represents a literal number. 164 type LiteralExpr struct { 165 Comments 166 Start Position 167 Token string // identifier token 168 } 169 170 func (x *LiteralExpr) Span() (start, end Position) { 171 return x.Start, x.Start.add(x.Token) 172 } 173 174 // A StringExpr represents a single literal string. 175 type StringExpr struct { 176 Comments 177 Start Position 178 Value string // string value (decoded) 179 TripleQuote bool // triple quote output 180 End Position 181 182 // To allow specific formatting of string literals, 183 // at least within our requirements, record the 184 // preferred form of Value. This field is a hint: 185 // it is only used if it is a valid quoted form for Value. 186 Token string 187 } 188 189 func (x *StringExpr) Span() (start, end Position) { 190 return x.Start, x.End 191 } 192 193 // An End represents the end of a parenthesized or bracketed expression. 194 // It is a place to hang comments. 195 type End struct { 196 Comments 197 Pos Position 198 } 199 200 func (x *End) Span() (start, end Position) { 201 return x.Pos, x.Pos.add(")") 202 } 203 204 // A CallExpr represents a function call expression: X(List). 205 type CallExpr struct { 206 Comments 207 X Expr 208 ListStart Position // position of ( 209 List []Expr 210 End // position of ) 211 ForceCompact bool // force compact (non-multiline) form when printing 212 ForceMultiLine bool // force multiline form when printing 213 } 214 215 func (x *CallExpr) Span() (start, end Position) { 216 start, _ = x.X.Span() 217 return start, x.End.Pos.add(")") 218 } 219 220 // A DotExpr represents a field selector: X.Name. 221 type DotExpr struct { 222 Comments 223 X Expr 224 Dot Position 225 NamePos Position 226 Name string 227 } 228 229 func (x *DotExpr) Span() (start, end Position) { 230 start, _ = x.X.Span() 231 return start, x.NamePos.add(x.Name) 232 } 233 234 // A Comprehension represents a list comprehension expression: [X for ... if ...]. 235 type Comprehension struct { 236 Comments 237 Curly bool // curly braces (as opposed to square brackets) 238 Lbrack Position 239 Body Expr 240 Clauses []Expr // = *ForClause | *IfClause 241 ForceMultiLine bool // split expression across multiple lines 242 End 243 } 244 245 func (x *Comprehension) Span() (start, end Position) { 246 return x.Lbrack, x.End.Pos.add("]") 247 } 248 249 // A ForClause represents a for clause in a list comprehension: for Var in Expr. 250 type ForClause struct { 251 Comments 252 For Position 253 Vars Expr 254 In Position 255 X Expr 256 } 257 258 func (x *ForClause) Span() (start, end Position) { 259 _, end = x.X.Span() 260 return x.For, end 261 } 262 263 // An IfClause represents an if clause in a list comprehension: if Cond. 264 type IfClause struct { 265 Comments 266 If Position 267 Cond Expr 268 } 269 270 func (x *IfClause) Span() (start, end Position) { 271 _, end = x.Cond.Span() 272 return x.If, end 273 } 274 275 // A KeyValueExpr represents a dictionary entry: Key: Value. 276 type KeyValueExpr struct { 277 Comments 278 Key Expr 279 Colon Position 280 Value Expr 281 } 282 283 func (x *KeyValueExpr) Span() (start, end Position) { 284 start, _ = x.Key.Span() 285 _, end = x.Value.Span() 286 return start, end 287 } 288 289 // A DictExpr represents a dictionary literal: { List }. 290 type DictExpr struct { 291 Comments 292 Start Position 293 List []Expr // all *KeyValueExprs 294 End 295 ForceMultiLine bool // force multiline form when printing 296 } 297 298 func (x *DictExpr) Span() (start, end Position) { 299 return x.Start, x.End.Pos.add("}") 300 } 301 302 // A ListExpr represents a list literal: [ List ]. 303 type ListExpr struct { 304 Comments 305 Start Position 306 List []Expr 307 End 308 ForceMultiLine bool // force multiline form when printing 309 } 310 311 func (x *ListExpr) Span() (start, end Position) { 312 return x.Start, x.End.Pos.add("]") 313 } 314 315 // A SetExpr represents a set literal: { List }. 316 type SetExpr struct { 317 Comments 318 Start Position 319 List []Expr 320 End 321 ForceMultiLine bool // force multiline form when printing 322 } 323 324 func (x *SetExpr) Span() (start, end Position) { 325 return x.Start, x.End.Pos.add("}") 326 } 327 328 // A TupleExpr represents a tuple literal: (List) 329 type TupleExpr struct { 330 Comments 331 NoBrackets bool // true if a tuple has no brackets, e.g. `a, b = x` 332 Start Position 333 List []Expr 334 End 335 ForceCompact bool // force compact (non-multiline) form when printing 336 ForceMultiLine bool // force multiline form when printing 337 } 338 339 func (x *TupleExpr) Span() (start, end Position) { 340 if !x.NoBrackets { 341 return x.Start, x.End.Pos.add(")") 342 } 343 start, _ = x.List[0].Span() 344 _, end = x.List[len(x.List)-1].Span() 345 return start, end 346 } 347 348 // A UnaryExpr represents a unary expression: Op X. 349 type UnaryExpr struct { 350 Comments 351 OpStart Position 352 Op string 353 X Expr 354 } 355 356 func (x *UnaryExpr) Span() (start, end Position) { 357 if x.X == nil { 358 return x.OpStart, x.OpStart 359 } 360 _, end = x.X.Span() 361 return x.OpStart, end 362 } 363 364 // A BinaryExpr represents a binary expression: X Op Y. 365 type BinaryExpr struct { 366 Comments 367 X Expr 368 OpStart Position 369 Op string 370 LineBreak bool // insert line break between Op and Y 371 Y Expr 372 } 373 374 func (x *BinaryExpr) Span() (start, end Position) { 375 start, _ = x.X.Span() 376 _, end = x.Y.Span() 377 return start, end 378 } 379 380 // An AssignExpr represents a binary expression with `=`: LHS = RHS. 381 type AssignExpr struct { 382 Comments 383 LHS Expr 384 OpPos Position 385 Op string 386 LineBreak bool // insert line break between Op and RHS 387 RHS Expr 388 } 389 390 func (x *AssignExpr) Span() (start, end Position) { 391 start, _ = x.LHS.Span() 392 _, end = x.RHS.Span() 393 return start, end 394 } 395 396 // A ParenExpr represents a parenthesized expression: (X). 397 type ParenExpr struct { 398 Comments 399 Start Position 400 X Expr 401 End 402 ForceMultiLine bool // insert line break after opening ( and before closing ) 403 } 404 405 func (x *ParenExpr) Span() (start, end Position) { 406 return x.Start, x.End.Pos.add(")") 407 } 408 409 // A SliceExpr represents a slice expression: expr[from:to] or expr[from:to:step] . 410 type SliceExpr struct { 411 Comments 412 X Expr 413 SliceStart Position 414 From Expr 415 FirstColon Position 416 To Expr 417 SecondColon Position 418 Step Expr 419 End Position 420 } 421 422 func (x *SliceExpr) Span() (start, end Position) { 423 start, _ = x.X.Span() 424 return start, x.End.add("]") 425 } 426 427 // An IndexExpr represents an index expression: X[Y]. 428 type IndexExpr struct { 429 Comments 430 X Expr 431 IndexStart Position 432 Y Expr 433 End Position 434 } 435 436 func (x *IndexExpr) Span() (start, end Position) { 437 start, _ = x.X.Span() 438 return start, x.End.add("]") 439 } 440 441 // A Function represents the common parts of LambdaExpr and DefStmt 442 type Function struct { 443 Comments 444 StartPos Position // position of DEF or LAMBDA token 445 Params []Expr 446 Body []Expr 447 } 448 449 func (x *Function) Span() (start, end Position) { 450 _, end = x.Body[len(x.Body)-1].Span() 451 return x.StartPos, end 452 } 453 454 // A LambdaExpr represents a lambda expression: lambda Var: Expr. 455 type LambdaExpr struct { 456 Comments 457 Function 458 } 459 460 func (x *LambdaExpr) Span() (start, end Position) { 461 return x.Function.Span() 462 } 463 464 // ConditionalExpr represents the conditional: X if TEST else ELSE. 465 type ConditionalExpr struct { 466 Comments 467 Then Expr 468 IfStart Position 469 Test Expr 470 ElseStart Position 471 Else Expr 472 } 473 474 // Span returns the start and end position of the expression, 475 // excluding leading or trailing comments. 476 func (x *ConditionalExpr) Span() (start, end Position) { 477 start, _ = x.Then.Span() 478 _, end = x.Else.Span() 479 return start, end 480 } 481 482 // A LoadStmt loads another module and binds names from it: 483 // load(Module, "x", y="foo"). 484 // 485 // The AST is slightly unfaithful to the concrete syntax here because 486 // Skylark's load statement, so that it can be implemented in Python, 487 // binds some names (like y above) with an identifier and some (like x) 488 // without. For consistency we create fake identifiers for all the 489 // strings. 490 type LoadStmt struct { 491 Comments 492 Load Position 493 Module *StringExpr 494 From []*Ident // name defined in loading module 495 To []*Ident // name in loaded module 496 Rparen End 497 ForceCompact bool // force compact (non-multiline) form when printing 498 } 499 500 func (x *LoadStmt) Span() (start, end Position) { 501 return x.Load, x.Rparen.Pos.add(")") 502 } 503 504 // A DefStmt represents a function definition expression: def foo(List):. 505 type DefStmt struct { 506 Comments 507 Function 508 Name string 509 ColonPos Position // position of the ":" 510 ForceCompact bool // force compact (non-multiline) form when printing the arguments 511 ForceMultiLine bool // force multiline form when printing the arguments 512 } 513 514 func (x *DefStmt) Span() (start, end Position) { 515 return x.Function.Span() 516 } 517 518 // HeaderSpan returns the span of the function header `def f(...):` 519 func (x *DefStmt) HeaderSpan() (start, end Position) { 520 return x.Function.StartPos, x.ColonPos 521 } 522 523 // A ReturnStmt represents a return statement: return f(x). 524 type ReturnStmt struct { 525 Comments 526 Return Position 527 Result Expr // may be nil 528 } 529 530 func (x *ReturnStmt) Span() (start, end Position) { 531 if x.Result == nil { 532 return x.Return, x.Return.add("return") 533 } 534 _, end = x.Result.Span() 535 return x.Return, end 536 } 537 538 // A ForStmt represents a for loop block: for x in range(10):. 539 type ForStmt struct { 540 Comments 541 Function 542 For Position // position of for 543 Vars Expr 544 X Expr 545 Body []Expr 546 } 547 548 func (x *ForStmt) Span() (start, end Position) { 549 end = stmtsEnd(x.Body) 550 return x.For, end 551 } 552 553 // An IfStmt represents an if-else block: if x: ... else: ... . 554 // `elif`s are treated as a chain of `IfStmt`s. 555 type IfStmt struct { 556 Comments 557 If Position // position of if 558 Cond Expr 559 True []Expr 560 ElsePos End // position of else or elif 561 False []Expr // optional 562 } 563 564 func (x *IfStmt) Span() (start, end Position) { 565 body := x.False 566 if body == nil { 567 body = x.True 568 } 569 end = stmtsEnd(body) 570 return x.If, end 571 }