• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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