1// Copyright 2023 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. 14package proptools 15 16import ( 17 "fmt" 18 "reflect" 19 "slices" 20 "strconv" 21 "strings" 22 23 "github.com/google/blueprint/optional" 24 "github.com/google/blueprint/parser" 25) 26 27// ConfigurableOptional is the same as ShallowOptional, but we use this separate 28// name to reserve the ability to switch to an alternative implementation later. 29type ConfigurableOptional[T any] struct { 30 shallowOptional optional.ShallowOptional[T] 31} 32 33// IsPresent returns true if the optional contains a value 34func (o *ConfigurableOptional[T]) IsPresent() bool { 35 return o.shallowOptional.IsPresent() 36} 37 38// IsEmpty returns true if the optional does not have a value 39func (o *ConfigurableOptional[T]) IsEmpty() bool { 40 return o.shallowOptional.IsEmpty() 41} 42 43// Get() returns the value inside the optional. It panics if IsEmpty() returns true 44func (o *ConfigurableOptional[T]) Get() T { 45 return o.shallowOptional.Get() 46} 47 48// GetOrDefault() returns the value inside the optional if IsPresent() returns true, 49// or the provided value otherwise. 50func (o *ConfigurableOptional[T]) GetOrDefault(other T) T { 51 return o.shallowOptional.GetOrDefault(other) 52} 53 54type ConfigurableElements interface { 55 string | bool | []string 56} 57 58type ConfigurableEvaluator interface { 59 EvaluateConfiguration(condition ConfigurableCondition, property string) ConfigurableValue 60 PropertyErrorf(property, fmt string, args ...interface{}) 61} 62 63// configurableMarker is just so that reflection can check type of the first field of 64// the struct to determine if it is a configurable struct. 65type configurableMarker bool 66 67var configurableMarkerType reflect.Type = reflect.TypeOf((*configurableMarker)(nil)).Elem() 68 69// ConfigurableCondition represents a condition that is being selected on, like 70// arch(), os(), soong_config_variable("namespace", "variable"), or other variables. 71// It's represented generically as a function name + arguments in blueprint, soong 72// interprets the function name and args into specific variable values. 73// 74// ConfigurableCondition is treated as an immutable object so that it may be shared 75// between different configurable properties. 76type ConfigurableCondition struct { 77 functionName string 78 args []string 79} 80 81func NewConfigurableCondition(functionName string, args []string) ConfigurableCondition { 82 return ConfigurableCondition{ 83 functionName: functionName, 84 args: slices.Clone(args), 85 } 86} 87 88func (c ConfigurableCondition) FunctionName() string { 89 return c.functionName 90} 91 92func (c ConfigurableCondition) NumArgs() int { 93 return len(c.args) 94} 95 96func (c ConfigurableCondition) Arg(i int) string { 97 return c.args[i] 98} 99 100func (c *ConfigurableCondition) String() string { 101 var sb strings.Builder 102 sb.WriteString(c.functionName) 103 sb.WriteRune('(') 104 for i, arg := range c.args { 105 sb.WriteString(strconv.Quote(arg)) 106 if i < len(c.args)-1 { 107 sb.WriteString(", ") 108 } 109 } 110 sb.WriteRune(')') 111 return sb.String() 112} 113 114func (c *ConfigurableCondition) toParserConfigurableCondition() parser.ConfigurableCondition { 115 var args []parser.String 116 for _, arg := range c.args { 117 args = append(args, parser.String{Value: arg}) 118 } 119 return parser.ConfigurableCondition{ 120 FunctionName: c.functionName, 121 Args: args, 122 } 123} 124 125type configurableValueType int 126 127const ( 128 configurableValueTypeString configurableValueType = iota 129 configurableValueTypeBool 130 configurableValueTypeUndefined 131 configurableValueTypeStringList 132) 133 134func (v *configurableValueType) patternType() configurablePatternType { 135 switch *v { 136 case configurableValueTypeString: 137 return configurablePatternTypeString 138 case configurableValueTypeBool: 139 return configurablePatternTypeBool 140 case configurableValueTypeStringList: 141 return configurablePatternTypeStringList 142 default: 143 panic("unimplemented") 144 } 145} 146 147func (v *configurableValueType) String() string { 148 switch *v { 149 case configurableValueTypeString: 150 return "string" 151 case configurableValueTypeBool: 152 return "bool" 153 case configurableValueTypeStringList: 154 return "string_list" 155 case configurableValueTypeUndefined: 156 return "undefined" 157 default: 158 panic("unimplemented") 159 } 160} 161 162// ConfigurableValue represents the value of a certain condition being selected on. 163// This type mostly exists to act as a sum type between string, bool, and undefined. 164type ConfigurableValue struct { 165 typ configurableValueType 166 stringValue string 167 boolValue bool 168 stringListValue []string 169} 170 171func (c *ConfigurableValue) toExpression() parser.Expression { 172 switch c.typ { 173 case configurableValueTypeBool: 174 return &parser.Bool{Value: c.boolValue} 175 case configurableValueTypeString: 176 return &parser.String{Value: c.stringValue} 177 case configurableValueTypeStringList: 178 result := &parser.List{} 179 for _, s := range c.stringListValue { 180 result.Values = append(result.Values, &parser.String{Value: s}) 181 } 182 return result 183 default: 184 panic(fmt.Sprintf("Unhandled configurableValueType: %s", c.typ.String())) 185 } 186} 187 188func (c *ConfigurableValue) String() string { 189 switch c.typ { 190 case configurableValueTypeString: 191 return strconv.Quote(c.stringValue) 192 case configurableValueTypeBool: 193 if c.boolValue { 194 return "true" 195 } else { 196 return "false" 197 } 198 case configurableValueTypeUndefined: 199 return "undefined" 200 default: 201 panic("unimplemented") 202 } 203} 204 205func ConfigurableValueString(s string) ConfigurableValue { 206 return ConfigurableValue{ 207 typ: configurableValueTypeString, 208 stringValue: s, 209 } 210} 211 212func ConfigurableValueBool(b bool) ConfigurableValue { 213 return ConfigurableValue{ 214 typ: configurableValueTypeBool, 215 boolValue: b, 216 } 217} 218 219func ConfigurableValueStringList(l []string) ConfigurableValue { 220 return ConfigurableValue{ 221 typ: configurableValueTypeStringList, 222 stringListValue: slices.Clone(l), 223 } 224} 225 226func ConfigurableValueUndefined() ConfigurableValue { 227 return ConfigurableValue{ 228 typ: configurableValueTypeUndefined, 229 } 230} 231 232type configurablePatternType int 233 234const ( 235 configurablePatternTypeString configurablePatternType = iota 236 configurablePatternTypeBool 237 configurablePatternTypeStringList 238 configurablePatternTypeDefault 239 configurablePatternTypeAny 240) 241 242func (v *configurablePatternType) String() string { 243 switch *v { 244 case configurablePatternTypeString: 245 return "string" 246 case configurablePatternTypeBool: 247 return "bool" 248 case configurablePatternTypeStringList: 249 return "string_list" 250 case configurablePatternTypeDefault: 251 return "default" 252 case configurablePatternTypeAny: 253 return "any" 254 default: 255 panic("unimplemented") 256 } 257} 258 259// ConfigurablePattern represents a concrete value for a ConfigurableCase. 260// Currently this just means the value of whatever variable is being looked 261// up with the ConfigurableCase, but in the future it may be expanded to 262// match multiple values (e.g. ranges of integers like 3..7). 263// 264// ConfigurablePattern can represent different types of values, like 265// strings vs bools. 266// 267// ConfigurablePattern must be immutable so it can be shared between 268// different configurable properties. 269type ConfigurablePattern struct { 270 typ configurablePatternType 271 stringValue string 272 boolValue bool 273 binding string 274} 275 276func (c ConfigurablePattern) toParserSelectPattern() parser.SelectPattern { 277 switch c.typ { 278 case configurablePatternTypeString: 279 return parser.SelectPattern{ 280 Value: &parser.String{Value: c.stringValue}, 281 Binding: parser.Variable{Name: c.binding}, 282 } 283 case configurablePatternTypeBool: 284 return parser.SelectPattern{ 285 Value: &parser.Bool{Value: c.boolValue}, 286 Binding: parser.Variable{Name: c.binding}, 287 } 288 case configurablePatternTypeDefault: 289 return parser.SelectPattern{ 290 Value: &parser.String{Value: "__soong_conditions_default__"}, 291 Binding: parser.Variable{Name: c.binding}, 292 } 293 case configurablePatternTypeAny: 294 return parser.SelectPattern{ 295 Value: &parser.String{Value: "__soong_conditions_any__"}, 296 Binding: parser.Variable{Name: c.binding}, 297 } 298 default: 299 panic(fmt.Sprintf("unknown type %d", c.typ)) 300 } 301} 302 303func NewStringConfigurablePattern(s string) ConfigurablePattern { 304 return ConfigurablePattern{ 305 typ: configurablePatternTypeString, 306 stringValue: s, 307 } 308} 309 310func NewBoolConfigurablePattern(b bool) ConfigurablePattern { 311 return ConfigurablePattern{ 312 typ: configurablePatternTypeBool, 313 boolValue: b, 314 } 315} 316 317func NewDefaultConfigurablePattern() ConfigurablePattern { 318 return ConfigurablePattern{ 319 typ: configurablePatternTypeDefault, 320 } 321} 322 323func (p *ConfigurablePattern) matchesValue(v ConfigurableValue) bool { 324 if p.typ == configurablePatternTypeDefault { 325 return true 326 } 327 if v.typ == configurableValueTypeUndefined { 328 return false 329 } 330 if p.typ == configurablePatternTypeAny { 331 return true 332 } 333 if p.typ != v.typ.patternType() { 334 return false 335 } 336 switch p.typ { 337 case configurablePatternTypeString: 338 return p.stringValue == v.stringValue 339 case configurablePatternTypeBool: 340 return p.boolValue == v.boolValue 341 default: 342 panic("unimplemented") 343 } 344} 345 346func (p *ConfigurablePattern) matchesValueType(v ConfigurableValue) bool { 347 if p.typ == configurablePatternTypeDefault { 348 return true 349 } 350 if v.typ == configurableValueTypeUndefined { 351 return true 352 } 353 if p.typ == configurablePatternTypeAny { 354 return true 355 } 356 return p.typ == v.typ.patternType() 357} 358 359// ConfigurableCase represents a set of ConfigurablePatterns 360// (exactly 1 pattern per ConfigurableCase), and a value to use 361// if all of the patterns are matched. 362// 363// ConfigurableCase must be immutable so it can be shared between 364// different configurable properties. 365type ConfigurableCase[T ConfigurableElements] struct { 366 patterns []ConfigurablePattern 367 value parser.Expression 368} 369 370func (c *ConfigurableCase[T]) toParserConfigurableCase() *parser.SelectCase { 371 var patterns []parser.SelectPattern 372 for _, p := range c.patterns { 373 patterns = append(patterns, p.toParserSelectPattern()) 374 } 375 return &parser.SelectCase{ 376 Patterns: patterns, 377 Value: c.value, 378 } 379} 380 381type configurableCaseReflection interface { 382 initialize(patterns []ConfigurablePattern, value parser.Expression) 383} 384 385var _ configurableCaseReflection = &ConfigurableCase[string]{} 386 387func NewConfigurableCase[T ConfigurableElements](patterns []ConfigurablePattern, value *T) ConfigurableCase[T] { 388 var valueExpr parser.Expression 389 if value == nil { 390 valueExpr = &parser.UnsetProperty{} 391 } else { 392 switch v := any(value).(type) { 393 case *string: 394 valueExpr = &parser.String{Value: *v} 395 case *bool: 396 valueExpr = &parser.Bool{Value: *v} 397 case *[]string: 398 innerValues := make([]parser.Expression, 0, len(*v)) 399 for _, x := range *v { 400 innerValues = append(innerValues, &parser.String{Value: x}) 401 } 402 valueExpr = &parser.List{Values: innerValues} 403 default: 404 panic(fmt.Sprintf("should be unreachable due to the ConfigurableElements restriction: %#v", value)) 405 } 406 } 407 // Clone the values so they can't be modified from soong 408 patterns = slices.Clone(patterns) 409 return ConfigurableCase[T]{ 410 patterns: patterns, 411 value: valueExpr, 412 } 413} 414 415func (c *ConfigurableCase[T]) initialize(patterns []ConfigurablePattern, value parser.Expression) { 416 c.patterns = patterns 417 c.value = value 418} 419 420// for the given T, return the reflect.type of configurableCase[T] 421func configurableCaseType(configuredType reflect.Type) reflect.Type { 422 // I don't think it's possible to do this generically with go's 423 // current reflection apis unfortunately 424 switch configuredType.Kind() { 425 case reflect.String: 426 return reflect.TypeOf(ConfigurableCase[string]{}) 427 case reflect.Bool: 428 return reflect.TypeOf(ConfigurableCase[bool]{}) 429 case reflect.Slice: 430 switch configuredType.Elem().Kind() { 431 case reflect.String: 432 return reflect.TypeOf(ConfigurableCase[[]string]{}) 433 } 434 } 435 panic("unimplemented") 436} 437 438// for the given T, return the reflect.type of Configurable[T] 439func configurableType(configuredType reflect.Type) (reflect.Type, error) { 440 // I don't think it's possible to do this generically with go's 441 // current reflection apis unfortunately 442 switch configuredType.Kind() { 443 case reflect.String: 444 return reflect.TypeOf(Configurable[string]{}), nil 445 case reflect.Bool: 446 return reflect.TypeOf(Configurable[bool]{}), nil 447 case reflect.Slice: 448 switch configuredType.Elem().Kind() { 449 case reflect.String: 450 return reflect.TypeOf(Configurable[[]string]{}), nil 451 } 452 } 453 return nil, fmt.Errorf("configurable structs can only contain strings, bools, or string slices, found %s", configuredType.String()) 454} 455 456// Configurable can wrap the type of a blueprint property, 457// in order to allow select statements to be used in bp files 458// for that property. For example, for the property struct: 459// 460// my_props { 461// Property_a: string, 462// Property_b: Configurable[string], 463// } 464// 465// property_b can then use select statements: 466// 467// my_module { 468// property_a: "foo" 469// property_b: select(soong_config_variable("my_namespace", "my_variable"), { 470// "value_1": "bar", 471// "value_2": "baz", 472// default: "qux", 473// }) 474// } 475// 476// The configurable property holds all the branches of the select 477// statement in the bp file. To extract the final value, you must 478// call Evaluate() on the configurable property. 479// 480// All configurable properties support being unset, so there is 481// no need to use a pointer type like Configurable[*string]. 482type Configurable[T ConfigurableElements] struct { 483 marker configurableMarker 484 propertyName string 485 inner *configurableInner[T] 486 // See Configurable.evaluate for a description of the postProcessor algorithm and 487 // why this is a 2d list 488 postProcessors *[][]postProcessor[T] 489} 490 491type postProcessor[T ConfigurableElements] struct { 492 f func(T) T 493 // start and end represent the range of configurableInners 494 // that this postprocessor is applied to. When appending two configurables 495 // together, the start and end values will stay the same for the left 496 // configurable's postprocessors, but the rights will be rebased by the 497 // number of configurableInners in the left configurable. This way 498 // the postProcessors still only apply to the configurableInners they 499 // origionally applied to before the appending. 500 start int 501 end int 502} 503 504type configurableInner[T ConfigurableElements] struct { 505 single singleConfigurable[T] 506 replace bool 507 next *configurableInner[T] 508} 509 510// singleConfigurable must be immutable so it can be reused 511// between multiple configurables 512type singleConfigurable[T ConfigurableElements] struct { 513 conditions []ConfigurableCondition 514 cases []ConfigurableCase[T] 515 scope *parser.Scope 516} 517 518// Ignore the warning about the unused marker variable, it's used via reflection 519var _ configurableMarker = Configurable[string]{}.marker 520 521func NewConfigurable[T ConfigurableElements](conditions []ConfigurableCondition, cases []ConfigurableCase[T]) Configurable[T] { 522 for _, c := range cases { 523 if len(c.patterns) != len(conditions) { 524 panic(fmt.Sprintf("All configurables cases must have as many patterns as the configurable has conditions. Expected: %d, found: %d", len(conditions), len(c.patterns))) 525 } 526 } 527 // Clone the slices so they can't be modified from soong 528 conditions = slices.Clone(conditions) 529 cases = slices.Clone(cases) 530 var zeroPostProcessors [][]postProcessor[T] 531 return Configurable[T]{ 532 inner: &configurableInner[T]{ 533 single: singleConfigurable[T]{ 534 conditions: conditions, 535 cases: cases, 536 }, 537 }, 538 postProcessors: &zeroPostProcessors, 539 } 540} 541 542func NewSimpleConfigurable[T ConfigurableElements](value T) Configurable[T] { 543 return NewConfigurable(nil, []ConfigurableCase[T]{ 544 NewConfigurableCase(nil, &value), 545 }) 546} 547 548func newConfigurableWithPropertyName[T ConfigurableElements](propertyName string, conditions []ConfigurableCondition, cases []ConfigurableCase[T], addScope bool) Configurable[T] { 549 result := NewConfigurable(conditions, cases) 550 result.propertyName = propertyName 551 if addScope { 552 for curr := result.inner; curr != nil; curr = curr.next { 553 curr.single.scope = parser.NewScope(nil) 554 } 555 } 556 return result 557} 558 559func (c *Configurable[T]) AppendSimpleValue(value T) { 560 value = copyConfiguredValue(value) 561 // This may be a property that was never initialized from a bp file 562 if c.inner == nil { 563 c.initialize(nil, "", nil, []ConfigurableCase[T]{{ 564 value: configuredValueToExpression(value), 565 }}) 566 return 567 } 568 c.inner.appendSimpleValue(value) 569} 570 571// AddPostProcessor adds a function that will modify the result of 572// Get() when Get() is called. It operates on all the current contents 573// of the Configurable property, but if other values are appended to 574// the Configurable property afterwards, the postProcessor will not run 575// on them. This can be useful to essentially modify a configurable 576// property without evaluating it. 577func (c *Configurable[T]) AddPostProcessor(p func(T) T) { 578 // Add the new postProcessor on top of the tallest stack of postProcessors. 579 // See Configurable.evaluate for more details on the postProcessors algorithm 580 // and data structure. 581 num_links := c.inner.numLinks() 582 if c.postProcessors == nil { 583 var nilCases []ConfigurableCase[T] 584 c.initialize(nil, "", nil, nilCases) 585 } 586 if len(*c.postProcessors) == 0 { 587 *c.postProcessors = [][]postProcessor[T]{{{ 588 f: p, 589 start: 0, 590 end: num_links, 591 }}} 592 } else { 593 deepestI := 0 594 deepestDepth := 0 595 for i := 0; i < len(*c.postProcessors); i++ { 596 if len((*c.postProcessors)[i]) > deepestDepth { 597 deepestDepth = len((*c.postProcessors)[i]) 598 deepestI = i 599 } 600 } 601 (*c.postProcessors)[deepestI] = append((*c.postProcessors)[deepestI], postProcessor[T]{ 602 f: p, 603 start: 0, 604 end: num_links, 605 }) 606 } 607} 608 609// Get returns the final value for the configurable property. 610// A configurable property may be unset, in which case Get will return nil. 611func (c *Configurable[T]) Get(evaluator ConfigurableEvaluator) ConfigurableOptional[T] { 612 result := c.evaluate(c.propertyName, evaluator) 613 return configuredValuePtrToOptional(result) 614} 615 616// GetOrDefault is the same as Get, but will return the provided default value if the property was unset. 617func (c *Configurable[T]) GetOrDefault(evaluator ConfigurableEvaluator, defaultValue T) T { 618 result := c.evaluate(c.propertyName, evaluator) 619 if result != nil { 620 // Copy the result so that it can't be changed from soong 621 return copyConfiguredValue(*result) 622 } 623 return defaultValue 624} 625 626type valueAndIndices[T ConfigurableElements] struct { 627 value *T 628 replace bool 629 // Similar to start/end in postProcessor, these represent the origional 630 // range or configurableInners that this merged group represents. It's needed 631 // in order to apply recursive postProcessors to only the relevant 632 // configurableInners, even after those configurableInners have been merged 633 // in order to apply an earlier postProcessor. 634 start int 635 end int 636} 637 638func (c *Configurable[T]) evaluate(propertyName string, evaluator ConfigurableEvaluator) *T { 639 if c.inner == nil { 640 return nil 641 } 642 643 if len(*c.postProcessors) == 0 { 644 // Use a simpler algorithm if there are no postprocessors 645 return c.inner.evaluate(propertyName, evaluator) 646 } 647 648 // The basic idea around evaluating with postprocessors is that each individual 649 // node in the chain (each configurableInner) is first evaluated, and then when 650 // a postprocessor operates on a certain range, that range is merged before passing 651 // it to the postprocessor. We want postProcessors to only accept a final merged 652 // value instead of a linked list, but at the same time, only operate over a portion 653 // of the list. If more configurables are appended onto this one, their values won't 654 // be operated on by the existing postProcessors, but they may have their own 655 // postprocessors. 656 // 657 // _____________________ 658 // | __________| 659 // ______ | _____| ___ 660 // | | | | | | 661 // a -> b -> c -> d -> e -> f -> g 662 // 663 // In this diagram, the letters along the bottom is the chain of configurableInners. 664 // The brackets on top represent postprocessors, where higher brackets are processed 665 // after lower ones. 666 // 667 // To evaluate this example, first we evaluate the raw values for all nodes a->g. 668 // Then we merge nodes a/b and d/e and apply the postprocessors to their merged values, 669 // and also to g. Those merged and postprocessed nodes are then reinserted into the 670 // list, and we move on to doing the higher level postprocessors (starting with the c->e one) 671 // in the same way. When all postprocessors are done, a final merge is done on anything 672 // leftover. 673 // 674 // The Configurable.postProcessors field is a 2d array to represent this hierarchy. 675 // The outer index moves right on this graph, the inner index goes up. 676 // When adding a new postProcessor, it will always be the last postProcessor to run 677 // until another is added or another configurable is appended. So in AddPostProcessor(), 678 // we add it to the tallest existing stack. 679 680 var currentValues []valueAndIndices[T] 681 for curr, i := c.inner, 0; curr != nil; curr, i = curr.next, i+1 { 682 value := curr.single.evaluateNonTransitive(propertyName, evaluator) 683 currentValues = append(currentValues, valueAndIndices[T]{ 684 value: value, 685 replace: curr.replace, 686 start: i, 687 end: i + 1, 688 }) 689 } 690 691 if c.postProcessors == nil || len(*c.postProcessors) == 0 { 692 return mergeValues(currentValues).value 693 } 694 695 foundPostProcessor := true 696 for depth := 0; foundPostProcessor; depth++ { 697 foundPostProcessor = false 698 var newValues []valueAndIndices[T] 699 i := 0 700 for _, postProcessorGroup := range *c.postProcessors { 701 if len(postProcessorGroup) > depth { 702 foundPostProcessor = true 703 postProcessor := postProcessorGroup[depth] 704 startI := 0 705 endI := 0 706 for currentValues[startI].start < postProcessor.start { 707 startI++ 708 } 709 for currentValues[endI].end < postProcessor.end { 710 endI++ 711 } 712 endI++ 713 newValues = append(newValues, currentValues[i:startI]...) 714 merged := mergeValues(currentValues[startI:endI]) 715 if merged.value != nil { 716 processed := postProcessor.f(*merged.value) 717 merged.value = &processed 718 } 719 newValues = append(newValues, merged) 720 i = endI 721 } 722 } 723 newValues = append(newValues, currentValues[i:]...) 724 currentValues = newValues 725 } 726 727 return mergeValues(currentValues).value 728} 729 730func mergeValues[T ConfigurableElements](values []valueAndIndices[T]) valueAndIndices[T] { 731 if len(values) < 0 { 732 panic("Expected at least 1 value in mergeValues") 733 } 734 result := values[0] 735 for i := 1; i < len(values); i++ { 736 if result.replace { 737 result.value = replaceConfiguredValues(result.value, values[i].value) 738 } else { 739 result.value = appendConfiguredValues(result.value, values[i].value) 740 } 741 result.end = values[i].end 742 result.replace = values[i].replace 743 } 744 return result 745} 746 747func (c *configurableInner[T]) evaluate(propertyName string, evaluator ConfigurableEvaluator) *T { 748 if c == nil { 749 return nil 750 } 751 if c.next == nil { 752 return c.single.evaluateNonTransitive(propertyName, evaluator) 753 } 754 if c.replace { 755 return replaceConfiguredValues( 756 c.single.evaluateNonTransitive(propertyName, evaluator), 757 c.next.evaluate(propertyName, evaluator), 758 ) 759 } else { 760 return appendConfiguredValues( 761 c.single.evaluateNonTransitive(propertyName, evaluator), 762 c.next.evaluate(propertyName, evaluator), 763 ) 764 } 765} 766 767func (c *singleConfigurable[T]) evaluateNonTransitive(propertyName string, evaluator ConfigurableEvaluator) *T { 768 for i, case_ := range c.cases { 769 if len(c.conditions) != len(case_.patterns) { 770 evaluator.PropertyErrorf(propertyName, "Expected each case to have as many patterns as conditions. conditions: %d, len(cases[%d].patterns): %d", len(c.conditions), i, len(case_.patterns)) 771 return nil 772 } 773 } 774 if len(c.conditions) == 0 { 775 if len(c.cases) == 0 { 776 return nil 777 } else if len(c.cases) == 1 { 778 if result, err := expressionToConfiguredValue[T](c.cases[0].value, c.scope); err != nil { 779 evaluator.PropertyErrorf(propertyName, "%s", err.Error()) 780 return nil 781 } else { 782 return result 783 } 784 } else { 785 evaluator.PropertyErrorf(propertyName, "Expected 0 or 1 branches in an unconfigured select, found %d", len(c.cases)) 786 return nil 787 } 788 } 789 values := make([]ConfigurableValue, len(c.conditions)) 790 for i, condition := range c.conditions { 791 values[i] = evaluator.EvaluateConfiguration(condition, propertyName) 792 } 793 foundMatch := false 794 nonMatchingIndex := 0 795 var result *T 796 for _, case_ := range c.cases { 797 allMatch := true 798 for i, pat := range case_.patterns { 799 if !pat.matchesValueType(values[i]) { 800 evaluator.PropertyErrorf(propertyName, "Expected all branches of a select on condition %s to have type %s, found %s", c.conditions[i].String(), values[i].typ.String(), pat.typ.String()) 801 return nil 802 } 803 if !pat.matchesValue(values[i]) { 804 allMatch = false 805 nonMatchingIndex = i 806 break 807 } 808 } 809 if allMatch && !foundMatch { 810 newScope := createScopeWithBindings(c.scope, case_.patterns, values) 811 if r, err := expressionToConfiguredValue[T](case_.value, newScope); err != nil { 812 evaluator.PropertyErrorf(propertyName, "%s", err.Error()) 813 return nil 814 } else { 815 result = r 816 } 817 foundMatch = true 818 } 819 } 820 if foundMatch { 821 return result 822 } 823 824 evaluator.PropertyErrorf(propertyName, "%s had value %s, which was not handled by the select statement", c.conditions[nonMatchingIndex].String(), values[nonMatchingIndex].String()) 825 return nil 826} 827 828func createScopeWithBindings(parent *parser.Scope, patterns []ConfigurablePattern, values []ConfigurableValue) *parser.Scope { 829 result := parent 830 for i, pattern := range patterns { 831 if pattern.binding != "" { 832 if result == parent { 833 result = parser.NewScope(parent) 834 } 835 err := result.HandleAssignment(&parser.Assignment{ 836 Name: pattern.binding, 837 Value: values[i].toExpression(), 838 Assigner: "=", 839 }) 840 if err != nil { 841 // This shouldn't happen due to earlier validity checks 842 panic(err.Error()) 843 } 844 } 845 } 846 return result 847} 848 849func appendConfiguredValues[T ConfigurableElements](a, b *T) *T { 850 if a == nil && b == nil { 851 return nil 852 } 853 switch any(a).(type) { 854 case *[]string: 855 var a2 []string 856 var b2 []string 857 if a != nil { 858 a2 = *any(a).(*[]string) 859 } 860 if b != nil { 861 b2 = *any(b).(*[]string) 862 } 863 result := make([]string, len(a2)+len(b2)) 864 idx := 0 865 for i := 0; i < len(a2); i++ { 866 result[idx] = a2[i] 867 idx += 1 868 } 869 for i := 0; i < len(b2); i++ { 870 result[idx] = b2[i] 871 idx += 1 872 } 873 return any(&result).(*T) 874 case *string: 875 a := String(any(a).(*string)) 876 b := String(any(b).(*string)) 877 result := a + b 878 return any(&result).(*T) 879 case *bool: 880 // Addition of bools will OR them together. This is inherited behavior 881 // from how proptools.ExtendBasicType works with non-configurable bools. 882 result := false 883 if a != nil { 884 result = result || *any(a).(*bool) 885 } 886 if b != nil { 887 result = result || *any(b).(*bool) 888 } 889 return any(&result).(*T) 890 default: 891 panic("Should be unreachable") 892 } 893} 894 895func replaceConfiguredValues[T ConfigurableElements](a, b *T) *T { 896 if b != nil { 897 return b 898 } 899 return a 900} 901 902// configurableReflection is an interface that exposes some methods that are 903// helpful when working with reflect.Values of Configurable objects, used by 904// the property unpacking code. You can't call unexported methods from reflection, 905// (at least without unsafe pointer trickery) so this is the next best thing. 906type configurableReflection interface { 907 setAppend(append any, replace bool, prepend bool) 908 configuredType() reflect.Type 909 clone() any 910 isEmpty() bool 911 printfInto(value string) error 912 toExpression() (*parser.Expression, error) 913} 914 915// Same as configurableReflection, but since initialize needs to take a pointer 916// to a Configurable, it was broken out into a separate interface. 917type configurablePtrReflection interface { 918 initialize(scope *parser.Scope, propertyName string, conditions []ConfigurableCondition, cases any) 919} 920 921var _ configurableReflection = Configurable[string]{} 922var _ configurablePtrReflection = &Configurable[string]{} 923 924func (c *Configurable[T]) initialize(scope *parser.Scope, propertyName string, conditions []ConfigurableCondition, cases any) { 925 c.propertyName = propertyName 926 c.inner = &configurableInner[T]{ 927 single: singleConfigurable[T]{ 928 conditions: conditions, 929 cases: cases.([]ConfigurableCase[T]), 930 scope: scope, 931 }, 932 } 933 var postProcessors [][]postProcessor[T] 934 c.postProcessors = &postProcessors 935} 936 937func (c *Configurable[T]) Append(other Configurable[T]) { 938 c.setAppend(other, false, false) 939} 940 941func (c Configurable[T]) setAppend(append any, replace bool, prepend bool) { 942 a := append.(Configurable[T]) 943 if a.inner.isEmpty() { 944 return 945 } 946 947 if prepend { 948 newBase := a.inner.numLinks() 949 *c.postProcessors = appendPostprocessors(*a.postProcessors, *c.postProcessors, newBase) 950 } else { 951 newBase := c.inner.numLinks() 952 *c.postProcessors = appendPostprocessors(*c.postProcessors, *a.postProcessors, newBase) 953 } 954 955 c.inner.setAppend(a.inner, replace, prepend) 956 if c.inner == c.inner.next { 957 panic("pointer loop") 958 } 959} 960 961func (c Configurable[T]) toExpression() (*parser.Expression, error) { 962 var err error 963 var result *parser.Select 964 var tail *parser.Select 965 for curr := c.inner; curr != nil; curr = curr.next { 966 if curr.replace == true { 967 return nil, fmt.Errorf("Cannot turn a configurable property with replacements into an expression; " + 968 "replacements can only be created via soong code / defaults squashing, not simply in a bp file") 969 } 970 if curr.single.isEmpty() { 971 continue 972 } 973 if result == nil { 974 result, err = curr.single.toExpression() 975 if err != nil { 976 return nil, err 977 } 978 tail = result 979 } else { 980 tail.Append, err = curr.single.toExpression() 981 if err != nil { 982 return nil, err 983 } 984 tail = tail.Append.(*parser.Select) 985 } 986 } 987 if result == nil { 988 return nil, nil 989 } 990 var result2 parser.Expression = result 991 return &result2, nil 992} 993 994func appendPostprocessors[T ConfigurableElements](a, b [][]postProcessor[T], newBase int) [][]postProcessor[T] { 995 var result [][]postProcessor[T] 996 for i := 0; i < len(a); i++ { 997 result = append(result, slices.Clone(a[i])) 998 } 999 for i := 0; i < len(b); i++ { 1000 n := slices.Clone(b[i]) 1001 for j := 0; j < len(n); j++ { 1002 n[j].start += newBase 1003 n[j].end += newBase 1004 } 1005 result = append(result, n) 1006 } 1007 return result 1008} 1009 1010func (c *configurableInner[T]) setAppend(append *configurableInner[T], replace bool, prepend bool) { 1011 if c.isEmpty() { 1012 *c = *append.clone() 1013 } else if prepend { 1014 if replace && c.alwaysHasValue() { 1015 // The current value would always override the prepended value, so don't do anything 1016 return 1017 } 1018 // We're going to replace the head node with the one from append, so allocate 1019 // a new one here. 1020 old := &configurableInner[T]{ 1021 single: c.single, 1022 replace: c.replace, 1023 next: c.next, 1024 } 1025 *c = *append.clone() 1026 curr := c 1027 for curr.next != nil { 1028 curr = curr.next 1029 } 1030 curr.next = old 1031 curr.replace = replace 1032 } else { 1033 // If we're replacing with something that always has a value set, 1034 // we can optimize the code by replacing our entire append chain here. 1035 if replace && append.alwaysHasValue() { 1036 *c = *append.clone() 1037 } else { 1038 curr := c 1039 for curr.next != nil { 1040 curr = curr.next 1041 } 1042 curr.next = append.clone() 1043 curr.replace = replace 1044 } 1045 } 1046} 1047 1048func (c *configurableInner[T]) numLinks() int { 1049 result := 0 1050 for curr := c; curr != nil; curr = curr.next { 1051 result++ 1052 } 1053 return result 1054} 1055 1056func (c *configurableInner[T]) appendSimpleValue(value T) { 1057 if c.next == nil { 1058 c.replace = false 1059 c.next = &configurableInner[T]{ 1060 single: singleConfigurable[T]{ 1061 cases: []ConfigurableCase[T]{{ 1062 value: configuredValueToExpression(value), 1063 }}, 1064 }, 1065 } 1066 } else { 1067 c.next.appendSimpleValue(value) 1068 } 1069} 1070 1071func (c Configurable[T]) printfInto(value string) error { 1072 return c.inner.printfInto(value) 1073} 1074 1075func (c *configurableInner[T]) printfInto(value string) error { 1076 for c != nil { 1077 if err := c.single.printfInto(value); err != nil { 1078 return err 1079 } 1080 c = c.next 1081 } 1082 return nil 1083} 1084 1085func (c *singleConfigurable[T]) printfInto(value string) error { 1086 for _, c := range c.cases { 1087 if c.value == nil { 1088 continue 1089 } 1090 if err := c.value.PrintfInto(value); err != nil { 1091 return err 1092 } 1093 } 1094 return nil 1095} 1096 1097func (c *singleConfigurable[T]) toExpression() (*parser.Select, error) { 1098 if c.scope != nil { 1099 return nil, fmt.Errorf("Cannot turn a select with a scope back into an expression") 1100 } 1101 var conditions []parser.ConfigurableCondition 1102 for _, cond := range c.conditions { 1103 conditions = append(conditions, cond.toParserConfigurableCondition()) 1104 } 1105 var cases []*parser.SelectCase 1106 for _, case_ := range c.cases { 1107 cases = append(cases, case_.toParserConfigurableCase()) 1108 } 1109 result := &parser.Select{ 1110 Conditions: conditions, 1111 Cases: cases, 1112 } 1113 return result, nil 1114} 1115 1116func (c Configurable[T]) clone() any { 1117 var newPostProcessors *[][]postProcessor[T] 1118 if c.postProcessors != nil { 1119 x := appendPostprocessors(*c.postProcessors, nil, 0) 1120 newPostProcessors = &x 1121 } 1122 return Configurable[T]{ 1123 propertyName: c.propertyName, 1124 inner: c.inner.clone(), 1125 postProcessors: newPostProcessors, 1126 } 1127} 1128 1129func (c Configurable[T]) Clone() Configurable[T] { 1130 return c.clone().(Configurable[T]) 1131} 1132 1133func (c *configurableInner[T]) clone() *configurableInner[T] { 1134 if c == nil { 1135 return nil 1136 } 1137 return &configurableInner[T]{ 1138 // We don't need to clone the singleConfigurable because 1139 // it's supposed to be immutable 1140 single: c.single, 1141 replace: c.replace, 1142 next: c.next.clone(), 1143 } 1144} 1145 1146func (c *configurableInner[T]) isEmpty() bool { 1147 if c == nil { 1148 return true 1149 } 1150 if !c.single.isEmpty() { 1151 return false 1152 } 1153 return c.next.isEmpty() 1154} 1155 1156func (c Configurable[T]) isEmpty() bool { 1157 return c.inner.isEmpty() 1158} 1159 1160func (c *singleConfigurable[T]) isEmpty() bool { 1161 if c == nil { 1162 return true 1163 } 1164 if len(c.cases) > 1 { 1165 return false 1166 } 1167 if len(c.cases) == 1 && c.cases[0].value != nil { 1168 if _, ok := c.cases[0].value.(*parser.UnsetProperty); ok { 1169 return true 1170 } 1171 return false 1172 } 1173 return true 1174} 1175 1176func (c *configurableInner[T]) alwaysHasValue() bool { 1177 for curr := c; curr != nil; curr = curr.next { 1178 if curr.single.alwaysHasValue() { 1179 return true 1180 } 1181 } 1182 return false 1183} 1184 1185func (c *singleConfigurable[T]) alwaysHasValue() bool { 1186 if len(c.cases) == 0 { 1187 return false 1188 } 1189 for _, c := range c.cases { 1190 if _, isUnset := c.value.(*parser.UnsetProperty); isUnset || c.value == nil { 1191 return false 1192 } 1193 } 1194 return true 1195} 1196 1197func (c Configurable[T]) configuredType() reflect.Type { 1198 return reflect.TypeOf((*T)(nil)).Elem() 1199} 1200 1201func expressionToConfiguredValue[T ConfigurableElements](expr parser.Expression, scope *parser.Scope) (*T, error) { 1202 expr, err := expr.Eval(scope) 1203 if err != nil { 1204 return nil, err 1205 } 1206 switch e := expr.(type) { 1207 case *parser.UnsetProperty: 1208 return nil, nil 1209 case *parser.String: 1210 if result, ok := any(&e.Value).(*T); ok { 1211 return result, nil 1212 } else { 1213 return nil, fmt.Errorf("can't assign string value to %s property", configuredTypeToString[T]()) 1214 } 1215 case *parser.Bool: 1216 if result, ok := any(&e.Value).(*T); ok { 1217 return result, nil 1218 } else { 1219 return nil, fmt.Errorf("can't assign bool value to %s property", configuredTypeToString[T]()) 1220 } 1221 case *parser.List: 1222 result := make([]string, 0, len(e.Values)) 1223 for _, x := range e.Values { 1224 if y, ok := x.(*parser.String); ok { 1225 result = append(result, y.Value) 1226 } else { 1227 return nil, fmt.Errorf("expected list of strings but found list of %s", x.Type()) 1228 } 1229 } 1230 if result, ok := any(&result).(*T); ok { 1231 return result, nil 1232 } else { 1233 return nil, fmt.Errorf("can't assign list of strings to list of %s property", configuredTypeToString[T]()) 1234 } 1235 default: 1236 // If the expression was not evaluated beforehand we could hit this error even when the types match, 1237 // but that's an internal logic error. 1238 return nil, fmt.Errorf("expected %s but found %s (%#v)", configuredTypeToString[T](), expr.Type().String(), expr) 1239 } 1240} 1241 1242func configuredValueToExpression[T ConfigurableElements](value T) parser.Expression { 1243 switch v := any(value).(type) { 1244 case string: 1245 return &parser.String{Value: v} 1246 case bool: 1247 return &parser.Bool{Value: v} 1248 case []string: 1249 values := make([]parser.Expression, 0, len(v)) 1250 for _, x := range v { 1251 values = append(values, &parser.String{Value: x}) 1252 } 1253 return &parser.List{Values: values} 1254 default: 1255 panic("unhandled type in configuredValueToExpression") 1256 } 1257} 1258 1259func configuredTypeToString[T ConfigurableElements]() string { 1260 var zero T 1261 switch any(zero).(type) { 1262 case string: 1263 return "string" 1264 case bool: 1265 return "bool" 1266 case []string: 1267 return "list of strings" 1268 default: 1269 panic("should be unreachable") 1270 } 1271} 1272 1273func copyConfiguredValue[T ConfigurableElements](t T) T { 1274 switch t2 := any(t).(type) { 1275 case []string: 1276 return any(slices.Clone(t2)).(T) 1277 default: 1278 return t 1279 } 1280} 1281 1282func configuredValuePtrToOptional[T ConfigurableElements](t *T) ConfigurableOptional[T] { 1283 if t == nil { 1284 return ConfigurableOptional[T]{optional.NewShallowOptional(t)} 1285 } 1286 switch t2 := any(*t).(type) { 1287 case []string: 1288 result := any(slices.Clone(t2)).(T) 1289 return ConfigurableOptional[T]{optional.NewShallowOptional(&result)} 1290 default: 1291 return ConfigurableOptional[T]{optional.NewShallowOptional(t)} 1292 } 1293} 1294 1295// PrintfIntoConfigurable replaces %s occurrences in strings in Configurable properties 1296// with the provided string value. It's intention is to support soong config value variables 1297// on Configurable properties. 1298func PrintfIntoConfigurable(c any, value string) error { 1299 return c.(configurableReflection).printfInto(value) 1300} 1301 1302func promoteValueToConfigurable(origional reflect.Value) reflect.Value { 1303 var expr parser.Expression 1304 var kind reflect.Kind 1305 if origional.Kind() == reflect.Pointer && origional.IsNil() { 1306 expr = &parser.UnsetProperty{} 1307 kind = origional.Type().Elem().Kind() 1308 } else { 1309 if origional.Kind() == reflect.Pointer { 1310 origional = origional.Elem() 1311 } 1312 kind = origional.Kind() 1313 switch kind { 1314 case reflect.String: 1315 expr = &parser.String{Value: origional.String()} 1316 case reflect.Bool: 1317 expr = &parser.Bool{Value: origional.Bool()} 1318 case reflect.Slice: 1319 strList := origional.Interface().([]string) 1320 exprList := make([]parser.Expression, 0, len(strList)) 1321 for _, x := range strList { 1322 exprList = append(exprList, &parser.String{Value: x}) 1323 } 1324 expr = &parser.List{Values: exprList} 1325 default: 1326 panic("can only convert string/bool/[]string to configurable") 1327 } 1328 } 1329 switch kind { 1330 case reflect.String: 1331 return reflect.ValueOf(Configurable[string]{ 1332 inner: &configurableInner[string]{ 1333 single: singleConfigurable[string]{ 1334 cases: []ConfigurableCase[string]{{ 1335 value: expr, 1336 }}, 1337 }, 1338 }, 1339 postProcessors: &[][]postProcessor[string]{}, 1340 }) 1341 case reflect.Bool: 1342 return reflect.ValueOf(Configurable[bool]{ 1343 inner: &configurableInner[bool]{ 1344 single: singleConfigurable[bool]{ 1345 cases: []ConfigurableCase[bool]{{ 1346 value: expr, 1347 }}, 1348 }, 1349 }, 1350 postProcessors: &[][]postProcessor[bool]{}, 1351 }) 1352 case reflect.Slice: 1353 return reflect.ValueOf(Configurable[[]string]{ 1354 inner: &configurableInner[[]string]{ 1355 single: singleConfigurable[[]string]{ 1356 cases: []ConfigurableCase[[]string]{{ 1357 value: expr, 1358 }}, 1359 }, 1360 }, 1361 postProcessors: &[][]postProcessor[[]string]{}, 1362 }) 1363 default: 1364 panic(fmt.Sprintf("Can't convert %s property to a configurable", origional.Kind().String())) 1365 } 1366} 1367