xref: /aosp_15_r20/build/blueprint/proptools/configurable.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
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