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