1// Copyright 2016 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 15package parser 16 17import ( 18 "fmt" 19 "strings" 20 "text/scanner" 21) 22 23type Node interface { 24 // Pos returns the position of the first token in the Node 25 Pos() scanner.Position 26 // End returns the position of the character after the last token in the Node 27 End() scanner.Position 28} 29 30// Definition is an Assignment or a Module at the top level of a Blueprints file 31type Definition interface { 32 Node 33 String() string 34 definitionTag() 35} 36 37// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the 38// file and subdirs. 39type Assignment struct { 40 Name string 41 NamePos scanner.Position 42 Value Expression 43 OrigValue Expression 44 EqualsPos scanner.Position 45 Assigner string 46 Referenced bool 47} 48 49func (a *Assignment) String() string { 50 return fmt.Sprintf("%s@%s %s %s (%s) %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.OrigValue, a.Referenced) 51} 52 53func (a *Assignment) Pos() scanner.Position { return a.NamePos } 54func (a *Assignment) End() scanner.Position { return a.Value.End() } 55 56func (a *Assignment) definitionTag() {} 57 58// A Module is a module definition at the top level of a Blueprints file 59type Module struct { 60 Type string 61 TypePos scanner.Position 62 Map 63 //TODO(delmerico) make this a private field once ag/21588220 lands 64 Name__internal_only *string 65} 66 67func (m *Module) Copy() *Module { 68 ret := *m 69 ret.Properties = make([]*Property, len(m.Properties)) 70 for i := range m.Properties { 71 ret.Properties[i] = m.Properties[i].Copy() 72 } 73 return &ret 74} 75 76func (m *Module) String() string { 77 propertyStrings := make([]string, len(m.Properties)) 78 for i, property := range m.Properties { 79 propertyStrings[i] = property.String() 80 } 81 return fmt.Sprintf("%s@%s-%s{%s}", m.Type, 82 m.LBracePos, m.RBracePos, 83 strings.Join(propertyStrings, ", ")) 84} 85 86func (m *Module) definitionTag() {} 87 88func (m *Module) Pos() scanner.Position { return m.TypePos } 89func (m *Module) End() scanner.Position { return m.Map.End() } 90 91func (m *Module) Name() string { 92 if m.Name__internal_only != nil { 93 return *m.Name__internal_only 94 } 95 for _, prop := range m.Properties { 96 if prop.Name == "name" { 97 if stringProp, ok := prop.Value.(*String); ok { 98 name := stringProp.Value 99 m.Name__internal_only = &name 100 } else { 101 name := prop.Value.String() 102 m.Name__internal_only = &name 103 } 104 } 105 } 106 if m.Name__internal_only == nil { 107 name := "" 108 m.Name__internal_only = &name 109 } 110 return *m.Name__internal_only 111} 112 113// A Property is a name: value pair within a Map, which may be a top level Module. 114type Property struct { 115 Name string 116 NamePos scanner.Position 117 ColonPos scanner.Position 118 Value Expression 119} 120 121func (p *Property) Copy() *Property { 122 ret := *p 123 ret.Value = p.Value.Copy() 124 return &ret 125} 126 127func (p *Property) String() string { 128 return fmt.Sprintf("%s@%s: %s", p.Name, p.ColonPos, p.Value) 129} 130 131func (p *Property) Pos() scanner.Position { return p.NamePos } 132func (p *Property) End() scanner.Position { return p.Value.End() } 133 134// An Expression is a Value in a Property or Assignment. It can be a literal (String or Bool), a 135// Map, a List, an Operator that combines two expressions of the same type, or a Variable that 136// references and Assignment. 137type Expression interface { 138 Node 139 // Copy returns a copy of the Expression that will not affect the original if mutated 140 Copy() Expression 141 String() string 142 // Type returns the underlying Type enum of the Expression if it were to be evaluated 143 Type() Type 144 // Eval returns an expression that is fully evaluated to a simple type (List, Map, String, or 145 // Bool). It will return the same object for every call to Eval(). 146 Eval() Expression 147} 148 149// ExpressionsAreSame tells whether the two values are the same Expression. 150// This includes the symbolic representation of each Expression but not their positions in the original source tree. 151// This does not apply any simplification to the expressions before comparing them 152// (for example, "!!a" wouldn't be deemed equal to "a") 153func ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) { 154 return hackyExpressionsAreSame(a, b) 155} 156 157// TODO(jeffrygaston) once positions are removed from Expression structs, 158// remove this function and have callers use reflect.DeepEqual(a, b) 159func hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) { 160 if a.Type() != b.Type() { 161 return false, nil 162 } 163 left, err := hackyFingerprint(a) 164 if err != nil { 165 return false, nil 166 } 167 right, err := hackyFingerprint(b) 168 if err != nil { 169 return false, nil 170 } 171 areEqual := string(left) == string(right) 172 return areEqual, nil 173} 174 175func hackyFingerprint(expression Expression) (fingerprint []byte, err error) { 176 assignment := &Assignment{"a", noPos, expression, expression, noPos, "=", false} 177 module := &File{} 178 module.Defs = append(module.Defs, assignment) 179 p := newPrinter(module) 180 return p.Print() 181} 182 183type Type int 184 185const ( 186 BoolType Type = iota + 1 187 StringType 188 Int64Type 189 ListType 190 MapType 191 NotEvaluatedType 192 UnsetType 193) 194 195func (t Type) String() string { 196 switch t { 197 case BoolType: 198 return "bool" 199 case StringType: 200 return "string" 201 case Int64Type: 202 return "int64" 203 case ListType: 204 return "list" 205 case MapType: 206 return "map" 207 case NotEvaluatedType: 208 return "notevaluated" 209 case UnsetType: 210 return "unset" 211 default: 212 panic(fmt.Errorf("Unknown type %d", t)) 213 } 214} 215 216type Operator struct { 217 Args [2]Expression 218 Operator rune 219 OperatorPos scanner.Position 220 Value Expression 221} 222 223func (x *Operator) Copy() Expression { 224 ret := *x 225 ret.Args[0] = x.Args[0].Copy() 226 ret.Args[1] = x.Args[1].Copy() 227 return &ret 228} 229 230func (x *Operator) Eval() Expression { 231 return x.Value.Eval() 232} 233 234func (x *Operator) Type() Type { 235 return x.Args[0].Type() 236} 237 238func (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() } 239func (x *Operator) End() scanner.Position { return x.Args[1].End() } 240 241func (x *Operator) String() string { 242 return fmt.Sprintf("(%s %c %s = %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(), 243 x.Value, x.OperatorPos) 244} 245 246type Variable struct { 247 Name string 248 NamePos scanner.Position 249 Value Expression 250} 251 252func (x *Variable) Pos() scanner.Position { return x.NamePos } 253func (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) } 254 255func (x *Variable) Copy() Expression { 256 ret := *x 257 return &ret 258} 259 260func (x *Variable) Eval() Expression { 261 return x.Value.Eval() 262} 263 264func (x *Variable) String() string { 265 return x.Name + " = " + x.Value.String() 266} 267 268func (x *Variable) Type() Type { return x.Value.Type() } 269 270type Map struct { 271 LBracePos scanner.Position 272 RBracePos scanner.Position 273 Properties []*Property 274} 275 276func (x *Map) Pos() scanner.Position { return x.LBracePos } 277func (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) } 278 279func (x *Map) Copy() Expression { 280 ret := *x 281 ret.Properties = make([]*Property, len(x.Properties)) 282 for i := range x.Properties { 283 ret.Properties[i] = x.Properties[i].Copy() 284 } 285 return &ret 286} 287 288func (x *Map) Eval() Expression { 289 return x 290} 291 292func (x *Map) String() string { 293 propertyStrings := make([]string, len(x.Properties)) 294 for i, property := range x.Properties { 295 propertyStrings[i] = property.String() 296 } 297 return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos, 298 strings.Join(propertyStrings, ", ")) 299} 300 301func (x *Map) Type() Type { return MapType } 302 303// GetProperty looks for a property with the given name. 304// It resembles the bracket operator of a built-in Golang map. 305func (x *Map) GetProperty(name string) (Property *Property, found bool) { 306 prop, found, _ := x.getPropertyImpl(name) 307 return prop, found // we don't currently expose the index to callers 308} 309 310func (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) { 311 for i, prop := range x.Properties { 312 if prop.Name == name { 313 return prop, true, i 314 } 315 } 316 return nil, false, -1 317} 318 319// RemoveProperty removes the property with the given name, if it exists. 320func (x *Map) RemoveProperty(propertyName string) (removed bool) { 321 _, found, index := x.getPropertyImpl(propertyName) 322 if found { 323 x.Properties = append(x.Properties[:index], x.Properties[index+1:]...) 324 } 325 return found 326} 327 328// MovePropertyContents moves the contents of propertyName into property newLocation 329// If property newLocation doesn't exist, MovePropertyContents renames propertyName as newLocation. 330// Otherwise, MovePropertyContents only supports moving contents that are a List of String. 331func (x *Map) MovePropertyContents(propertyName string, newLocation string) (removed bool) { 332 oldProp, oldFound, _ := x.getPropertyImpl(propertyName) 333 newProp, newFound, _ := x.getPropertyImpl(newLocation) 334 335 // newLoc doesn't exist, simply renaming property 336 if oldFound && !newFound { 337 oldProp.Name = newLocation 338 return oldFound 339 } 340 341 if oldFound { 342 old, oldOk := oldProp.Value.(*List) 343 new, newOk := newProp.Value.(*List) 344 if oldOk && newOk { 345 toBeMoved := make([]string, len(old.Values)) // 346 for i, p := range old.Values { 347 toBeMoved[i] = p.(*String).Value 348 } 349 350 for _, moved := range toBeMoved { 351 RemoveStringFromList(old, moved) 352 AddStringToList(new, moved) 353 } 354 // oldProp should now be empty and needs to be deleted 355 x.RemoveProperty(oldProp.Name) 356 } else { 357 print(`MovePropertyContents currently only supports moving PropertyName 358 with List of Strings into an existing newLocation with List of Strings\n`) 359 } 360 } 361 return oldFound 362} 363 364type List struct { 365 LBracePos scanner.Position 366 RBracePos scanner.Position 367 Values []Expression 368} 369 370func (x *List) Pos() scanner.Position { return x.LBracePos } 371func (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) } 372 373func (x *List) Copy() Expression { 374 ret := *x 375 ret.Values = make([]Expression, len(x.Values)) 376 for i := range ret.Values { 377 ret.Values[i] = x.Values[i].Copy() 378 } 379 return &ret 380} 381 382func (x *List) Eval() Expression { 383 return x 384} 385 386func (x *List) String() string { 387 valueStrings := make([]string, len(x.Values)) 388 for i, value := range x.Values { 389 valueStrings[i] = value.String() 390 } 391 return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos, 392 strings.Join(valueStrings, ", ")) 393} 394 395func (x *List) Type() Type { return ListType } 396 397type String struct { 398 LiteralPos scanner.Position 399 Value string 400} 401 402func (x *String) Pos() scanner.Position { return x.LiteralPos } 403func (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) } 404 405func (x *String) Copy() Expression { 406 ret := *x 407 return &ret 408} 409 410func (x *String) Eval() Expression { 411 return x 412} 413 414func (x *String) String() string { 415 return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) 416} 417 418func (x *String) Type() Type { 419 return StringType 420} 421 422type Int64 struct { 423 LiteralPos scanner.Position 424 Value int64 425 Token string 426} 427 428func (x *Int64) Pos() scanner.Position { return x.LiteralPos } 429func (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } 430 431func (x *Int64) Copy() Expression { 432 ret := *x 433 return &ret 434} 435 436func (x *Int64) Eval() Expression { 437 return x 438} 439 440func (x *Int64) String() string { 441 return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) 442} 443 444func (x *Int64) Type() Type { 445 return Int64Type 446} 447 448type Bool struct { 449 LiteralPos scanner.Position 450 Value bool 451 Token string 452} 453 454func (x *Bool) Pos() scanner.Position { return x.LiteralPos } 455func (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } 456 457func (x *Bool) Copy() Expression { 458 ret := *x 459 return &ret 460} 461 462func (x *Bool) Eval() Expression { 463 return x 464} 465 466func (x *Bool) String() string { 467 return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos) 468} 469 470func (x *Bool) Type() Type { 471 return BoolType 472} 473 474type CommentGroup struct { 475 Comments []*Comment 476} 477 478func (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() } 479func (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() } 480 481type Comment struct { 482 Comment []string 483 Slash scanner.Position 484} 485 486func (c Comment) Pos() scanner.Position { 487 return c.Slash 488} 489 490func (c Comment) End() scanner.Position { 491 pos := c.Slash 492 for _, comment := range c.Comment { 493 pos.Offset += len(comment) + 1 494 pos.Column = len(comment) + 1 495 } 496 pos.Line += len(c.Comment) - 1 497 return pos 498} 499 500func (c Comment) String() string { 501 l := 0 502 for _, comment := range c.Comment { 503 l += len(comment) + 1 504 } 505 buf := make([]byte, 0, l) 506 for _, comment := range c.Comment { 507 buf = append(buf, comment...) 508 buf = append(buf, '\n') 509 } 510 511 return string(buf) + "@" + c.Slash.String() 512} 513 514// Return the text of the comment with // or /* and */ stripped 515func (c Comment) Text() string { 516 l := 0 517 for _, comment := range c.Comment { 518 l += len(comment) + 1 519 } 520 buf := make([]byte, 0, l) 521 522 blockComment := false 523 if strings.HasPrefix(c.Comment[0], "/*") { 524 blockComment = true 525 } 526 527 for i, comment := range c.Comment { 528 if blockComment { 529 if i == 0 { 530 comment = strings.TrimPrefix(comment, "/*") 531 } 532 if i == len(c.Comment)-1 { 533 comment = strings.TrimSuffix(comment, "*/") 534 } 535 } else { 536 comment = strings.TrimPrefix(comment, "//") 537 } 538 buf = append(buf, comment...) 539 buf = append(buf, '\n') 540 } 541 542 return string(buf) 543} 544 545type NotEvaluated struct { 546 Position scanner.Position 547} 548 549func (n NotEvaluated) Copy() Expression { 550 return NotEvaluated{Position: n.Position} 551} 552 553func (n NotEvaluated) String() string { 554 return "Not Evaluated" 555} 556 557func (n NotEvaluated) Type() Type { 558 return NotEvaluatedType 559} 560 561func (n NotEvaluated) Eval() Expression { 562 return NotEvaluated{Position: n.Position} 563} 564 565func (n NotEvaluated) Pos() scanner.Position { return n.Position } 566func (n NotEvaluated) End() scanner.Position { return n.Position } 567 568func endPos(pos scanner.Position, n int) scanner.Position { 569 pos.Offset += n 570 pos.Column += n 571 return pos 572} 573 574type ConfigurableCondition struct { 575 position scanner.Position 576 FunctionName string 577 Args []String 578} 579 580func (c *ConfigurableCondition) Equals(other ConfigurableCondition) bool { 581 if c.FunctionName != other.FunctionName { 582 return false 583 } 584 if len(c.Args) != len(other.Args) { 585 return false 586 } 587 for i := range c.Args { 588 if c.Args[i] != other.Args[i] { 589 return false 590 } 591 } 592 return true 593} 594 595func (c *ConfigurableCondition) String() string { 596 var sb strings.Builder 597 sb.WriteString(c.FunctionName) 598 sb.WriteRune('(') 599 for i, arg := range c.Args { 600 sb.WriteRune('"') 601 sb.WriteString(arg.Value) 602 sb.WriteRune('"') 603 if i < len(c.Args)-1 { 604 sb.WriteString(", ") 605 } 606 } 607 sb.WriteRune(')') 608 return sb.String() 609} 610 611type Select struct { 612 KeywordPos scanner.Position // the keyword "select" 613 Conditions []ConfigurableCondition 614 LBracePos scanner.Position 615 RBracePos scanner.Position 616 Cases []*SelectCase // the case statements 617 Append Expression 618 ExpressionType Type 619} 620 621func (s *Select) Pos() scanner.Position { return s.KeywordPos } 622func (s *Select) End() scanner.Position { return endPos(s.RBracePos, 1) } 623 624func (s *Select) Copy() Expression { 625 ret := *s 626 ret.Cases = make([]*SelectCase, len(ret.Cases)) 627 for i, selectCase := range s.Cases { 628 ret.Cases[i] = selectCase.Copy() 629 } 630 if s.Append != nil { 631 ret.Append = s.Append.Copy() 632 } 633 return &ret 634} 635 636func (s *Select) Eval() Expression { 637 return s 638} 639 640func (s *Select) String() string { 641 return "<select>" 642} 643 644func (s *Select) Type() Type { 645 if s.ExpressionType == UnsetType && s.Append != nil { 646 return s.Append.Type() 647 } 648 return s.ExpressionType 649} 650 651type SelectCase struct { 652 Patterns []Expression 653 ColonPos scanner.Position 654 Value Expression 655} 656 657func (c *SelectCase) Copy() *SelectCase { 658 ret := *c 659 ret.Value = c.Value.Copy() 660 return &ret 661} 662 663func (c *SelectCase) String() string { 664 return "<select case>" 665} 666 667func (c *SelectCase) Pos() scanner.Position { return c.Patterns[0].Pos() } 668func (c *SelectCase) End() scanner.Position { return c.Value.End() } 669 670// UnsetProperty is the expression type of the "unset" keyword that can be 671// used in select statements to make the property unset. For example: 672// 673// my_module_type { 674// name: "foo", 675// some_prop: select(soong_config_variable("my_namespace", "my_var"), { 676// "foo": unset, 677// "default": "bar", 678// }) 679// } 680type UnsetProperty struct { 681 Position scanner.Position 682} 683 684func (n UnsetProperty) Copy() Expression { 685 return UnsetProperty{Position: n.Position} 686} 687 688func (n UnsetProperty) String() string { 689 return "unset" 690} 691 692func (n UnsetProperty) Type() Type { 693 return UnsetType 694} 695 696func (n UnsetProperty) Eval() Expression { 697 return UnsetProperty{Position: n.Position} 698} 699 700func (n UnsetProperty) Pos() scanner.Position { return n.Position } 701func (n UnsetProperty) End() scanner.Position { return n.Position } 702