Add PostProcessors to configurable properties
Some module types currently evaluate configurable properties in load hooks, modify the results, and pass them onto properties of other modules. Evaluating configurable properties in load hooks is problematic, it happens so early that we can't decide the configuration beforehand. Add a "post processors" mechanism to configurable properties where the result of evaluating the property will be passed through a post processing function before being returned from Get(). This essentially allows you to modify the property without evaluating it. Bug: 362579941 Test: m nothing --no-skip-soong-tests Change-Id: Ibddb3f14b3433364ba474b964c701e8915d4dc85
This commit is contained in:
parent
738bb54ded
commit
c472e38ec1
6 changed files with 791 additions and 548 deletions
|
@ -133,6 +133,7 @@ bootstrap_go_package {
|
||||||
],
|
],
|
||||||
testSrcs: [
|
testSrcs: [
|
||||||
"proptools/clone_test.go",
|
"proptools/clone_test.go",
|
||||||
|
"proptools/configurable_test.go",
|
||||||
"proptools/escape_test.go",
|
"proptools/escape_test.go",
|
||||||
"proptools/extend_test.go",
|
"proptools/extend_test.go",
|
||||||
"proptools/filter_test.go",
|
"proptools/filter_test.go",
|
||||||
|
|
|
@ -412,6 +412,22 @@ type Configurable[T ConfigurableElements] struct {
|
||||||
marker configurableMarker
|
marker configurableMarker
|
||||||
propertyName string
|
propertyName string
|
||||||
inner *configurableInner[T]
|
inner *configurableInner[T]
|
||||||
|
// See Configurable.evaluate for a description of the postProcessor algorithm and
|
||||||
|
// why this is a 2d list
|
||||||
|
postProcessors *[][]postProcessor[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
type postProcessor[T ConfigurableElements] struct {
|
||||||
|
f func(T) T
|
||||||
|
// start and end represent the range of configurableInners
|
||||||
|
// that this postprocessor is applied to. When appending two configurables
|
||||||
|
// together, the start and end values will stay the same for the left
|
||||||
|
// configurable's postprocessors, but the rights will be rebased by the
|
||||||
|
// number of configurableInners in the left configurable. This way
|
||||||
|
// the postProcessors still only apply to the configurableInners they
|
||||||
|
// origionally applied to before the appending.
|
||||||
|
start int
|
||||||
|
end int
|
||||||
}
|
}
|
||||||
|
|
||||||
type configurableInner[T ConfigurableElements] struct {
|
type configurableInner[T ConfigurableElements] struct {
|
||||||
|
@ -440,6 +456,7 @@ func NewConfigurable[T ConfigurableElements](conditions []ConfigurableCondition,
|
||||||
// Clone the slices so they can't be modified from soong
|
// Clone the slices so they can't be modified from soong
|
||||||
conditions = slices.Clone(conditions)
|
conditions = slices.Clone(conditions)
|
||||||
cases = slices.Clone(cases)
|
cases = slices.Clone(cases)
|
||||||
|
var zeroPostProcessors [][]postProcessor[T]
|
||||||
return Configurable[T]{
|
return Configurable[T]{
|
||||||
inner: &configurableInner[T]{
|
inner: &configurableInner[T]{
|
||||||
single: singleConfigurable[T]{
|
single: singleConfigurable[T]{
|
||||||
|
@ -447,35 +464,77 @@ func NewConfigurable[T ConfigurableElements](conditions []ConfigurableCondition,
|
||||||
cases: cases,
|
cases: cases,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &zeroPostProcessors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newConfigurableWithPropertyName[T ConfigurableElements](propertyName string, conditions []ConfigurableCondition, cases []ConfigurableCase[T], addScope bool) Configurable[T] {
|
||||||
|
result := NewConfigurable(conditions, cases)
|
||||||
|
result.propertyName = propertyName
|
||||||
|
if addScope {
|
||||||
|
for curr := result.inner; curr != nil; curr = curr.next {
|
||||||
|
curr.single.scope = parser.NewScope(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Configurable[T]) AppendSimpleValue(value T) {
|
func (c *Configurable[T]) AppendSimpleValue(value T) {
|
||||||
value = copyConfiguredValue(value)
|
value = copyConfiguredValue(value)
|
||||||
// This may be a property that was never initialized from a bp file
|
// This may be a property that was never initialized from a bp file
|
||||||
if c.inner == nil {
|
if c.inner == nil {
|
||||||
c.inner = &configurableInner[T]{
|
c.initialize(nil, "", nil, []ConfigurableCase[T]{{
|
||||||
single: singleConfigurable[T]{
|
value: configuredValueToExpression(value),
|
||||||
cases: []ConfigurableCase[T]{{
|
}})
|
||||||
value: configuredValueToExpression(value),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.inner.appendSimpleValue(value)
|
c.inner.appendSimpleValue(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddPostProcessor adds a function that will modify the result of
|
||||||
|
// Get() when Get() is called. It operates on all the current contents
|
||||||
|
// of the Configurable property, but if other values are appended to
|
||||||
|
// the Configurable property afterwards, the postProcessor will not run
|
||||||
|
// on them. This can be useful to essentially modify a configurable
|
||||||
|
// property without evaluating it.
|
||||||
|
func (c *Configurable[T]) AddPostProcessor(p func(T) T) {
|
||||||
|
// Add the new postProcessor on top of the tallest stack of postProcessors.
|
||||||
|
// See Configurable.evaluate for more details on the postProcessors algorithm
|
||||||
|
// and data structure.
|
||||||
|
num_links := c.inner.numLinks()
|
||||||
|
if c.postProcessors == nil || len(*c.postProcessors) == 0 {
|
||||||
|
c.postProcessors = &[][]postProcessor[T]{{{
|
||||||
|
f: p,
|
||||||
|
start: 0,
|
||||||
|
end: num_links,
|
||||||
|
}}}
|
||||||
|
} else {
|
||||||
|
deepestI := 0
|
||||||
|
deepestDepth := 0
|
||||||
|
for i := 0; i < len(*c.postProcessors); i++ {
|
||||||
|
if len((*c.postProcessors)[i]) > deepestDepth {
|
||||||
|
deepestDepth = len((*c.postProcessors)[i])
|
||||||
|
deepestI = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*c.postProcessors)[deepestI] = append((*c.postProcessors)[deepestI], postProcessor[T]{
|
||||||
|
f: p,
|
||||||
|
start: 0,
|
||||||
|
end: num_links,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns the final value for the configurable property.
|
// Get returns the final value for the configurable property.
|
||||||
// A configurable property may be unset, in which case Get will return nil.
|
// A configurable property may be unset, in which case Get will return nil.
|
||||||
func (c *Configurable[T]) Get(evaluator ConfigurableEvaluator) ConfigurableOptional[T] {
|
func (c *Configurable[T]) Get(evaluator ConfigurableEvaluator) ConfigurableOptional[T] {
|
||||||
result := c.inner.evaluate(c.propertyName, evaluator)
|
result := c.evaluate(c.propertyName, evaluator)
|
||||||
return configuredValuePtrToOptional(result)
|
return configuredValuePtrToOptional(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrDefault is the same as Get, but will return the provided default value if the property was unset.
|
// GetOrDefault is the same as Get, but will return the provided default value if the property was unset.
|
||||||
func (c *Configurable[T]) GetOrDefault(evaluator ConfigurableEvaluator, defaultValue T) T {
|
func (c *Configurable[T]) GetOrDefault(evaluator ConfigurableEvaluator, defaultValue T) T {
|
||||||
result := c.inner.evaluate(c.propertyName, evaluator)
|
result := c.evaluate(c.propertyName, evaluator)
|
||||||
if result != nil {
|
if result != nil {
|
||||||
// Copy the result so that it can't be changed from soong
|
// Copy the result so that it can't be changed from soong
|
||||||
return copyConfiguredValue(*result)
|
return copyConfiguredValue(*result)
|
||||||
|
@ -483,6 +542,127 @@ func (c *Configurable[T]) GetOrDefault(evaluator ConfigurableEvaluator, defaultV
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type valueAndIndices[T ConfigurableElements] struct {
|
||||||
|
value *T
|
||||||
|
replace bool
|
||||||
|
// Similar to start/end in postProcessor, these represent the origional
|
||||||
|
// range or configurableInners that this merged group represents. It's needed
|
||||||
|
// in order to apply recursive postProcessors to only the relevant
|
||||||
|
// configurableInners, even after those configurableInners have been merged
|
||||||
|
// in order to apply an earlier postProcessor.
|
||||||
|
start int
|
||||||
|
end int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configurable[T]) evaluate(propertyName string, evaluator ConfigurableEvaluator) *T {
|
||||||
|
if c.inner == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*c.postProcessors) == 0 {
|
||||||
|
// Use a simpler algorithm if there are no postprocessors
|
||||||
|
return c.inner.evaluate(propertyName, evaluator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The basic idea around evaluating with postprocessors is that each individual
|
||||||
|
// node in the chain (each configurableInner) is first evaluated, and then when
|
||||||
|
// a postprocessor operates on a certain range, that range is merged before passing
|
||||||
|
// it to the postprocessor. We want postProcessors to only accept a final merged
|
||||||
|
// value instead of a linked list, but at the same time, only operate over a portion
|
||||||
|
// of the list. If more configurables are appended onto this one, their values won't
|
||||||
|
// be operated on by the existing postProcessors, but they may have their own
|
||||||
|
// postprocessors.
|
||||||
|
//
|
||||||
|
// _____________________
|
||||||
|
// | __________|
|
||||||
|
// ______ | _____| ___
|
||||||
|
// | | | | | |
|
||||||
|
// a -> b -> c -> d -> e -> f -> g
|
||||||
|
//
|
||||||
|
// In this diagram, the letters along the bottom is the chain of configurableInners.
|
||||||
|
// The brackets on top represent postprocessors, where higher brackets are processed
|
||||||
|
// after lower ones.
|
||||||
|
//
|
||||||
|
// To evaluate this example, first we evaluate the raw values for all nodes a->g.
|
||||||
|
// Then we merge nodes a/b and d/e and apply the postprocessors to their merged values,
|
||||||
|
// and also to g. Those merged and postprocessed nodes are then reinserted into the
|
||||||
|
// list, and we move on to doing the higher level postprocessors (starting with the c->e one)
|
||||||
|
// in the same way. When all postprocessors are done, a final merge is done on anything
|
||||||
|
// leftover.
|
||||||
|
//
|
||||||
|
// The Configurable.postProcessors field is a 2d array to represent this hierarchy.
|
||||||
|
// The outer index moves right on this graph, the inner index goes up.
|
||||||
|
// When adding a new postProcessor, it will always be the last postProcessor to run
|
||||||
|
// until another is added or another configurable is appended. So in AddPostProcessor(),
|
||||||
|
// we add it to the tallest existing stack.
|
||||||
|
|
||||||
|
var currentValues []valueAndIndices[T]
|
||||||
|
for curr, i := c.inner, 0; curr != nil; curr, i = curr.next, i+1 {
|
||||||
|
value := curr.single.evaluateNonTransitive(propertyName, evaluator)
|
||||||
|
currentValues = append(currentValues, valueAndIndices[T]{
|
||||||
|
value: value,
|
||||||
|
replace: curr.replace,
|
||||||
|
start: i,
|
||||||
|
end: i + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.postProcessors == nil || len(*c.postProcessors) == 0 {
|
||||||
|
return mergeValues(currentValues).value
|
||||||
|
}
|
||||||
|
|
||||||
|
foundPostProcessor := true
|
||||||
|
for depth := 0; foundPostProcessor; depth++ {
|
||||||
|
foundPostProcessor = false
|
||||||
|
var newValues []valueAndIndices[T]
|
||||||
|
i := 0
|
||||||
|
for _, postProcessorGroup := range *c.postProcessors {
|
||||||
|
if len(postProcessorGroup) > depth {
|
||||||
|
foundPostProcessor = true
|
||||||
|
postProcessor := postProcessorGroup[depth]
|
||||||
|
startI := 0
|
||||||
|
endI := 0
|
||||||
|
for currentValues[startI].start < postProcessor.start {
|
||||||
|
startI++
|
||||||
|
}
|
||||||
|
for currentValues[endI].end < postProcessor.end {
|
||||||
|
endI++
|
||||||
|
}
|
||||||
|
endI++
|
||||||
|
newValues = append(newValues, currentValues[i:startI]...)
|
||||||
|
merged := mergeValues(currentValues[startI:endI])
|
||||||
|
if merged.value != nil {
|
||||||
|
processed := postProcessor.f(*merged.value)
|
||||||
|
merged.value = &processed
|
||||||
|
}
|
||||||
|
newValues = append(newValues, merged)
|
||||||
|
i = endI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newValues = append(newValues, currentValues[i:]...)
|
||||||
|
currentValues = newValues
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeValues(currentValues).value
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeValues[T ConfigurableElements](values []valueAndIndices[T]) valueAndIndices[T] {
|
||||||
|
if len(values) < 0 {
|
||||||
|
panic("Expected at least 1 value in mergeValues")
|
||||||
|
}
|
||||||
|
result := values[0]
|
||||||
|
for i := 1; i < len(values); i++ {
|
||||||
|
if result.replace {
|
||||||
|
result.value = replaceConfiguredValues(result.value, values[i].value)
|
||||||
|
} else {
|
||||||
|
result.value = appendConfiguredValues(result.value, values[i].value)
|
||||||
|
}
|
||||||
|
result.end = values[i].end
|
||||||
|
result.replace = values[i].replace
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configurableInner[T]) evaluate(propertyName string, evaluator ConfigurableEvaluator) *T {
|
func (c *configurableInner[T]) evaluate(propertyName string, evaluator ConfigurableEvaluator) *T {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -668,6 +848,12 @@ func (c *Configurable[T]) initialize(scope *parser.Scope, propertyName string, c
|
||||||
scope: scope,
|
scope: scope,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
var postProcessors [][]postProcessor[T]
|
||||||
|
c.postProcessors = &postProcessors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configurable[T]) Append(other Configurable[T]) {
|
||||||
|
c.setAppend(other, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Configurable[T]) setAppend(append any, replace bool, prepend bool) {
|
func (c Configurable[T]) setAppend(append any, replace bool, prepend bool) {
|
||||||
|
@ -675,12 +861,37 @@ func (c Configurable[T]) setAppend(append any, replace bool, prepend bool) {
|
||||||
if a.inner.isEmpty() {
|
if a.inner.isEmpty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if prepend {
|
||||||
|
newBase := a.inner.numLinks()
|
||||||
|
*c.postProcessors = appendPostprocessors(*a.postProcessors, *c.postProcessors, newBase)
|
||||||
|
} else {
|
||||||
|
newBase := c.inner.numLinks()
|
||||||
|
*c.postProcessors = appendPostprocessors(*c.postProcessors, *a.postProcessors, newBase)
|
||||||
|
}
|
||||||
|
|
||||||
c.inner.setAppend(a.inner, replace, prepend)
|
c.inner.setAppend(a.inner, replace, prepend)
|
||||||
if c.inner == c.inner.next {
|
if c.inner == c.inner.next {
|
||||||
panic("pointer loop")
|
panic("pointer loop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendPostprocessors[T ConfigurableElements](a, b [][]postProcessor[T], newBase int) [][]postProcessor[T] {
|
||||||
|
var result [][]postProcessor[T]
|
||||||
|
for i := 0; i < len(a); i++ {
|
||||||
|
result = append(result, slices.Clone(a[i]))
|
||||||
|
}
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
n := slices.Clone(b[i])
|
||||||
|
for j := 0; j < len(n); j++ {
|
||||||
|
n[j].start += newBase
|
||||||
|
n[j].end += newBase
|
||||||
|
}
|
||||||
|
result = append(result, n)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configurableInner[T]) setAppend(append *configurableInner[T], replace bool, prepend bool) {
|
func (c *configurableInner[T]) setAppend(append *configurableInner[T], replace bool, prepend bool) {
|
||||||
if c.isEmpty() {
|
if c.isEmpty() {
|
||||||
*c = *append.clone()
|
*c = *append.clone()
|
||||||
|
@ -719,6 +930,14 @@ func (c *configurableInner[T]) setAppend(append *configurableInner[T], replace b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configurableInner[T]) numLinks() int {
|
||||||
|
result := 0
|
||||||
|
for curr := c; curr != nil; curr = curr.next {
|
||||||
|
result++
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configurableInner[T]) appendSimpleValue(value T) {
|
func (c *configurableInner[T]) appendSimpleValue(value T) {
|
||||||
if c.next == nil {
|
if c.next == nil {
|
||||||
c.replace = false
|
c.replace = false
|
||||||
|
@ -761,10 +980,20 @@ func (c *singleConfigurable[T]) printfInto(value string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Configurable[T]) clone() any {
|
func (c Configurable[T]) clone() any {
|
||||||
return Configurable[T]{
|
var newPostProcessors *[][]postProcessor[T]
|
||||||
propertyName: c.propertyName,
|
if c.postProcessors != nil {
|
||||||
inner: c.inner.clone(),
|
x := appendPostprocessors(*c.postProcessors, nil, 0)
|
||||||
|
newPostProcessors = &x
|
||||||
}
|
}
|
||||||
|
return Configurable[T]{
|
||||||
|
propertyName: c.propertyName,
|
||||||
|
inner: c.inner.clone(),
|
||||||
|
postProcessors: newPostProcessors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Configurable[T]) Clone() Configurable[T] {
|
||||||
|
return c.clone().(Configurable[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurableInner[T]) clone() *configurableInner[T] {
|
func (c *configurableInner[T]) clone() *configurableInner[T] {
|
||||||
|
@ -973,6 +1202,7 @@ func promoteValueToConfigurable(origional reflect.Value) reflect.Value {
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &[][]postProcessor[string]{},
|
||||||
})
|
})
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return reflect.ValueOf(Configurable[bool]{
|
return reflect.ValueOf(Configurable[bool]{
|
||||||
|
@ -983,6 +1213,7 @@ func promoteValueToConfigurable(origional reflect.Value) reflect.Value {
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &[][]postProcessor[bool]{},
|
||||||
})
|
})
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
return reflect.ValueOf(Configurable[[]string]{
|
return reflect.ValueOf(Configurable[[]string]{
|
||||||
|
@ -993,6 +1224,7 @@ func promoteValueToConfigurable(origional reflect.Value) reflect.Value {
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &[][]postProcessor[[]string]{},
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Can't convert %s property to a configurable", origional.Kind().String()))
|
panic(fmt.Sprintf("Can't convert %s property to a configurable", origional.Kind().String()))
|
||||||
|
|
77
proptools/configurable_test.go
Normal file
77
proptools/configurable_test.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package proptools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPostProcessor(t *testing.T) {
|
||||||
|
// Same as the ascii art example in Configurable.evaluate()
|
||||||
|
prop := NewConfigurable[[]string](nil, nil)
|
||||||
|
prop.AppendSimpleValue([]string{"a"})
|
||||||
|
prop.AppendSimpleValue([]string{"b"})
|
||||||
|
prop.AddPostProcessor(addToElements("1"))
|
||||||
|
|
||||||
|
prop2 := NewConfigurable[[]string](nil, nil)
|
||||||
|
prop2.AppendSimpleValue([]string{"c"})
|
||||||
|
|
||||||
|
prop3 := NewConfigurable[[]string](nil, nil)
|
||||||
|
prop3.AppendSimpleValue([]string{"d"})
|
||||||
|
prop3.AppendSimpleValue([]string{"e"})
|
||||||
|
prop3.AddPostProcessor(addToElements("2"))
|
||||||
|
|
||||||
|
prop4 := NewConfigurable[[]string](nil, nil)
|
||||||
|
prop4.AppendSimpleValue([]string{"f"})
|
||||||
|
|
||||||
|
prop5 := NewConfigurable[[]string](nil, nil)
|
||||||
|
prop5.AppendSimpleValue([]string{"g"})
|
||||||
|
prop5.AddPostProcessor(addToElements("3"))
|
||||||
|
|
||||||
|
prop2.Append(prop3)
|
||||||
|
prop2.AddPostProcessor(addToElements("z"))
|
||||||
|
|
||||||
|
prop.Append(prop2)
|
||||||
|
prop.AddPostProcessor(addToElements("y"))
|
||||||
|
prop.Append(prop4)
|
||||||
|
prop.Append(prop5)
|
||||||
|
|
||||||
|
expected := []string{"a1y", "b1y", "czy", "d2zy", "e2zy", "f", "g3"}
|
||||||
|
x := prop.Get(&configurableEvalutorForTesting{})
|
||||||
|
if !reflect.DeepEqual(x.Get(), expected) {
|
||||||
|
t.Fatalf("Expected %v, got %v", expected, x.Get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addToElements(s string) func([]string) []string {
|
||||||
|
return func(arr []string) []string {
|
||||||
|
for i := range arr {
|
||||||
|
arr[i] = arr[i] + s
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type configurableEvalutorForTesting struct {
|
||||||
|
vars map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *configurableEvalutorForTesting) EvaluateConfiguration(condition ConfigurableCondition, property string) ConfigurableValue {
|
||||||
|
if condition.functionName != "f" {
|
||||||
|
panic("Expected functionName to be f")
|
||||||
|
}
|
||||||
|
if len(condition.args) != 1 {
|
||||||
|
panic("Expected exactly 1 arg")
|
||||||
|
}
|
||||||
|
val, ok := e.vars[condition.args[0]]
|
||||||
|
if ok {
|
||||||
|
return ConfigurableValueString(val)
|
||||||
|
}
|
||||||
|
return ConfigurableValueUndefined()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *configurableEvalutorForTesting) PropertyErrorf(property, fmtString string, args ...interface{}) {
|
||||||
|
panic(fmt.Sprintf(fmtString, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ConfigurableEvaluator = (*configurableEvalutorForTesting)(nil)
|
|
@ -1259,196 +1259,166 @@ func appendPropertiesTestCases() []appendPropertyTestCase {
|
||||||
{
|
{
|
||||||
name: "Append configurable",
|
name: "Append configurable",
|
||||||
dst: &struct{ S Configurable[[]string] }{
|
dst: &struct{ S Configurable[[]string] }{
|
||||||
S: Configurable[[]string]{
|
S: NewConfigurable[[]string]([]ConfigurableCondition{{
|
||||||
inner: &configurableInner[[]string]{
|
functionName: "soong_config_variable",
|
||||||
single: singleConfigurable[[]string]{
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"my_namespace",
|
||||||
functionName: "soong_config_variable",
|
"foo",
|
||||||
args: []string{
|
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "1"},
|
|
||||||
&parser.String{Value: "2"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
|
[]ConfigurableCase[[]string]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "1"},
|
||||||
|
&parser.String{Value: "2"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
src: &struct{ S Configurable[[]string] }{
|
src: &struct{ S Configurable[[]string] }{
|
||||||
S: Configurable[[]string]{
|
S: NewConfigurable([]ConfigurableCondition{{
|
||||||
inner: &configurableInner[[]string]{
|
functionName: "release_variable",
|
||||||
single: singleConfigurable[[]string]{
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"bar",
|
||||||
functionName: "release_variable",
|
|
||||||
args: []string{
|
|
||||||
"bar",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "b",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "3"},
|
|
||||||
&parser.String{Value: "4"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
|
[]ConfigurableCase[[]string]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "b",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "3"},
|
||||||
|
&parser.String{Value: "4"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
out: &struct{ S Configurable[[]string] }{
|
out: &struct{ S Configurable[[]string] }{
|
||||||
S: Configurable[[]string]{
|
S: func() Configurable[[]string] {
|
||||||
inner: &configurableInner[[]string]{
|
result := NewConfigurable([]ConfigurableCondition{{
|
||||||
single: singleConfigurable[[]string]{
|
functionName: "soong_config_variable",
|
||||||
conditions: []ConfigurableCondition{{
|
args: []string{
|
||||||
functionName: "soong_config_variable",
|
"my_namespace",
|
||||||
args: []string{
|
"foo",
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "1"},
|
|
||||||
&parser.String{Value: "2"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
next: &configurableInner[[]string]{
|
}},
|
||||||
single: singleConfigurable[[]string]{
|
[]ConfigurableCase[[]string]{{
|
||||||
conditions: []ConfigurableCondition{{
|
patterns: []ConfigurablePattern{{
|
||||||
functionName: "release_variable",
|
typ: configurablePatternTypeString,
|
||||||
args: []string{
|
stringValue: "a",
|
||||||
"bar",
|
}},
|
||||||
},
|
value: &parser.List{Values: []parser.Expression{
|
||||||
}},
|
&parser.String{Value: "1"},
|
||||||
cases: []ConfigurableCase[[]string]{{
|
&parser.String{Value: "2"},
|
||||||
patterns: []ConfigurablePattern{{
|
}},
|
||||||
typ: configurablePatternTypeString,
|
}},
|
||||||
stringValue: "b",
|
)
|
||||||
}},
|
result.Append(NewConfigurable([]ConfigurableCondition{{
|
||||||
value: &parser.List{Values: []parser.Expression{
|
functionName: "release_variable",
|
||||||
&parser.String{Value: "3"},
|
args: []string{
|
||||||
&parser.String{Value: "4"},
|
"bar",
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
[]ConfigurableCase[[]string]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "b",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "3"},
|
||||||
|
&parser.String{Value: "4"},
|
||||||
|
}},
|
||||||
|
}}))
|
||||||
|
return result
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Prepend configurable",
|
name: "Prepend configurable",
|
||||||
order: Prepend,
|
order: Prepend,
|
||||||
dst: &struct{ S Configurable[[]string] }{
|
dst: &struct{ S Configurable[[]string] }{
|
||||||
S: Configurable[[]string]{
|
S: NewConfigurable([]ConfigurableCondition{{
|
||||||
inner: &configurableInner[[]string]{
|
functionName: "soong_config_variable",
|
||||||
single: singleConfigurable[[]string]{
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"my_namespace",
|
||||||
functionName: "soong_config_variable",
|
"foo",
|
||||||
args: []string{
|
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "1"},
|
|
||||||
&parser.String{Value: "2"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
|
[]ConfigurableCase[[]string]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "1"},
|
||||||
|
&parser.String{Value: "2"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
src: &struct{ S Configurable[[]string] }{
|
src: &struct{ S Configurable[[]string] }{
|
||||||
S: Configurable[[]string]{
|
S: NewConfigurable([]ConfigurableCondition{{
|
||||||
inner: &configurableInner[[]string]{
|
functionName: "release_variable",
|
||||||
single: singleConfigurable[[]string]{
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"bar",
|
||||||
functionName: "release_variable",
|
|
||||||
args: []string{
|
|
||||||
"bar",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "b",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "3"},
|
|
||||||
&parser.String{Value: "4"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
|
[]ConfigurableCase[[]string]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "b",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "3"},
|
||||||
|
&parser.String{Value: "4"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
out: &struct{ S Configurable[[]string] }{
|
out: &struct{ S Configurable[[]string] }{
|
||||||
S: Configurable[[]string]{
|
S: func() Configurable[[]string] {
|
||||||
inner: &configurableInner[[]string]{
|
result := NewConfigurable(
|
||||||
single: singleConfigurable[[]string]{
|
[]ConfigurableCondition{{
|
||||||
conditions: []ConfigurableCondition{{
|
functionName: "release_variable",
|
||||||
functionName: "release_variable",
|
args: []string{
|
||||||
args: []string{
|
"bar",
|
||||||
"bar",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "b",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "3"},
|
|
||||||
&parser.String{Value: "4"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
next: &configurableInner[[]string]{
|
|
||||||
single: singleConfigurable[[]string]{
|
|
||||||
conditions: []ConfigurableCondition{{
|
|
||||||
functionName: "soong_config_variable",
|
|
||||||
args: []string{
|
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[[]string]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.List{Values: []parser.Expression{
|
|
||||||
&parser.String{Value: "1"},
|
|
||||||
&parser.String{Value: "2"},
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
[]ConfigurableCase[[]string]{{
|
||||||
},
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "b",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "3"},
|
||||||
|
&parser.String{Value: "4"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
)
|
||||||
|
result.Append(NewConfigurable(
|
||||||
|
[]ConfigurableCondition{{
|
||||||
|
functionName: "soong_config_variable",
|
||||||
|
args: []string{
|
||||||
|
"my_namespace",
|
||||||
|
"foo",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
[]ConfigurableCase[[]string]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
|
}},
|
||||||
|
value: &parser.List{Values: []parser.Expression{
|
||||||
|
&parser.String{Value: "1"},
|
||||||
|
&parser.String{Value: "2"},
|
||||||
|
}},
|
||||||
|
}}))
|
||||||
|
return result
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1918,31 +1888,24 @@ func appendMatchingPropertiesTestCases() []appendMatchingPropertiesTestCase {
|
||||||
order: Append,
|
order: Append,
|
||||||
dst: []interface{}{
|
dst: []interface{}{
|
||||||
&struct{ S Configurable[bool] }{
|
&struct{ S Configurable[bool] }{
|
||||||
S: Configurable[bool]{
|
S: NewConfigurable[bool]([]ConfigurableCondition{{
|
||||||
inner: &configurableInner[bool]{
|
functionName: "soong_config_variable",
|
||||||
single: singleConfigurable[bool]{
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"my_namespace",
|
||||||
functionName: "soong_config_variable",
|
"foo",
|
||||||
args: []string{
|
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[bool]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: true},
|
|
||||||
}, {
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeDefault,
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: false},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}}, []ConfigurableCase[bool]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: true},
|
||||||
|
}, {
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeDefault,
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: false},
|
||||||
|
}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
src: &struct{ S *bool }{
|
src: &struct{ S *bool }{
|
||||||
|
@ -1950,38 +1913,30 @@ func appendMatchingPropertiesTestCases() []appendMatchingPropertiesTestCase {
|
||||||
},
|
},
|
||||||
out: []interface{}{
|
out: []interface{}{
|
||||||
&struct{ S Configurable[bool] }{
|
&struct{ S Configurable[bool] }{
|
||||||
S: Configurable[bool]{
|
S: func() Configurable[bool] {
|
||||||
inner: &configurableInner[bool]{
|
result := NewConfigurable[bool]([]ConfigurableCondition{{
|
||||||
single: singleConfigurable[bool]{
|
functionName: "soong_config_variable",
|
||||||
conditions: []ConfigurableCondition{{
|
args: []string{
|
||||||
functionName: "soong_config_variable",
|
"my_namespace",
|
||||||
args: []string{
|
"foo",
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[bool]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: true},
|
|
||||||
}, {
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeDefault,
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: false},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
next: &configurableInner[bool]{
|
}},
|
||||||
single: singleConfigurable[bool]{
|
[]ConfigurableCase[bool]{{
|
||||||
cases: []ConfigurableCase[bool]{{
|
patterns: []ConfigurablePattern{{
|
||||||
value: &parser.Bool{Value: true},
|
typ: configurablePatternTypeString,
|
||||||
}},
|
stringValue: "a",
|
||||||
},
|
}},
|
||||||
},
|
value: &parser.Bool{Value: true},
|
||||||
},
|
}, {
|
||||||
},
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeDefault,
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: false},
|
||||||
|
}},
|
||||||
|
)
|
||||||
|
result.AppendSimpleValue(true)
|
||||||
|
return result
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1990,31 +1945,26 @@ func appendMatchingPropertiesTestCases() []appendMatchingPropertiesTestCase {
|
||||||
order: Append,
|
order: Append,
|
||||||
dst: []interface{}{
|
dst: []interface{}{
|
||||||
&struct{ S Configurable[bool] }{
|
&struct{ S Configurable[bool] }{
|
||||||
S: Configurable[bool]{
|
S: NewConfigurable[bool]([]ConfigurableCondition{{
|
||||||
inner: &configurableInner[bool]{
|
functionName: "soong_config_variable",
|
||||||
single: singleConfigurable[bool]{
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"my_namespace",
|
||||||
functionName: "soong_config_variable",
|
"foo",
|
||||||
args: []string{
|
|
||||||
"my_namespace",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[bool]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: true},
|
|
||||||
}, {
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeDefault,
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: false},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
|
[]ConfigurableCase[bool]{{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: true},
|
||||||
|
}, {
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeDefault,
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: false},
|
||||||
|
}},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
src: &struct{ S bool }{
|
src: &struct{ S bool }{
|
||||||
|
@ -2022,38 +1972,31 @@ func appendMatchingPropertiesTestCases() []appendMatchingPropertiesTestCase {
|
||||||
},
|
},
|
||||||
out: []interface{}{
|
out: []interface{}{
|
||||||
&struct{ S Configurable[bool] }{
|
&struct{ S Configurable[bool] }{
|
||||||
S: Configurable[bool]{
|
S: func() Configurable[bool] {
|
||||||
inner: &configurableInner[bool]{
|
result := NewConfigurable[bool](
|
||||||
single: singleConfigurable[bool]{
|
[]ConfigurableCondition{{
|
||||||
conditions: []ConfigurableCondition{{
|
functionName: "soong_config_variable",
|
||||||
functionName: "soong_config_variable",
|
args: []string{
|
||||||
args: []string{
|
"my_namespace",
|
||||||
"my_namespace",
|
"foo",
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[bool]{{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: true},
|
|
||||||
}, {
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeDefault,
|
|
||||||
}},
|
|
||||||
value: &parser.Bool{Value: false},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
next: &configurableInner[bool]{
|
|
||||||
single: singleConfigurable[bool]{
|
|
||||||
cases: []ConfigurableCase[bool]{{
|
|
||||||
value: &parser.Bool{Value: true},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
[]ConfigurableCase[bool]{{
|
||||||
},
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: true},
|
||||||
|
}, {
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeDefault,
|
||||||
|
}},
|
||||||
|
value: &parser.Bool{Value: false},
|
||||||
|
}},
|
||||||
|
)
|
||||||
|
result.AppendSimpleValue(true)
|
||||||
|
return result
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -354,6 +354,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
||||||
})
|
})
|
||||||
return reflect.New(configurableType), false
|
return reflect.New(configurableType), false
|
||||||
}
|
}
|
||||||
|
var postProcessors [][]postProcessor[string]
|
||||||
result := Configurable[string]{
|
result := Configurable[string]{
|
||||||
propertyName: property.Name,
|
propertyName: property.Name,
|
||||||
inner: &configurableInner[string]{
|
inner: &configurableInner[string]{
|
||||||
|
@ -363,6 +364,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &postProcessors,
|
||||||
}
|
}
|
||||||
return reflect.ValueOf(&result), true
|
return reflect.ValueOf(&result), true
|
||||||
case *parser.Bool:
|
case *parser.Bool:
|
||||||
|
@ -374,6 +376,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
||||||
})
|
})
|
||||||
return reflect.New(configurableType), false
|
return reflect.New(configurableType), false
|
||||||
}
|
}
|
||||||
|
var postProcessors [][]postProcessor[bool]
|
||||||
result := Configurable[bool]{
|
result := Configurable[bool]{
|
||||||
propertyName: property.Name,
|
propertyName: property.Name,
|
||||||
inner: &configurableInner[bool]{
|
inner: &configurableInner[bool]{
|
||||||
|
@ -383,6 +386,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &postProcessors,
|
||||||
}
|
}
|
||||||
return reflect.ValueOf(&result), true
|
return reflect.ValueOf(&result), true
|
||||||
case *parser.List:
|
case *parser.List:
|
||||||
|
@ -411,6 +415,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
||||||
value[i] = exprUnpacked.Interface().(string)
|
value[i] = exprUnpacked.Interface().(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var postProcessors [][]postProcessor[[]string]
|
||||||
result := Configurable[[]string]{
|
result := Configurable[[]string]{
|
||||||
propertyName: property.Name,
|
propertyName: property.Name,
|
||||||
inner: &configurableInner[[]string]{
|
inner: &configurableInner[[]string]{
|
||||||
|
@ -420,6 +425,7 @@ func (ctx *unpackContext) unpackToConfigurable(propertyName string, property *pa
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postProcessors: &postProcessors,
|
||||||
}
|
}
|
||||||
return reflect.ValueOf(&result), true
|
return reflect.ValueOf(&result), true
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -733,23 +733,21 @@ var validUnpackTestCases = []struct {
|
||||||
&struct {
|
&struct {
|
||||||
Foo Configurable[string]
|
Foo Configurable[string]
|
||||||
}{
|
}{
|
||||||
Foo: Configurable[string]{
|
Foo: newConfigurableWithPropertyName(
|
||||||
propertyName: "foo",
|
"foo",
|
||||||
inner: &configurableInner[string]{
|
nil,
|
||||||
single: singleConfigurable[string]{
|
[]ConfigurableCase[string]{{
|
||||||
cases: []ConfigurableCase[string]{{
|
value: &parser.String{
|
||||||
value: &parser.String{
|
LiteralPos: scanner.Position{
|
||||||
LiteralPos: scanner.Position{
|
Offset: 17,
|
||||||
Offset: 17,
|
Line: 3,
|
||||||
Line: 3,
|
Column: 10,
|
||||||
Column: 10,
|
},
|
||||||
},
|
Value: "bar",
|
||||||
Value: "bar",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
false,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -764,24 +762,22 @@ var validUnpackTestCases = []struct {
|
||||||
&struct {
|
&struct {
|
||||||
Foo Configurable[bool]
|
Foo Configurable[bool]
|
||||||
}{
|
}{
|
||||||
Foo: Configurable[bool]{
|
Foo: newConfigurableWithPropertyName(
|
||||||
propertyName: "foo",
|
"foo",
|
||||||
inner: &configurableInner[bool]{
|
nil,
|
||||||
single: singleConfigurable[bool]{
|
[]ConfigurableCase[bool]{{
|
||||||
cases: []ConfigurableCase[bool]{{
|
value: &parser.Bool{
|
||||||
value: &parser.Bool{
|
LiteralPos: scanner.Position{
|
||||||
LiteralPos: scanner.Position{
|
Offset: 17,
|
||||||
Offset: 17,
|
Line: 3,
|
||||||
Line: 3,
|
Column: 10,
|
||||||
Column: 10,
|
},
|
||||||
},
|
Value: true,
|
||||||
Value: true,
|
Token: "true",
|
||||||
Token: "true",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
false,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -796,45 +792,43 @@ var validUnpackTestCases = []struct {
|
||||||
&struct {
|
&struct {
|
||||||
Foo Configurable[[]string]
|
Foo Configurable[[]string]
|
||||||
}{
|
}{
|
||||||
Foo: Configurable[[]string]{
|
Foo: newConfigurableWithPropertyName(
|
||||||
propertyName: "foo",
|
"foo",
|
||||||
inner: &configurableInner[[]string]{
|
nil,
|
||||||
single: singleConfigurable[[]string]{
|
[]ConfigurableCase[[]string]{{
|
||||||
cases: []ConfigurableCase[[]string]{{
|
value: &parser.List{
|
||||||
value: &parser.List{
|
LBracePos: scanner.Position{
|
||||||
LBracePos: scanner.Position{
|
Offset: 17,
|
||||||
Offset: 17,
|
Line: 3,
|
||||||
|
Column: 10,
|
||||||
|
},
|
||||||
|
RBracePos: scanner.Position{
|
||||||
|
Offset: 26,
|
||||||
|
Line: 3,
|
||||||
|
Column: 19,
|
||||||
|
},
|
||||||
|
Values: []parser.Expression{
|
||||||
|
&parser.String{
|
||||||
|
LiteralPos: scanner.Position{
|
||||||
|
Offset: 18,
|
||||||
Line: 3,
|
Line: 3,
|
||||||
Column: 10,
|
Column: 11,
|
||||||
},
|
|
||||||
RBracePos: scanner.Position{
|
|
||||||
Offset: 26,
|
|
||||||
Line: 3,
|
|
||||||
Column: 19,
|
|
||||||
},
|
|
||||||
Values: []parser.Expression{
|
|
||||||
&parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 18,
|
|
||||||
Line: 3,
|
|
||||||
Column: 11,
|
|
||||||
},
|
|
||||||
Value: "a",
|
|
||||||
},
|
|
||||||
&parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 23,
|
|
||||||
Line: 3,
|
|
||||||
Column: 16,
|
|
||||||
},
|
|
||||||
Value: "b",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Value: "a",
|
||||||
},
|
},
|
||||||
}},
|
&parser.String{
|
||||||
|
LiteralPos: scanner.Position{
|
||||||
|
Offset: 23,
|
||||||
|
Line: 3,
|
||||||
|
Column: 16,
|
||||||
|
},
|
||||||
|
Value: "b",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
false,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -853,64 +847,60 @@ var validUnpackTestCases = []struct {
|
||||||
&struct {
|
&struct {
|
||||||
Foo Configurable[string]
|
Foo Configurable[string]
|
||||||
}{
|
}{
|
||||||
Foo: Configurable[string]{
|
Foo: newConfigurableWithPropertyName(
|
||||||
propertyName: "foo",
|
"foo",
|
||||||
inner: &configurableInner[string]{
|
[]ConfigurableCondition{{
|
||||||
single: singleConfigurable[string]{
|
functionName: "soong_config_variable",
|
||||||
scope: parser.NewScope(nil),
|
args: []string{
|
||||||
conditions: []ConfigurableCondition{{
|
"my_namespace",
|
||||||
functionName: "soong_config_variable",
|
"my_variable",
|
||||||
args: []string{
|
},
|
||||||
"my_namespace",
|
}},
|
||||||
"my_variable",
|
[]ConfigurableCase[string]{
|
||||||
},
|
{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "a",
|
||||||
}},
|
}},
|
||||||
cases: []ConfigurableCase[string]{
|
value: &parser.String{
|
||||||
{
|
LiteralPos: scanner.Position{
|
||||||
patterns: []ConfigurablePattern{{
|
Offset: 90,
|
||||||
typ: configurablePatternTypeString,
|
Line: 4,
|
||||||
stringValue: "a",
|
Column: 11,
|
||||||
}},
|
|
||||||
value: &parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 90,
|
|
||||||
Line: 4,
|
|
||||||
Column: 11,
|
|
||||||
},
|
|
||||||
Value: "a2",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
Value: "a2",
|
||||||
patterns: []ConfigurablePattern{{
|
},
|
||||||
typ: configurablePatternTypeString,
|
},
|
||||||
stringValue: "b",
|
{
|
||||||
}},
|
patterns: []ConfigurablePattern{{
|
||||||
value: &parser.String{
|
typ: configurablePatternTypeString,
|
||||||
LiteralPos: scanner.Position{
|
stringValue: "b",
|
||||||
Offset: 106,
|
}},
|
||||||
Line: 5,
|
value: &parser.String{
|
||||||
Column: 11,
|
LiteralPos: scanner.Position{
|
||||||
},
|
Offset: 106,
|
||||||
Value: "b2",
|
Line: 5,
|
||||||
},
|
Column: 11,
|
||||||
},
|
},
|
||||||
{
|
Value: "b2",
|
||||||
patterns: []ConfigurablePattern{{
|
},
|
||||||
typ: configurablePatternTypeDefault,
|
},
|
||||||
}},
|
{
|
||||||
value: &parser.String{
|
patterns: []ConfigurablePattern{{
|
||||||
LiteralPos: scanner.Position{
|
typ: configurablePatternTypeDefault,
|
||||||
Offset: 126,
|
}},
|
||||||
Line: 6,
|
value: &parser.String{
|
||||||
Column: 15,
|
LiteralPos: scanner.Position{
|
||||||
},
|
Offset: 126,
|
||||||
Value: "c2",
|
Line: 6,
|
||||||
},
|
Column: 15,
|
||||||
},
|
},
|
||||||
|
Value: "c2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
true,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -933,119 +923,117 @@ var validUnpackTestCases = []struct {
|
||||||
&struct {
|
&struct {
|
||||||
Foo Configurable[string]
|
Foo Configurable[string]
|
||||||
}{
|
}{
|
||||||
Foo: Configurable[string]{
|
Foo: func() Configurable[string] {
|
||||||
propertyName: "foo",
|
result := newConfigurableWithPropertyName(
|
||||||
inner: &configurableInner[string]{
|
"foo",
|
||||||
single: singleConfigurable[string]{
|
[]ConfigurableCondition{{
|
||||||
scope: parser.NewScope(nil),
|
functionName: "soong_config_variable",
|
||||||
conditions: []ConfigurableCondition{{
|
args: []string{
|
||||||
functionName: "soong_config_variable",
|
"my_namespace",
|
||||||
args: []string{
|
"my_variable",
|
||||||
"my_namespace",
|
|
||||||
"my_variable",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
cases: []ConfigurableCase[string]{
|
|
||||||
{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "a",
|
|
||||||
}},
|
|
||||||
value: &parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 90,
|
|
||||||
Line: 4,
|
|
||||||
Column: 11,
|
|
||||||
},
|
|
||||||
Value: "a2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeString,
|
|
||||||
stringValue: "b",
|
|
||||||
}},
|
|
||||||
value: &parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 106,
|
|
||||||
Line: 5,
|
|
||||||
Column: 11,
|
|
||||||
},
|
|
||||||
Value: "b2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
patterns: []ConfigurablePattern{{
|
|
||||||
typ: configurablePatternTypeDefault,
|
|
||||||
}},
|
|
||||||
value: &parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 126,
|
|
||||||
Line: 6,
|
|
||||||
Column: 15,
|
|
||||||
},
|
|
||||||
Value: "c2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
next: &configurableInner[string]{
|
[]ConfigurableCase[string]{
|
||||||
single: singleConfigurable[string]{
|
{
|
||||||
scope: parser.NewScope(nil),
|
patterns: []ConfigurablePattern{{
|
||||||
conditions: []ConfigurableCondition{{
|
typ: configurablePatternTypeString,
|
||||||
functionName: "soong_config_variable",
|
stringValue: "a",
|
||||||
args: []string{
|
|
||||||
"my_namespace",
|
|
||||||
"my_2nd_variable",
|
|
||||||
},
|
|
||||||
}},
|
}},
|
||||||
cases: []ConfigurableCase[string]{
|
value: &parser.String{
|
||||||
{
|
LiteralPos: scanner.Position{
|
||||||
patterns: []ConfigurablePattern{{
|
Offset: 90,
|
||||||
typ: configurablePatternTypeString,
|
Line: 4,
|
||||||
stringValue: "d",
|
Column: 11,
|
||||||
}},
|
|
||||||
value: &parser.String{
|
|
||||||
LiteralPos: scanner.Position{
|
|
||||||
Offset: 218,
|
|
||||||
Line: 8,
|
|
||||||
Column: 11,
|
|
||||||
},
|
|
||||||
Value: "d2",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
Value: "a2",
|
||||||
patterns: []ConfigurablePattern{{
|
},
|
||||||
typ: configurablePatternTypeString,
|
},
|
||||||
stringValue: "e",
|
{
|
||||||
}},
|
patterns: []ConfigurablePattern{{
|
||||||
value: &parser.String{
|
typ: configurablePatternTypeString,
|
||||||
LiteralPos: scanner.Position{
|
stringValue: "b",
|
||||||
Offset: 234,
|
}},
|
||||||
Line: 9,
|
value: &parser.String{
|
||||||
Column: 11,
|
LiteralPos: scanner.Position{
|
||||||
},
|
Offset: 106,
|
||||||
Value: "e2",
|
Line: 5,
|
||||||
},
|
Column: 11,
|
||||||
},
|
},
|
||||||
{
|
Value: "b2",
|
||||||
patterns: []ConfigurablePattern{{
|
},
|
||||||
typ: configurablePatternTypeDefault,
|
},
|
||||||
}},
|
{
|
||||||
value: &parser.String{
|
patterns: []ConfigurablePattern{{
|
||||||
LiteralPos: scanner.Position{
|
typ: configurablePatternTypeDefault,
|
||||||
Offset: 254,
|
}},
|
||||||
Line: 10,
|
value: &parser.String{
|
||||||
Column: 15,
|
LiteralPos: scanner.Position{
|
||||||
},
|
Offset: 126,
|
||||||
Value: "f2",
|
Line: 6,
|
||||||
},
|
Column: 15,
|
||||||
},
|
},
|
||||||
|
Value: "c2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
true,
|
||||||
},
|
)
|
||||||
|
result.Append(newConfigurableWithPropertyName(
|
||||||
|
"",
|
||||||
|
[]ConfigurableCondition{{
|
||||||
|
functionName: "soong_config_variable",
|
||||||
|
args: []string{
|
||||||
|
"my_namespace",
|
||||||
|
"my_2nd_variable",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
[]ConfigurableCase[string]{
|
||||||
|
{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "d",
|
||||||
|
}},
|
||||||
|
value: &parser.String{
|
||||||
|
LiteralPos: scanner.Position{
|
||||||
|
Offset: 218,
|
||||||
|
Line: 8,
|
||||||
|
Column: 11,
|
||||||
|
},
|
||||||
|
Value: "d2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeString,
|
||||||
|
stringValue: "e",
|
||||||
|
}},
|
||||||
|
value: &parser.String{
|
||||||
|
LiteralPos: scanner.Position{
|
||||||
|
Offset: 234,
|
||||||
|
Line: 9,
|
||||||
|
Column: 11,
|
||||||
|
},
|
||||||
|
Value: "e2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []ConfigurablePattern{{
|
||||||
|
typ: configurablePatternTypeDefault,
|
||||||
|
}},
|
||||||
|
value: &parser.String{
|
||||||
|
LiteralPos: scanner.Position{
|
||||||
|
Offset: 254,
|
||||||
|
Line: 10,
|
||||||
|
Column: 15,
|
||||||
|
},
|
||||||
|
Value: "f2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
))
|
||||||
|
return result
|
||||||
|
}(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1064,41 +1052,37 @@ var validUnpackTestCases = []struct {
|
||||||
Foo Configurable[string]
|
Foo Configurable[string]
|
||||||
Bar Configurable[bool]
|
Bar Configurable[bool]
|
||||||
}{
|
}{
|
||||||
Foo: Configurable[string]{
|
Foo: newConfigurableWithPropertyName(
|
||||||
propertyName: "foo",
|
"foo",
|
||||||
inner: &configurableInner[string]{
|
nil,
|
||||||
single: singleConfigurable[string]{
|
[]ConfigurableCase[string]{{
|
||||||
cases: []ConfigurableCase[string]{{
|
value: &parser.String{
|
||||||
value: &parser.String{
|
LiteralPos: scanner.Position{
|
||||||
LiteralPos: scanner.Position{
|
Offset: 25,
|
||||||
Offset: 25,
|
Line: 2,
|
||||||
Line: 2,
|
Column: 25,
|
||||||
Column: 25,
|
},
|
||||||
},
|
Value: "asdf",
|
||||||
Value: "asdf",
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
false,
|
||||||
Bar: Configurable[bool]{
|
),
|
||||||
propertyName: "bar",
|
Bar: newConfigurableWithPropertyName(
|
||||||
inner: &configurableInner[bool]{
|
"bar",
|
||||||
single: singleConfigurable[bool]{
|
nil,
|
||||||
cases: []ConfigurableCase[bool]{{
|
[]ConfigurableCase[bool]{{
|
||||||
value: &parser.Bool{
|
value: &parser.Bool{
|
||||||
LiteralPos: scanner.Position{
|
LiteralPos: scanner.Position{
|
||||||
Offset: 54,
|
Offset: 54,
|
||||||
Line: 3,
|
Line: 3,
|
||||||
Column: 23,
|
Column: 23,
|
||||||
},
|
},
|
||||||
Value: true,
|
Value: true,
|
||||||
Token: "true",
|
Token: "true",
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
},
|
false,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue