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