github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/blueprint/parser/parser.go (about) 1 // Copyright 2014 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package parser 16 17 import ( 18 "errors" 19 "fmt" 20 "io" 21 "sort" 22 "strconv" 23 "strings" 24 "text/scanner" 25 ) 26 27 var errTooManyErrors = errors.New("too many errors") 28 29 const maxErrors = 1 30 31 type ParseError struct { 32 Err error 33 Pos scanner.Position 34 } 35 36 func (e *ParseError) Error() string { 37 return fmt.Sprintf("%s: %s", e.Pos, e.Err) 38 } 39 40 type File struct { 41 Name string 42 Defs []Definition 43 Comments []*CommentGroup 44 } 45 46 func (f *File) Pos() scanner.Position { 47 return scanner.Position{ 48 Filename: f.Name, 49 Line: 1, 50 Column: 1, 51 Offset: 0, 52 } 53 } 54 55 func (f *File) End() scanner.Position { 56 if len(f.Defs) > 0 { 57 return f.Defs[len(f.Defs)-1].End() 58 } 59 return noPos 60 } 61 62 func parse(p *parser) (file *File, errs []error) { 63 defer func() { 64 if r := recover(); r != nil { 65 if r == errTooManyErrors { 66 errs = p.errors 67 return 68 } 69 panic(r) 70 } 71 }() 72 73 defs := p.parseDefinitions() 74 p.accept(scanner.EOF) 75 errs = p.errors 76 comments := p.comments 77 78 return &File{ 79 Name: p.scanner.Filename, 80 Defs: defs, 81 Comments: comments, 82 }, errs 83 84 } 85 86 func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) { 87 p := newParser(r, scope) 88 p.eval = true 89 p.scanner.Filename = filename 90 91 return parse(p) 92 } 93 94 func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error) { 95 p := newParser(r, scope) 96 p.scanner.Filename = filename 97 98 return parse(p) 99 } 100 101 type parser struct { 102 scanner scanner.Scanner 103 tok rune 104 errors []error 105 scope *Scope 106 comments []*CommentGroup 107 eval bool 108 } 109 110 func newParser(r io.Reader, scope *Scope) *parser { 111 p := &parser{} 112 p.scope = scope 113 p.scanner.Init(r) 114 p.scanner.Error = func(sc *scanner.Scanner, msg string) { 115 p.errorf(msg) 116 } 117 p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | 118 scanner.ScanRawStrings | scanner.ScanComments 119 p.next() 120 return p 121 } 122 123 func (p *parser) error(err error) { 124 pos := p.scanner.Position 125 if !pos.IsValid() { 126 pos = p.scanner.Pos() 127 } 128 err = &ParseError{ 129 Err: err, 130 Pos: pos, 131 } 132 p.errors = append(p.errors, err) 133 if len(p.errors) >= maxErrors { 134 panic(errTooManyErrors) 135 } 136 } 137 138 func (p *parser) errorf(format string, args ...interface{}) { 139 p.error(fmt.Errorf(format, args...)) 140 } 141 142 func (p *parser) accept(toks ...rune) bool { 143 for _, tok := range toks { 144 if p.tok != tok { 145 p.errorf("expected %s, found %s", scanner.TokenString(tok), 146 scanner.TokenString(p.tok)) 147 return false 148 } 149 p.next() 150 } 151 return true 152 } 153 154 func (p *parser) next() { 155 if p.tok != scanner.EOF { 156 p.tok = p.scanner.Scan() 157 if p.tok == scanner.Comment { 158 var comments []*Comment 159 for p.tok == scanner.Comment { 160 lines := strings.Split(p.scanner.TokenText(), "\n") 161 if len(comments) > 0 && p.scanner.Position.Line > comments[len(comments)-1].End().Line+1 { 162 p.comments = append(p.comments, &CommentGroup{Comments: comments}) 163 comments = nil 164 } 165 comments = append(comments, &Comment{lines, p.scanner.Position}) 166 p.tok = p.scanner.Scan() 167 } 168 p.comments = append(p.comments, &CommentGroup{Comments: comments}) 169 } 170 } 171 return 172 } 173 174 func (p *parser) parseDefinitions() (defs []Definition) { 175 for { 176 switch p.tok { 177 case scanner.Ident: 178 ident := p.scanner.TokenText() 179 pos := p.scanner.Position 180 181 p.accept(scanner.Ident) 182 183 switch p.tok { 184 case '+': 185 p.accept('+') 186 defs = append(defs, p.parseAssignment(ident, pos, "+=")) 187 case '=': 188 defs = append(defs, p.parseAssignment(ident, pos, "=")) 189 case '{', '(': 190 defs = append(defs, p.parseModule(ident, pos)) 191 default: 192 p.errorf("expected \"=\" or \"+=\" or \"{\" or \"(\", found %s", 193 scanner.TokenString(p.tok)) 194 } 195 case scanner.EOF: 196 return 197 default: 198 p.errorf("expected assignment or module definition, found %s", 199 scanner.TokenString(p.tok)) 200 return 201 } 202 } 203 } 204 205 func (p *parser) parseAssignment(name string, namePos scanner.Position, 206 assigner string) (assignment *Assignment) { 207 208 assignment = new(Assignment) 209 210 pos := p.scanner.Position 211 if !p.accept('=') { 212 return 213 } 214 value := p.parseExpression() 215 216 assignment.Name = name 217 assignment.NamePos = namePos 218 assignment.Value = value 219 assignment.OrigValue = value 220 assignment.EqualsPos = pos 221 assignment.Assigner = assigner 222 223 if p.scope != nil { 224 if assigner == "+=" { 225 if old, local := p.scope.Get(assignment.Name); old == nil { 226 p.errorf("modified non-existent variable %q with +=", assignment.Name) 227 } else if !local { 228 p.errorf("modified non-local variable %q with +=", assignment.Name) 229 } else if old.Referenced { 230 p.errorf("modified variable %q with += after referencing", assignment.Name) 231 } else { 232 val, err := p.evaluateOperator(old.Value, assignment.Value, '+', assignment.EqualsPos) 233 if err != nil { 234 p.error(err) 235 } else { 236 old.Value = val 237 } 238 } 239 } else { 240 err := p.scope.Add(assignment) 241 if err != nil { 242 p.error(err) 243 } 244 } 245 } 246 247 return 248 } 249 250 func (p *parser) parseModule(typ string, typPos scanner.Position) *Module { 251 252 compat := false 253 lbracePos := p.scanner.Position 254 if p.tok == '{' { 255 compat = true 256 } 257 258 if !p.accept(p.tok) { 259 return nil 260 } 261 properties := p.parsePropertyList(true, compat) 262 rbracePos := p.scanner.Position 263 if !compat { 264 p.accept(')') 265 } else { 266 p.accept('}') 267 } 268 269 return &Module{ 270 Type: typ, 271 TypePos: typPos, 272 Map: Map{ 273 Properties: properties, 274 LBracePos: lbracePos, 275 RBracePos: rbracePos, 276 }, 277 } 278 } 279 280 func (p *parser) parsePropertyList(isModule, compat bool) (properties []*Property) { 281 for p.tok == scanner.Ident { 282 property := p.parseProperty(isModule, compat) 283 properties = append(properties, property) 284 285 if p.tok != ',' { 286 // There was no comma, so the list is done. 287 break 288 } 289 290 p.accept(',') 291 } 292 293 return 294 } 295 296 func (p *parser) parseProperty(isModule, compat bool) (property *Property) { 297 property = new(Property) 298 299 name := p.scanner.TokenText() 300 namePos := p.scanner.Position 301 p.accept(scanner.Ident) 302 pos := p.scanner.Position 303 304 if isModule { 305 if compat && p.tok == ':' { 306 p.accept(':') 307 } else { 308 if !p.accept('=') { 309 return 310 } 311 } 312 } else { 313 if !p.accept(':') { 314 return 315 } 316 } 317 318 value := p.parseExpression() 319 320 property.Name = name 321 property.NamePos = namePos 322 property.Value = value 323 property.ColonPos = pos 324 325 return 326 } 327 328 func (p *parser) parseExpression() (value Expression) { 329 value = p.parseValue() 330 switch p.tok { 331 case '+': 332 return p.parseOperator(value) 333 case '-': 334 p.errorf("subtraction not supported: %s", p.scanner.String()) 335 return value 336 default: 337 return value 338 } 339 } 340 341 func (p *parser) evaluateOperator(value1, value2 Expression, operator rune, 342 pos scanner.Position) (*Operator, error) { 343 344 value := value1 345 346 if p.eval { 347 e1 := value1.Eval() 348 e2 := value2.Eval() 349 if e1.Type() != e2.Type() { 350 return nil, fmt.Errorf("mismatched type in operator %c: %s != %s", operator, 351 e1.Type(), e2.Type()) 352 } 353 354 value = e1.Copy() 355 356 switch operator { 357 case '+': 358 switch v := value.(type) { 359 case *String: 360 v.Value += e2.(*String).Value 361 case *Int64: 362 v.Value += e2.(*Int64).Value 363 v.Token = "" 364 case *List: 365 v.Values = append(v.Values, e2.(*List).Values...) 366 case *Map: 367 var err error 368 v.Properties, err = p.addMaps(v.Properties, e2.(*Map).Properties, pos) 369 if err != nil { 370 return nil, err 371 } 372 default: 373 return nil, fmt.Errorf("operator %c not supported on type %s", operator, v.Type()) 374 } 375 default: 376 panic("unknown operator " + string(operator)) 377 } 378 } 379 380 return &Operator{ 381 Args: [2]Expression{value1, value2}, 382 Operator: operator, 383 OperatorPos: pos, 384 Value: value, 385 }, nil 386 } 387 388 func (p *parser) addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) { 389 ret := make([]*Property, 0, len(map1)) 390 391 inMap1 := make(map[string]*Property) 392 inMap2 := make(map[string]*Property) 393 inBoth := make(map[string]*Property) 394 395 for _, prop1 := range map1 { 396 inMap1[prop1.Name] = prop1 397 } 398 399 for _, prop2 := range map2 { 400 inMap2[prop2.Name] = prop2 401 if _, ok := inMap1[prop2.Name]; ok { 402 inBoth[prop2.Name] = prop2 403 } 404 } 405 406 for _, prop1 := range map1 { 407 if prop2, ok := inBoth[prop1.Name]; ok { 408 var err error 409 newProp := *prop1 410 newProp.Value, err = p.evaluateOperator(prop1.Value, prop2.Value, '+', pos) 411 if err != nil { 412 return nil, err 413 } 414 ret = append(ret, &newProp) 415 } else { 416 ret = append(ret, prop1) 417 } 418 } 419 420 for _, prop2 := range map2 { 421 if _, ok := inBoth[prop2.Name]; !ok { 422 ret = append(ret, prop2) 423 } 424 } 425 426 return ret, nil 427 } 428 429 func (p *parser) parseOperator(value1 Expression) *Operator { 430 operator := p.tok 431 pos := p.scanner.Position 432 p.accept(operator) 433 434 value2 := p.parseExpression() 435 436 value, err := p.evaluateOperator(value1, value2, operator, pos) 437 if err != nil { 438 p.error(err) 439 return nil 440 } 441 442 return value 443 444 } 445 446 func (p *parser) parseValue() (value Expression) { 447 switch p.tok { 448 case scanner.Ident: 449 return p.parseVariable() 450 case '-', scanner.Int: // Integer might have '-' sign ahead ('+' is only treated as operator now) 451 return p.parseIntValue() 452 case scanner.String: 453 return p.parseStringValue() 454 case '[': 455 return p.parseListValue() 456 case '{': 457 return p.parseMapValue() 458 default: 459 p.errorf("expected bool, list, or string value; found %s", 460 scanner.TokenString(p.tok)) 461 return 462 } 463 } 464 465 func (p *parser) parseVariable() Expression { 466 var value Expression 467 468 switch text := p.scanner.TokenText(); text { 469 case "true", "false": 470 value = &Bool{ 471 LiteralPos: p.scanner.Position, 472 Value: text == "true", 473 Token: text, 474 } 475 default: 476 if p.eval { 477 if assignment, local := p.scope.Get(text); assignment == nil { 478 p.errorf("variable %q is not set", text) 479 } else { 480 if local { 481 assignment.Referenced = true 482 } 483 value = assignment.Value 484 } 485 } 486 value = &Variable{ 487 Name: text, 488 NamePos: p.scanner.Position, 489 Value: value, 490 } 491 } 492 493 p.accept(scanner.Ident) 494 return value 495 } 496 497 func (p *parser) parseStringValue() *String { 498 str, err := strconv.Unquote(p.scanner.TokenText()) 499 if err != nil { 500 p.errorf("couldn't parse string: %s", err) 501 return nil 502 } 503 504 value := &String{ 505 LiteralPos: p.scanner.Position, 506 Value: str, 507 } 508 p.accept(scanner.String) 509 return value 510 } 511 512 func (p *parser) parseIntValue() *Int64 { 513 var str string 514 literalPos := p.scanner.Position 515 if p.tok == '-' { 516 str += string(p.tok) 517 p.accept(p.tok) 518 if p.tok != scanner.Int { 519 p.errorf("expected int; found %s", scanner.TokenString(p.tok)) 520 return nil 521 } 522 } 523 str += p.scanner.TokenText() 524 i, err := strconv.ParseInt(str, 10, 64) 525 if err != nil { 526 p.errorf("couldn't parse int: %s", err) 527 return nil 528 } 529 530 value := &Int64{ 531 LiteralPos: literalPos, 532 Value: i, 533 Token: str, 534 } 535 p.accept(scanner.Int) 536 return value 537 } 538 539 func (p *parser) parseListValue() *List { 540 lBracePos := p.scanner.Position 541 if !p.accept('[') { 542 return nil 543 } 544 545 var elements []Expression 546 for p.tok != ']' { 547 element := p.parseExpression() 548 if p.eval && element.Type() != StringType { 549 p.errorf("Expected string in list, found %s", element.Type().String()) 550 return nil 551 } 552 elements = append(elements, element) 553 554 if p.tok != ',' { 555 // There was no comma, so the list is done. 556 break 557 } 558 559 p.accept(',') 560 } 561 562 rBracePos := p.scanner.Position 563 p.accept(']') 564 565 return &List{ 566 LBracePos: lBracePos, 567 RBracePos: rBracePos, 568 Values: elements, 569 } 570 } 571 572 func (p *parser) parseMapValue() *Map { 573 lBracePos := p.scanner.Position 574 if !p.accept('{') { 575 return nil 576 } 577 578 properties := p.parsePropertyList(false, false) 579 580 rBracePos := p.scanner.Position 581 p.accept('}') 582 583 return &Map{ 584 LBracePos: lBracePos, 585 RBracePos: rBracePos, 586 Properties: properties, 587 } 588 } 589 590 type Scope struct { 591 vars map[string]*Assignment 592 inheritedVars map[string]*Assignment 593 } 594 595 func NewScope(s *Scope) *Scope { 596 newScope := &Scope{ 597 vars: make(map[string]*Assignment), 598 inheritedVars: make(map[string]*Assignment), 599 } 600 601 if s != nil { 602 for k, v := range s.vars { 603 newScope.inheritedVars[k] = v 604 } 605 for k, v := range s.inheritedVars { 606 newScope.inheritedVars[k] = v 607 } 608 } 609 610 return newScope 611 } 612 613 func (s *Scope) Add(assignment *Assignment) error { 614 if old, ok := s.vars[assignment.Name]; ok { 615 return fmt.Errorf("variable already set, previous assignment: %s", old) 616 } 617 618 if old, ok := s.inheritedVars[assignment.Name]; ok { 619 return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old) 620 } 621 622 s.vars[assignment.Name] = assignment 623 624 return nil 625 } 626 627 func (s *Scope) Remove(name string) { 628 delete(s.vars, name) 629 delete(s.inheritedVars, name) 630 } 631 632 func (s *Scope) Get(name string) (*Assignment, bool) { 633 if a, ok := s.vars[name]; ok { 634 return a, true 635 } 636 637 if a, ok := s.inheritedVars[name]; ok { 638 return a, false 639 } 640 641 return nil, false 642 } 643 644 func (s *Scope) String() string { 645 vars := []string{} 646 647 for k := range s.vars { 648 vars = append(vars, k) 649 } 650 for k := range s.inheritedVars { 651 vars = append(vars, k) 652 } 653 654 sort.Strings(vars) 655 656 ret := []string{} 657 for _, v := range vars { 658 if assignment, ok := s.vars[v]; ok { 659 ret = append(ret, assignment.String()) 660 } else { 661 ret = append(ret, s.inheritedVars[v].String()) 662 } 663 } 664 665 return strings.Join(ret, "\n") 666 }