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 "os" 20 "strings" 21 "text/scanner" 22) 23 24type Node interface { 25 // Pos returns the position of the first token in the Node 26 Pos() scanner.Position 27 // End returns the position of the character after the last token in the Node 28 End() scanner.Position 29} 30 31// Definition is an Assignment or a Module at the top level of a Blueprints file 32type Definition interface { 33 Node 34 String() string 35 definitionTag() 36} 37 38// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the 39// file and subdirs. 40type Assignment struct { 41 Name string 42 NamePos scanner.Position 43 Value 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 %t", a.Name, a.EqualsPos, a.Assigner, a.Value, 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 134func (p *Property) MarkReferencedVariables(scope *Scope) { 135 p.Value.MarkReferencedVariables(scope) 136} 137 138// An Expression is a Value in a Property or Assignment. It can be a literal (String or Bool), a 139// Map, a List, an Operator that combines two expressions of the same type, or a Variable that 140// references and Assignment. 141type Expression interface { 142 Node 143 // Copy returns a copy of the Expression that will not affect the original if mutated 144 Copy() Expression 145 String() string 146 // Type returns the underlying Type enum of the Expression if it were to be evaluated, if it's known. 147 // It's possible that the type isn't known, such as when a select statement with a late-bound variable 148 // is used. For that reason, Type() is mostly for use in error messages, not to make logic decisions 149 // off of. 150 Type() Type 151 // Eval returns an expression that is fully evaluated to a simple type (List, Map, String, 152 // Bool, or Select). It will return the origional expression if possible, or allocate a 153 // new one if modifications were necessary. 154 Eval(scope *Scope) (Expression, error) 155 // PrintfInto will substitute any %s's in string literals in the AST with the provided 156 // value. It will modify the AST in-place. This is used to implement soong config value 157 // variables, but should be removed when those have switched to selects. 158 PrintfInto(value string) error 159 // MarkReferencedVariables marks the variables in the given scope referenced if there 160 // is a matching variable reference in this expression. This happens naturally during 161 // Eval as well, but for selects, we need to mark variables as referenced without 162 // actually evaluating the expression yet. 163 MarkReferencedVariables(scope *Scope) 164} 165 166// ExpressionsAreSame tells whether the two values are the same Expression. 167// This includes the symbolic representation of each Expression but not their positions in the original source tree. 168// This does not apply any simplification to the expressions before comparing them 169// (for example, "!!a" wouldn't be deemed equal to "a") 170func ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) { 171 return hackyExpressionsAreSame(a, b) 172} 173 174// TODO(jeffrygaston) once positions are removed from Expression structs, 175// remove this function and have callers use reflect.DeepEqual(a, b) 176func hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) { 177 left, err := hackyFingerprint(a) 178 if err != nil { 179 return false, nil 180 } 181 right, err := hackyFingerprint(b) 182 if err != nil { 183 return false, nil 184 } 185 areEqual := string(left) == string(right) 186 return areEqual, nil 187} 188 189func hackyFingerprint(expression Expression) (fingerprint []byte, err error) { 190 assignment := &Assignment{"a", noPos, expression, noPos, "=", false} 191 module := &File{} 192 module.Defs = append(module.Defs, assignment) 193 p := newPrinter(module) 194 return p.Print() 195} 196 197type Type int 198 199const ( 200 UnknownType Type = iota 201 BoolType 202 StringType 203 Int64Type 204 ListType 205 MapType 206 UnsetType 207) 208 209func (t Type) String() string { 210 switch t { 211 case UnknownType: 212 return "unknown" 213 case BoolType: 214 return "bool" 215 case StringType: 216 return "string" 217 case Int64Type: 218 return "int64" 219 case ListType: 220 return "list" 221 case MapType: 222 return "map" 223 case UnsetType: 224 return "unset" 225 default: 226 panic(fmt.Sprintf("Unknown type %d", t)) 227 } 228} 229 230func ZeroExpression(t Type) Expression { 231 switch t { 232 case UnknownType: 233 panic(fmt.Errorf("cannot create zero expression for UnknownType")) 234 case BoolType: 235 return &Bool{} 236 case StringType: 237 return &String{} 238 case Int64Type: 239 return &Int64{} 240 case ListType: 241 return &List{} 242 case MapType: 243 return &Map{} 244 case UnsetType: 245 panic(fmt.Errorf("cannot create zero expression for UnsetType")) 246 247 default: 248 panic(fmt.Errorf("Unknown type %d", t)) 249 } 250} 251 252type Operator struct { 253 Args [2]Expression 254 Operator rune 255 OperatorPos scanner.Position 256} 257 258func (x *Operator) Copy() Expression { 259 ret := *x 260 ret.Args[0] = x.Args[0].Copy() 261 ret.Args[1] = x.Args[1].Copy() 262 return &ret 263} 264 265func (x *Operator) Type() Type { 266 t1 := x.Args[0].Type() 267 t2 := x.Args[1].Type() 268 if t1 == UnknownType { 269 return t2 270 } 271 if t2 == UnknownType { 272 return t1 273 } 274 if t1 != t2 { 275 return UnknownType 276 } 277 return t1 278} 279 280func (x *Operator) Eval(scope *Scope) (Expression, error) { 281 return evaluateOperator(scope, x.Operator, x.Args[0], x.Args[1]) 282} 283 284func evaluateOperator(scope *Scope, operator rune, left, right Expression) (Expression, error) { 285 if operator != '+' { 286 return nil, fmt.Errorf("unknown operator %c", operator) 287 } 288 l, err := left.Eval(scope) 289 if err != nil { 290 return nil, err 291 } 292 r, err := right.Eval(scope) 293 if err != nil { 294 return nil, err 295 } 296 297 if _, ok := l.(*Select); !ok { 298 if _, ok := r.(*Select); ok { 299 // Promote l to a select so we can add r to it 300 l = &Select{ 301 Cases: []*SelectCase{{ 302 Value: l, 303 }}, 304 } 305 } 306 } 307 308 l = l.Copy() 309 310 switch v := l.(type) { 311 case *String: 312 if _, ok := r.(*String); !ok { 313 fmt.Fprintf(os.Stderr, "not ok") 314 } 315 v.Value += r.(*String).Value 316 case *Int64: 317 v.Value += r.(*Int64).Value 318 v.Token = "" 319 case *List: 320 v.Values = append(v.Values, r.(*List).Values...) 321 case *Map: 322 var err error 323 v.Properties, err = addMaps(scope, v.Properties, r.(*Map).Properties) 324 if err != nil { 325 return nil, err 326 } 327 case *Select: 328 v.Append = r 329 default: 330 return nil, fmt.Errorf("operator %c not supported on %v", operator, v) 331 } 332 333 return l, nil 334} 335 336func addMaps(scope *Scope, map1, map2 []*Property) ([]*Property, error) { 337 ret := make([]*Property, 0, len(map1)) 338 339 inMap1 := make(map[string]*Property) 340 inMap2 := make(map[string]*Property) 341 inBoth := make(map[string]*Property) 342 343 for _, prop1 := range map1 { 344 inMap1[prop1.Name] = prop1 345 } 346 347 for _, prop2 := range map2 { 348 inMap2[prop2.Name] = prop2 349 if _, ok := inMap1[prop2.Name]; ok { 350 inBoth[prop2.Name] = prop2 351 } 352 } 353 354 for _, prop1 := range map1 { 355 if prop2, ok := inBoth[prop1.Name]; ok { 356 var err error 357 newProp := *prop1 358 newProp.Value, err = evaluateOperator(scope, '+', prop1.Value, prop2.Value) 359 if err != nil { 360 return nil, err 361 } 362 ret = append(ret, &newProp) 363 } else { 364 ret = append(ret, prop1) 365 } 366 } 367 368 for _, prop2 := range map2 { 369 if _, ok := inBoth[prop2.Name]; !ok { 370 ret = append(ret, prop2) 371 } 372 } 373 374 return ret, nil 375} 376 377func (x *Operator) PrintfInto(value string) error { 378 if err := x.Args[0].PrintfInto(value); err != nil { 379 return err 380 } 381 return x.Args[1].PrintfInto(value) 382} 383 384func (x *Operator) MarkReferencedVariables(scope *Scope) { 385 x.Args[0].MarkReferencedVariables(scope) 386 x.Args[1].MarkReferencedVariables(scope) 387} 388 389func (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() } 390func (x *Operator) End() scanner.Position { return x.Args[1].End() } 391 392func (x *Operator) String() string { 393 return fmt.Sprintf("(%s %c %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(), 394 x.OperatorPos) 395} 396 397type Variable struct { 398 Name string 399 NamePos scanner.Position 400 Type_ Type 401} 402 403func (x *Variable) Pos() scanner.Position { return x.NamePos } 404func (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) } 405 406func (x *Variable) Copy() Expression { 407 ret := *x 408 return &ret 409} 410 411func (x *Variable) Eval(scope *Scope) (Expression, error) { 412 if assignment := scope.Get(x.Name); assignment != nil { 413 assignment.Referenced = true 414 return assignment.Value, nil 415 } 416 return nil, fmt.Errorf("undefined variable %s", x.Name) 417} 418 419func (x *Variable) PrintfInto(value string) error { 420 return nil 421} 422 423func (x *Variable) MarkReferencedVariables(scope *Scope) { 424 if assignment := scope.Get(x.Name); assignment != nil { 425 assignment.Referenced = true 426 } 427} 428 429func (x *Variable) String() string { 430 return x.Name 431} 432 433func (x *Variable) Type() Type { 434 // Variables do not normally have a type associated with them, this is only 435 // filled out in the androidmk tool 436 return x.Type_ 437} 438 439type Map struct { 440 LBracePos scanner.Position 441 RBracePos scanner.Position 442 Properties []*Property 443} 444 445func (x *Map) Pos() scanner.Position { return x.LBracePos } 446func (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) } 447 448func (x *Map) Copy() Expression { 449 ret := *x 450 ret.Properties = make([]*Property, len(x.Properties)) 451 for i := range x.Properties { 452 ret.Properties[i] = x.Properties[i].Copy() 453 } 454 return &ret 455} 456 457func (x *Map) Eval(scope *Scope) (Expression, error) { 458 newProps := make([]*Property, len(x.Properties)) 459 for i, prop := range x.Properties { 460 newVal, err := prop.Value.Eval(scope) 461 if err != nil { 462 return nil, err 463 } 464 newProps[i] = &Property{ 465 Name: prop.Name, 466 NamePos: prop.NamePos, 467 ColonPos: prop.ColonPos, 468 Value: newVal, 469 } 470 } 471 return &Map{ 472 LBracePos: x.LBracePos, 473 RBracePos: x.RBracePos, 474 Properties: newProps, 475 }, nil 476} 477 478func (x *Map) PrintfInto(value string) error { 479 // We should never reach this because selects cannot hold maps 480 panic("printfinto() is unsupported on maps") 481} 482 483func (x *Map) MarkReferencedVariables(scope *Scope) { 484 for _, prop := range x.Properties { 485 prop.MarkReferencedVariables(scope) 486 } 487} 488 489func (x *Map) String() string { 490 propertyStrings := make([]string, len(x.Properties)) 491 for i, property := range x.Properties { 492 propertyStrings[i] = property.String() 493 } 494 return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos, 495 strings.Join(propertyStrings, ", ")) 496} 497 498func (x *Map) Type() Type { return MapType } 499 500// GetProperty looks for a property with the given name. 501// It resembles the bracket operator of a built-in Golang map. 502func (x *Map) GetProperty(name string) (Property *Property, found bool) { 503 prop, found, _ := x.getPropertyImpl(name) 504 return prop, found // we don't currently expose the index to callers 505} 506 507func (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) { 508 for i, prop := range x.Properties { 509 if prop.Name == name { 510 return prop, true, i 511 } 512 } 513 return nil, false, -1 514} 515 516// RemoveProperty removes the property with the given name, if it exists. 517func (x *Map) RemoveProperty(propertyName string) (removed bool) { 518 _, found, index := x.getPropertyImpl(propertyName) 519 if found { 520 x.Properties = append(x.Properties[:index], x.Properties[index+1:]...) 521 } 522 return found 523} 524 525// MovePropertyContents moves the contents of propertyName into property newLocation 526// If property newLocation doesn't exist, MovePropertyContents renames propertyName as newLocation. 527// Otherwise, MovePropertyContents only supports moving contents that are a List of String. 528func (x *Map) MovePropertyContents(propertyName string, newLocation string) (removed bool) { 529 oldProp, oldFound, _ := x.getPropertyImpl(propertyName) 530 newProp, newFound, _ := x.getPropertyImpl(newLocation) 531 532 // newLoc doesn't exist, simply renaming property 533 if oldFound && !newFound { 534 oldProp.Name = newLocation 535 return oldFound 536 } 537 538 if oldFound { 539 old, oldOk := oldProp.Value.(*List) 540 new, newOk := newProp.Value.(*List) 541 if oldOk && newOk { 542 toBeMoved := make([]string, len(old.Values)) // 543 for i, p := range old.Values { 544 toBeMoved[i] = p.(*String).Value 545 } 546 547 for _, moved := range toBeMoved { 548 RemoveStringFromList(old, moved) 549 AddStringToList(new, moved) 550 } 551 // oldProp should now be empty and needs to be deleted 552 x.RemoveProperty(oldProp.Name) 553 } else { 554 print(`MovePropertyContents currently only supports moving PropertyName 555 with List of Strings into an existing newLocation with List of Strings\n`) 556 } 557 } 558 return oldFound 559} 560 561type List struct { 562 LBracePos scanner.Position 563 RBracePos scanner.Position 564 Values []Expression 565} 566 567func (x *List) Pos() scanner.Position { return x.LBracePos } 568func (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) } 569 570func (x *List) Copy() Expression { 571 ret := *x 572 ret.Values = make([]Expression, len(x.Values)) 573 for i := range ret.Values { 574 ret.Values[i] = x.Values[i].Copy() 575 } 576 return &ret 577} 578 579func (x *List) Eval(scope *Scope) (Expression, error) { 580 newValues := make([]Expression, len(x.Values)) 581 for i, val := range x.Values { 582 newVal, err := val.Eval(scope) 583 if err != nil { 584 return nil, err 585 } 586 newValues[i] = newVal 587 } 588 return &List{ 589 LBracePos: x.LBracePos, 590 RBracePos: x.RBracePos, 591 Values: newValues, 592 }, nil 593} 594 595func (x *List) PrintfInto(value string) error { 596 for _, val := range x.Values { 597 if err := val.PrintfInto(value); err != nil { 598 return err 599 } 600 } 601 return nil 602} 603 604func (x *List) MarkReferencedVariables(scope *Scope) { 605 for _, val := range x.Values { 606 val.MarkReferencedVariables(scope) 607 } 608} 609 610func (x *List) String() string { 611 valueStrings := make([]string, len(x.Values)) 612 for i, value := range x.Values { 613 valueStrings[i] = value.String() 614 } 615 return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos, 616 strings.Join(valueStrings, ", ")) 617} 618 619func (x *List) Type() Type { return ListType } 620 621type String struct { 622 LiteralPos scanner.Position 623 Value string 624} 625 626func (x *String) Pos() scanner.Position { return x.LiteralPos } 627func (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) } 628 629func (x *String) Copy() Expression { 630 ret := *x 631 return &ret 632} 633 634func (x *String) Eval(scope *Scope) (Expression, error) { 635 return x, nil 636} 637 638func (x *String) PrintfInto(value string) error { 639 count := strings.Count(x.Value, "%") 640 if count == 0 { 641 return nil 642 } 643 644 if count > 1 { 645 return fmt.Errorf("list/value variable properties only support a single '%%'") 646 } 647 648 if !strings.Contains(x.Value, "%s") { 649 return fmt.Errorf("unsupported %% in value variable property") 650 } 651 652 x.Value = fmt.Sprintf(x.Value, value) 653 return nil 654} 655 656func (x *String) MarkReferencedVariables(scope *Scope) { 657} 658 659func (x *String) String() string { 660 return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) 661} 662 663func (x *String) Type() Type { 664 return StringType 665} 666 667type Int64 struct { 668 LiteralPos scanner.Position 669 Value int64 670 Token string 671} 672 673func (x *Int64) Pos() scanner.Position { return x.LiteralPos } 674func (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } 675 676func (x *Int64) Copy() Expression { 677 ret := *x 678 return &ret 679} 680 681func (x *Int64) Eval(scope *Scope) (Expression, error) { 682 return x, nil 683} 684 685func (x *Int64) PrintfInto(value string) error { 686 return nil 687} 688 689func (x *Int64) MarkReferencedVariables(scope *Scope) { 690} 691 692func (x *Int64) String() string { 693 return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos) 694} 695 696func (x *Int64) Type() Type { 697 return Int64Type 698} 699 700type Bool struct { 701 LiteralPos scanner.Position 702 Value bool 703 Token string 704} 705 706func (x *Bool) Pos() scanner.Position { return x.LiteralPos } 707func (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) } 708 709func (x *Bool) Copy() Expression { 710 ret := *x 711 return &ret 712} 713 714func (x *Bool) Eval(scope *Scope) (Expression, error) { 715 return x, nil 716} 717 718func (x *Bool) PrintfInto(value string) error { 719 return nil 720} 721 722func (x *Bool) MarkReferencedVariables(scope *Scope) { 723} 724 725func (x *Bool) String() string { 726 return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos) 727} 728 729func (x *Bool) Type() Type { 730 return BoolType 731} 732 733type CommentGroup struct { 734 Comments []*Comment 735} 736 737func (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() } 738func (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() } 739 740type Comment struct { 741 Comment []string 742 Slash scanner.Position 743} 744 745func (c Comment) Pos() scanner.Position { 746 return c.Slash 747} 748 749func (c Comment) End() scanner.Position { 750 pos := c.Slash 751 for _, comment := range c.Comment { 752 pos.Offset += len(comment) + 1 753 pos.Column = len(comment) + 1 754 } 755 pos.Line += len(c.Comment) - 1 756 return pos 757} 758 759func (c Comment) String() string { 760 l := 0 761 for _, comment := range c.Comment { 762 l += len(comment) + 1 763 } 764 buf := make([]byte, 0, l) 765 for _, comment := range c.Comment { 766 buf = append(buf, comment...) 767 buf = append(buf, '\n') 768 } 769 770 return string(buf) + "@" + c.Slash.String() 771} 772 773// Return the text of the comment with // or /* and */ stripped 774func (c Comment) Text() string { 775 l := 0 776 for _, comment := range c.Comment { 777 l += len(comment) + 1 778 } 779 buf := make([]byte, 0, l) 780 781 blockComment := false 782 if strings.HasPrefix(c.Comment[0], "/*") { 783 blockComment = true 784 } 785 786 for i, comment := range c.Comment { 787 if blockComment { 788 if i == 0 { 789 comment = strings.TrimPrefix(comment, "/*") 790 } 791 if i == len(c.Comment)-1 { 792 comment = strings.TrimSuffix(comment, "*/") 793 } 794 } else { 795 comment = strings.TrimPrefix(comment, "//") 796 } 797 buf = append(buf, comment...) 798 buf = append(buf, '\n') 799 } 800 801 return string(buf) 802} 803 804func endPos(pos scanner.Position, n int) scanner.Position { 805 pos.Offset += n 806 pos.Column += n 807 return pos 808} 809 810type ConfigurableCondition struct { 811 position scanner.Position 812 FunctionName string 813 Args []String 814} 815 816func (c *ConfigurableCondition) Equals(other ConfigurableCondition) bool { 817 if c.FunctionName != other.FunctionName { 818 return false 819 } 820 if len(c.Args) != len(other.Args) { 821 return false 822 } 823 for i := range c.Args { 824 if c.Args[i] != other.Args[i] { 825 return false 826 } 827 } 828 return true 829} 830 831func (c *ConfigurableCondition) String() string { 832 var sb strings.Builder 833 sb.WriteString(c.FunctionName) 834 sb.WriteRune('(') 835 for i, arg := range c.Args { 836 sb.WriteRune('"') 837 sb.WriteString(arg.Value) 838 sb.WriteRune('"') 839 if i < len(c.Args)-1 { 840 sb.WriteString(", ") 841 } 842 } 843 sb.WriteRune(')') 844 return sb.String() 845} 846 847type Select struct { 848 Scope *Scope // scope used to evaluate the body of the select later on 849 KeywordPos scanner.Position // the keyword "select" 850 Conditions []ConfigurableCondition 851 LBracePos scanner.Position 852 RBracePos scanner.Position 853 Cases []*SelectCase // the case statements 854 Append Expression 855} 856 857func (s *Select) Pos() scanner.Position { return s.KeywordPos } 858func (s *Select) End() scanner.Position { return endPos(s.RBracePos, 1) } 859 860func (s *Select) Copy() Expression { 861 ret := *s 862 ret.Cases = make([]*SelectCase, len(ret.Cases)) 863 for i, selectCase := range s.Cases { 864 ret.Cases[i] = selectCase.Copy() 865 } 866 if s.Append != nil { 867 ret.Append = s.Append.Copy() 868 } 869 return &ret 870} 871 872func (s *Select) Eval(scope *Scope) (Expression, error) { 873 s.Scope = scope 874 s.MarkReferencedVariables(scope) 875 return s, nil 876} 877 878func (x *Select) PrintfInto(value string) error { 879 // PrintfInto will be handled at the Configurable object level 880 panic("Cannot call PrintfInto on a select expression") 881} 882 883func (x *Select) MarkReferencedVariables(scope *Scope) { 884 for _, c := range x.Cases { 885 c.MarkReferencedVariables(scope) 886 } 887 if x.Append != nil { 888 x.Append.MarkReferencedVariables(scope) 889 } 890} 891 892func (s *Select) String() string { 893 return "<select>" 894} 895 896func (s *Select) Type() Type { 897 if len(s.Cases) == 0 { 898 return UnsetType 899 } 900 return UnknownType 901} 902 903type SelectPattern struct { 904 Value Expression 905 Binding Variable 906} 907 908func (c *SelectPattern) Pos() scanner.Position { return c.Value.Pos() } 909func (c *SelectPattern) End() scanner.Position { 910 if c.Binding.NamePos.IsValid() { 911 return c.Binding.End() 912 } 913 return c.Value.End() 914} 915 916type SelectCase struct { 917 Patterns []SelectPattern 918 ColonPos scanner.Position 919 Value Expression 920} 921 922func (x *SelectCase) MarkReferencedVariables(scope *Scope) { 923 x.Value.MarkReferencedVariables(scope) 924} 925 926func (c *SelectCase) Copy() *SelectCase { 927 ret := *c 928 ret.Value = c.Value.Copy() 929 return &ret 930} 931 932func (c *SelectCase) String() string { 933 return "<select case>" 934} 935 936func (c *SelectCase) Pos() scanner.Position { return c.Patterns[0].Pos() } 937func (c *SelectCase) End() scanner.Position { return c.Value.End() } 938 939// UnsetProperty is the expression type of the "unset" keyword that can be 940// used in select statements to make the property unset. For example: 941// 942// my_module_type { 943// name: "foo", 944// some_prop: select(soong_config_variable("my_namespace", "my_var"), { 945// "foo": unset, 946// "default": "bar", 947// }) 948// } 949type UnsetProperty struct { 950 Position scanner.Position 951} 952 953func (n *UnsetProperty) Copy() Expression { 954 return &UnsetProperty{Position: n.Position} 955} 956 957func (n *UnsetProperty) String() string { 958 return "unset" 959} 960 961func (n *UnsetProperty) Type() Type { 962 return UnsetType 963} 964 965func (n *UnsetProperty) Eval(scope *Scope) (Expression, error) { 966 return n, nil 967} 968 969func (x *UnsetProperty) PrintfInto(value string) error { 970 return nil 971} 972 973func (x *UnsetProperty) MarkReferencedVariables(scope *Scope) { 974} 975 976func (n *UnsetProperty) Pos() scanner.Position { return n.Position } 977func (n *UnsetProperty) End() scanner.Position { return n.Position } 978