xref: /aosp_15_r20/build/blueprint/parser/ast.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2016 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 Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage parser
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"fmt"
19*1fa6dee9SAndroid Build Coastguard Worker	"os"
20*1fa6dee9SAndroid Build Coastguard Worker	"strings"
21*1fa6dee9SAndroid Build Coastguard Worker	"text/scanner"
22*1fa6dee9SAndroid Build Coastguard Worker)
23*1fa6dee9SAndroid Build Coastguard Worker
24*1fa6dee9SAndroid Build Coastguard Workertype Node interface {
25*1fa6dee9SAndroid Build Coastguard Worker	// Pos returns the position of the first token in the Node
26*1fa6dee9SAndroid Build Coastguard Worker	Pos() scanner.Position
27*1fa6dee9SAndroid Build Coastguard Worker	// End returns the position of the character after the last token in the Node
28*1fa6dee9SAndroid Build Coastguard Worker	End() scanner.Position
29*1fa6dee9SAndroid Build Coastguard Worker}
30*1fa6dee9SAndroid Build Coastguard Worker
31*1fa6dee9SAndroid Build Coastguard Worker// Definition is an Assignment or a Module at the top level of a Blueprints file
32*1fa6dee9SAndroid Build Coastguard Workertype Definition interface {
33*1fa6dee9SAndroid Build Coastguard Worker	Node
34*1fa6dee9SAndroid Build Coastguard Worker	String() string
35*1fa6dee9SAndroid Build Coastguard Worker	definitionTag()
36*1fa6dee9SAndroid Build Coastguard Worker}
37*1fa6dee9SAndroid Build Coastguard Worker
38*1fa6dee9SAndroid Build Coastguard Worker// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the
39*1fa6dee9SAndroid Build Coastguard Worker// file and subdirs.
40*1fa6dee9SAndroid Build Coastguard Workertype Assignment struct {
41*1fa6dee9SAndroid Build Coastguard Worker	Name       string
42*1fa6dee9SAndroid Build Coastguard Worker	NamePos    scanner.Position
43*1fa6dee9SAndroid Build Coastguard Worker	Value      Expression
44*1fa6dee9SAndroid Build Coastguard Worker	EqualsPos  scanner.Position
45*1fa6dee9SAndroid Build Coastguard Worker	Assigner   string
46*1fa6dee9SAndroid Build Coastguard Worker	Referenced bool
47*1fa6dee9SAndroid Build Coastguard Worker}
48*1fa6dee9SAndroid Build Coastguard Worker
49*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) String() string {
50*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("%s@%s %s %s %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.Referenced)
51*1fa6dee9SAndroid Build Coastguard Worker}
52*1fa6dee9SAndroid Build Coastguard Worker
53*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) Pos() scanner.Position { return a.NamePos }
54*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) End() scanner.Position { return a.Value.End() }
55*1fa6dee9SAndroid Build Coastguard Worker
56*1fa6dee9SAndroid Build Coastguard Workerfunc (a *Assignment) definitionTag() {}
57*1fa6dee9SAndroid Build Coastguard Worker
58*1fa6dee9SAndroid Build Coastguard Worker// A Module is a module definition at the top level of a Blueprints file
59*1fa6dee9SAndroid Build Coastguard Workertype Module struct {
60*1fa6dee9SAndroid Build Coastguard Worker	Type    string
61*1fa6dee9SAndroid Build Coastguard Worker	TypePos scanner.Position
62*1fa6dee9SAndroid Build Coastguard Worker	Map
63*1fa6dee9SAndroid Build Coastguard Worker	//TODO(delmerico) make this a private field once ag/21588220 lands
64*1fa6dee9SAndroid Build Coastguard Worker	Name__internal_only *string
65*1fa6dee9SAndroid Build Coastguard Worker}
66*1fa6dee9SAndroid Build Coastguard Worker
67*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) Copy() *Module {
68*1fa6dee9SAndroid Build Coastguard Worker	ret := *m
69*1fa6dee9SAndroid Build Coastguard Worker	ret.Properties = make([]*Property, len(m.Properties))
70*1fa6dee9SAndroid Build Coastguard Worker	for i := range m.Properties {
71*1fa6dee9SAndroid Build Coastguard Worker		ret.Properties[i] = m.Properties[i].Copy()
72*1fa6dee9SAndroid Build Coastguard Worker	}
73*1fa6dee9SAndroid Build Coastguard Worker	return &ret
74*1fa6dee9SAndroid Build Coastguard Worker}
75*1fa6dee9SAndroid Build Coastguard Worker
76*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) String() string {
77*1fa6dee9SAndroid Build Coastguard Worker	propertyStrings := make([]string, len(m.Properties))
78*1fa6dee9SAndroid Build Coastguard Worker	for i, property := range m.Properties {
79*1fa6dee9SAndroid Build Coastguard Worker		propertyStrings[i] = property.String()
80*1fa6dee9SAndroid Build Coastguard Worker	}
81*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("%s@%s-%s{%s}", m.Type,
82*1fa6dee9SAndroid Build Coastguard Worker		m.LBracePos, m.RBracePos,
83*1fa6dee9SAndroid Build Coastguard Worker		strings.Join(propertyStrings, ", "))
84*1fa6dee9SAndroid Build Coastguard Worker}
85*1fa6dee9SAndroid Build Coastguard Worker
86*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) definitionTag() {}
87*1fa6dee9SAndroid Build Coastguard Worker
88*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) Pos() scanner.Position { return m.TypePos }
89*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) End() scanner.Position { return m.Map.End() }
90*1fa6dee9SAndroid Build Coastguard Worker
91*1fa6dee9SAndroid Build Coastguard Workerfunc (m *Module) Name() string {
92*1fa6dee9SAndroid Build Coastguard Worker	if m.Name__internal_only != nil {
93*1fa6dee9SAndroid Build Coastguard Worker		return *m.Name__internal_only
94*1fa6dee9SAndroid Build Coastguard Worker	}
95*1fa6dee9SAndroid Build Coastguard Worker	for _, prop := range m.Properties {
96*1fa6dee9SAndroid Build Coastguard Worker		if prop.Name == "name" {
97*1fa6dee9SAndroid Build Coastguard Worker			if stringProp, ok := prop.Value.(*String); ok {
98*1fa6dee9SAndroid Build Coastguard Worker				name := stringProp.Value
99*1fa6dee9SAndroid Build Coastguard Worker				m.Name__internal_only = &name
100*1fa6dee9SAndroid Build Coastguard Worker			} else {
101*1fa6dee9SAndroid Build Coastguard Worker				name := prop.Value.String()
102*1fa6dee9SAndroid Build Coastguard Worker				m.Name__internal_only = &name
103*1fa6dee9SAndroid Build Coastguard Worker			}
104*1fa6dee9SAndroid Build Coastguard Worker		}
105*1fa6dee9SAndroid Build Coastguard Worker	}
106*1fa6dee9SAndroid Build Coastguard Worker	if m.Name__internal_only == nil {
107*1fa6dee9SAndroid Build Coastguard Worker		name := ""
108*1fa6dee9SAndroid Build Coastguard Worker		m.Name__internal_only = &name
109*1fa6dee9SAndroid Build Coastguard Worker	}
110*1fa6dee9SAndroid Build Coastguard Worker	return *m.Name__internal_only
111*1fa6dee9SAndroid Build Coastguard Worker}
112*1fa6dee9SAndroid Build Coastguard Worker
113*1fa6dee9SAndroid Build Coastguard Worker// A Property is a name: value pair within a Map, which may be a top level Module.
114*1fa6dee9SAndroid Build Coastguard Workertype Property struct {
115*1fa6dee9SAndroid Build Coastguard Worker	Name     string
116*1fa6dee9SAndroid Build Coastguard Worker	NamePos  scanner.Position
117*1fa6dee9SAndroid Build Coastguard Worker	ColonPos scanner.Position
118*1fa6dee9SAndroid Build Coastguard Worker	Value    Expression
119*1fa6dee9SAndroid Build Coastguard Worker}
120*1fa6dee9SAndroid Build Coastguard Worker
121*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) Copy() *Property {
122*1fa6dee9SAndroid Build Coastguard Worker	ret := *p
123*1fa6dee9SAndroid Build Coastguard Worker	ret.Value = p.Value.Copy()
124*1fa6dee9SAndroid Build Coastguard Worker	return &ret
125*1fa6dee9SAndroid Build Coastguard Worker}
126*1fa6dee9SAndroid Build Coastguard Worker
127*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) String() string {
128*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("%s@%s: %s", p.Name, p.ColonPos, p.Value)
129*1fa6dee9SAndroid Build Coastguard Worker}
130*1fa6dee9SAndroid Build Coastguard Worker
131*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) Pos() scanner.Position { return p.NamePos }
132*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) End() scanner.Position { return p.Value.End() }
133*1fa6dee9SAndroid Build Coastguard Worker
134*1fa6dee9SAndroid Build Coastguard Workerfunc (p *Property) MarkReferencedVariables(scope *Scope) {
135*1fa6dee9SAndroid Build Coastguard Worker	p.Value.MarkReferencedVariables(scope)
136*1fa6dee9SAndroid Build Coastguard Worker}
137*1fa6dee9SAndroid Build Coastguard Worker
138*1fa6dee9SAndroid Build Coastguard Worker// An Expression is a Value in a Property or Assignment.  It can be a literal (String or Bool), a
139*1fa6dee9SAndroid Build Coastguard Worker// Map, a List, an Operator that combines two expressions of the same type, or a Variable that
140*1fa6dee9SAndroid Build Coastguard Worker// references and Assignment.
141*1fa6dee9SAndroid Build Coastguard Workertype Expression interface {
142*1fa6dee9SAndroid Build Coastguard Worker	Node
143*1fa6dee9SAndroid Build Coastguard Worker	// Copy returns a copy of the Expression that will not affect the original if mutated
144*1fa6dee9SAndroid Build Coastguard Worker	Copy() Expression
145*1fa6dee9SAndroid Build Coastguard Worker	String() string
146*1fa6dee9SAndroid Build Coastguard Worker	// Type returns the underlying Type enum of the Expression if it were to be evaluated, if it's known.
147*1fa6dee9SAndroid Build Coastguard Worker	// It's possible that the type isn't known, such as when a select statement with a late-bound variable
148*1fa6dee9SAndroid Build Coastguard Worker	// is used. For that reason, Type() is mostly for use in error messages, not to make logic decisions
149*1fa6dee9SAndroid Build Coastguard Worker	// off of.
150*1fa6dee9SAndroid Build Coastguard Worker	Type() Type
151*1fa6dee9SAndroid Build Coastguard Worker	// Eval returns an expression that is fully evaluated to a simple type (List, Map, String,
152*1fa6dee9SAndroid Build Coastguard Worker	// Bool, or Select).  It will return the origional expression if possible, or allocate a
153*1fa6dee9SAndroid Build Coastguard Worker	// new one if modifications were necessary.
154*1fa6dee9SAndroid Build Coastguard Worker	Eval(scope *Scope) (Expression, error)
155*1fa6dee9SAndroid Build Coastguard Worker	// PrintfInto will substitute any %s's in string literals in the AST with the provided
156*1fa6dee9SAndroid Build Coastguard Worker	// value. It will modify the AST in-place. This is used to implement soong config value
157*1fa6dee9SAndroid Build Coastguard Worker	// variables, but should be removed when those have switched to selects.
158*1fa6dee9SAndroid Build Coastguard Worker	PrintfInto(value string) error
159*1fa6dee9SAndroid Build Coastguard Worker	// MarkReferencedVariables marks the variables in the given scope referenced if there
160*1fa6dee9SAndroid Build Coastguard Worker	// is a matching variable reference in this expression. This happens naturally during
161*1fa6dee9SAndroid Build Coastguard Worker	// Eval as well, but for selects, we need to mark variables as referenced without
162*1fa6dee9SAndroid Build Coastguard Worker	// actually evaluating the expression yet.
163*1fa6dee9SAndroid Build Coastguard Worker	MarkReferencedVariables(scope *Scope)
164*1fa6dee9SAndroid Build Coastguard Worker}
165*1fa6dee9SAndroid Build Coastguard Worker
166*1fa6dee9SAndroid Build Coastguard Worker// ExpressionsAreSame tells whether the two values are the same Expression.
167*1fa6dee9SAndroid Build Coastguard Worker// This includes the symbolic representation of each Expression but not their positions in the original source tree.
168*1fa6dee9SAndroid Build Coastguard Worker// This does not apply any simplification to the expressions before comparing them
169*1fa6dee9SAndroid Build Coastguard Worker// (for example, "!!a" wouldn't be deemed equal to "a")
170*1fa6dee9SAndroid Build Coastguard Workerfunc ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
171*1fa6dee9SAndroid Build Coastguard Worker	return hackyExpressionsAreSame(a, b)
172*1fa6dee9SAndroid Build Coastguard Worker}
173*1fa6dee9SAndroid Build Coastguard Worker
174*1fa6dee9SAndroid Build Coastguard Worker// TODO(jeffrygaston) once positions are removed from Expression structs,
175*1fa6dee9SAndroid Build Coastguard Worker// remove this function and have callers use reflect.DeepEqual(a, b)
176*1fa6dee9SAndroid Build Coastguard Workerfunc hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
177*1fa6dee9SAndroid Build Coastguard Worker	left, err := hackyFingerprint(a)
178*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
179*1fa6dee9SAndroid Build Coastguard Worker		return false, nil
180*1fa6dee9SAndroid Build Coastguard Worker	}
181*1fa6dee9SAndroid Build Coastguard Worker	right, err := hackyFingerprint(b)
182*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
183*1fa6dee9SAndroid Build Coastguard Worker		return false, nil
184*1fa6dee9SAndroid Build Coastguard Worker	}
185*1fa6dee9SAndroid Build Coastguard Worker	areEqual := string(left) == string(right)
186*1fa6dee9SAndroid Build Coastguard Worker	return areEqual, nil
187*1fa6dee9SAndroid Build Coastguard Worker}
188*1fa6dee9SAndroid Build Coastguard Worker
189*1fa6dee9SAndroid Build Coastguard Workerfunc hackyFingerprint(expression Expression) (fingerprint []byte, err error) {
190*1fa6dee9SAndroid Build Coastguard Worker	assignment := &Assignment{"a", noPos, expression, noPos, "=", false}
191*1fa6dee9SAndroid Build Coastguard Worker	module := &File{}
192*1fa6dee9SAndroid Build Coastguard Worker	module.Defs = append(module.Defs, assignment)
193*1fa6dee9SAndroid Build Coastguard Worker	p := newPrinter(module)
194*1fa6dee9SAndroid Build Coastguard Worker	return p.Print()
195*1fa6dee9SAndroid Build Coastguard Worker}
196*1fa6dee9SAndroid Build Coastguard Worker
197*1fa6dee9SAndroid Build Coastguard Workertype Type int
198*1fa6dee9SAndroid Build Coastguard Worker
199*1fa6dee9SAndroid Build Coastguard Workerconst (
200*1fa6dee9SAndroid Build Coastguard Worker	UnknownType Type = iota
201*1fa6dee9SAndroid Build Coastguard Worker	BoolType
202*1fa6dee9SAndroid Build Coastguard Worker	StringType
203*1fa6dee9SAndroid Build Coastguard Worker	Int64Type
204*1fa6dee9SAndroid Build Coastguard Worker	ListType
205*1fa6dee9SAndroid Build Coastguard Worker	MapType
206*1fa6dee9SAndroid Build Coastguard Worker	UnsetType
207*1fa6dee9SAndroid Build Coastguard Worker)
208*1fa6dee9SAndroid Build Coastguard Worker
209*1fa6dee9SAndroid Build Coastguard Workerfunc (t Type) String() string {
210*1fa6dee9SAndroid Build Coastguard Worker	switch t {
211*1fa6dee9SAndroid Build Coastguard Worker	case UnknownType:
212*1fa6dee9SAndroid Build Coastguard Worker		return "unknown"
213*1fa6dee9SAndroid Build Coastguard Worker	case BoolType:
214*1fa6dee9SAndroid Build Coastguard Worker		return "bool"
215*1fa6dee9SAndroid Build Coastguard Worker	case StringType:
216*1fa6dee9SAndroid Build Coastguard Worker		return "string"
217*1fa6dee9SAndroid Build Coastguard Worker	case Int64Type:
218*1fa6dee9SAndroid Build Coastguard Worker		return "int64"
219*1fa6dee9SAndroid Build Coastguard Worker	case ListType:
220*1fa6dee9SAndroid Build Coastguard Worker		return "list"
221*1fa6dee9SAndroid Build Coastguard Worker	case MapType:
222*1fa6dee9SAndroid Build Coastguard Worker		return "map"
223*1fa6dee9SAndroid Build Coastguard Worker	case UnsetType:
224*1fa6dee9SAndroid Build Coastguard Worker		return "unset"
225*1fa6dee9SAndroid Build Coastguard Worker	default:
226*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Sprintf("Unknown type %d", t))
227*1fa6dee9SAndroid Build Coastguard Worker	}
228*1fa6dee9SAndroid Build Coastguard Worker}
229*1fa6dee9SAndroid Build Coastguard Worker
230*1fa6dee9SAndroid Build Coastguard Workerfunc ZeroExpression(t Type) Expression {
231*1fa6dee9SAndroid Build Coastguard Worker	switch t {
232*1fa6dee9SAndroid Build Coastguard Worker	case UnknownType:
233*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Errorf("cannot create zero expression for UnknownType"))
234*1fa6dee9SAndroid Build Coastguard Worker	case BoolType:
235*1fa6dee9SAndroid Build Coastguard Worker		return &Bool{}
236*1fa6dee9SAndroid Build Coastguard Worker	case StringType:
237*1fa6dee9SAndroid Build Coastguard Worker		return &String{}
238*1fa6dee9SAndroid Build Coastguard Worker	case Int64Type:
239*1fa6dee9SAndroid Build Coastguard Worker		return &Int64{}
240*1fa6dee9SAndroid Build Coastguard Worker	case ListType:
241*1fa6dee9SAndroid Build Coastguard Worker		return &List{}
242*1fa6dee9SAndroid Build Coastguard Worker	case MapType:
243*1fa6dee9SAndroid Build Coastguard Worker		return &Map{}
244*1fa6dee9SAndroid Build Coastguard Worker	case UnsetType:
245*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Errorf("cannot create zero expression for UnsetType"))
246*1fa6dee9SAndroid Build Coastguard Worker
247*1fa6dee9SAndroid Build Coastguard Worker	default:
248*1fa6dee9SAndroid Build Coastguard Worker		panic(fmt.Errorf("Unknown type %d", t))
249*1fa6dee9SAndroid Build Coastguard Worker	}
250*1fa6dee9SAndroid Build Coastguard Worker}
251*1fa6dee9SAndroid Build Coastguard Worker
252*1fa6dee9SAndroid Build Coastguard Workertype Operator struct {
253*1fa6dee9SAndroid Build Coastguard Worker	Args        [2]Expression
254*1fa6dee9SAndroid Build Coastguard Worker	Operator    rune
255*1fa6dee9SAndroid Build Coastguard Worker	OperatorPos scanner.Position
256*1fa6dee9SAndroid Build Coastguard Worker}
257*1fa6dee9SAndroid Build Coastguard Worker
258*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Copy() Expression {
259*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
260*1fa6dee9SAndroid Build Coastguard Worker	ret.Args[0] = x.Args[0].Copy()
261*1fa6dee9SAndroid Build Coastguard Worker	ret.Args[1] = x.Args[1].Copy()
262*1fa6dee9SAndroid Build Coastguard Worker	return &ret
263*1fa6dee9SAndroid Build Coastguard Worker}
264*1fa6dee9SAndroid Build Coastguard Worker
265*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Type() Type {
266*1fa6dee9SAndroid Build Coastguard Worker	t1 := x.Args[0].Type()
267*1fa6dee9SAndroid Build Coastguard Worker	t2 := x.Args[1].Type()
268*1fa6dee9SAndroid Build Coastguard Worker	if t1 == UnknownType {
269*1fa6dee9SAndroid Build Coastguard Worker		return t2
270*1fa6dee9SAndroid Build Coastguard Worker	}
271*1fa6dee9SAndroid Build Coastguard Worker	if t2 == UnknownType {
272*1fa6dee9SAndroid Build Coastguard Worker		return t1
273*1fa6dee9SAndroid Build Coastguard Worker	}
274*1fa6dee9SAndroid Build Coastguard Worker	if t1 != t2 {
275*1fa6dee9SAndroid Build Coastguard Worker		return UnknownType
276*1fa6dee9SAndroid Build Coastguard Worker	}
277*1fa6dee9SAndroid Build Coastguard Worker	return t1
278*1fa6dee9SAndroid Build Coastguard Worker}
279*1fa6dee9SAndroid Build Coastguard Worker
280*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Eval(scope *Scope) (Expression, error) {
281*1fa6dee9SAndroid Build Coastguard Worker	return evaluateOperator(scope, x.Operator, x.Args[0], x.Args[1])
282*1fa6dee9SAndroid Build Coastguard Worker}
283*1fa6dee9SAndroid Build Coastguard Worker
284*1fa6dee9SAndroid Build Coastguard Workerfunc evaluateOperator(scope *Scope, operator rune, left, right Expression) (Expression, error) {
285*1fa6dee9SAndroid Build Coastguard Worker	if operator != '+' {
286*1fa6dee9SAndroid Build Coastguard Worker		return nil, fmt.Errorf("unknown operator %c", operator)
287*1fa6dee9SAndroid Build Coastguard Worker	}
288*1fa6dee9SAndroid Build Coastguard Worker	l, err := left.Eval(scope)
289*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
290*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
291*1fa6dee9SAndroid Build Coastguard Worker	}
292*1fa6dee9SAndroid Build Coastguard Worker	r, err := right.Eval(scope)
293*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
294*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
295*1fa6dee9SAndroid Build Coastguard Worker	}
296*1fa6dee9SAndroid Build Coastguard Worker
297*1fa6dee9SAndroid Build Coastguard Worker	if _, ok := l.(*Select); !ok {
298*1fa6dee9SAndroid Build Coastguard Worker		if _, ok := r.(*Select); ok {
299*1fa6dee9SAndroid Build Coastguard Worker			// Promote l to a select so we can add r to it
300*1fa6dee9SAndroid Build Coastguard Worker			l = &Select{
301*1fa6dee9SAndroid Build Coastguard Worker				Cases: []*SelectCase{{
302*1fa6dee9SAndroid Build Coastguard Worker					Value: l,
303*1fa6dee9SAndroid Build Coastguard Worker				}},
304*1fa6dee9SAndroid Build Coastguard Worker			}
305*1fa6dee9SAndroid Build Coastguard Worker		}
306*1fa6dee9SAndroid Build Coastguard Worker	}
307*1fa6dee9SAndroid Build Coastguard Worker
308*1fa6dee9SAndroid Build Coastguard Worker	l = l.Copy()
309*1fa6dee9SAndroid Build Coastguard Worker
310*1fa6dee9SAndroid Build Coastguard Worker	switch v := l.(type) {
311*1fa6dee9SAndroid Build Coastguard Worker	case *String:
312*1fa6dee9SAndroid Build Coastguard Worker		if _, ok := r.(*String); !ok {
313*1fa6dee9SAndroid Build Coastguard Worker			fmt.Fprintf(os.Stderr, "not ok")
314*1fa6dee9SAndroid Build Coastguard Worker		}
315*1fa6dee9SAndroid Build Coastguard Worker		v.Value += r.(*String).Value
316*1fa6dee9SAndroid Build Coastguard Worker	case *Int64:
317*1fa6dee9SAndroid Build Coastguard Worker		v.Value += r.(*Int64).Value
318*1fa6dee9SAndroid Build Coastguard Worker		v.Token = ""
319*1fa6dee9SAndroid Build Coastguard Worker	case *List:
320*1fa6dee9SAndroid Build Coastguard Worker		v.Values = append(v.Values, r.(*List).Values...)
321*1fa6dee9SAndroid Build Coastguard Worker	case *Map:
322*1fa6dee9SAndroid Build Coastguard Worker		var err error
323*1fa6dee9SAndroid Build Coastguard Worker		v.Properties, err = addMaps(scope, v.Properties, r.(*Map).Properties)
324*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
325*1fa6dee9SAndroid Build Coastguard Worker			return nil, err
326*1fa6dee9SAndroid Build Coastguard Worker		}
327*1fa6dee9SAndroid Build Coastguard Worker	case *Select:
328*1fa6dee9SAndroid Build Coastguard Worker		v.Append = r
329*1fa6dee9SAndroid Build Coastguard Worker	default:
330*1fa6dee9SAndroid Build Coastguard Worker		return nil, fmt.Errorf("operator %c not supported on %v", operator, v)
331*1fa6dee9SAndroid Build Coastguard Worker	}
332*1fa6dee9SAndroid Build Coastguard Worker
333*1fa6dee9SAndroid Build Coastguard Worker	return l, nil
334*1fa6dee9SAndroid Build Coastguard Worker}
335*1fa6dee9SAndroid Build Coastguard Worker
336*1fa6dee9SAndroid Build Coastguard Workerfunc addMaps(scope *Scope, map1, map2 []*Property) ([]*Property, error) {
337*1fa6dee9SAndroid Build Coastguard Worker	ret := make([]*Property, 0, len(map1))
338*1fa6dee9SAndroid Build Coastguard Worker
339*1fa6dee9SAndroid Build Coastguard Worker	inMap1 := make(map[string]*Property)
340*1fa6dee9SAndroid Build Coastguard Worker	inMap2 := make(map[string]*Property)
341*1fa6dee9SAndroid Build Coastguard Worker	inBoth := make(map[string]*Property)
342*1fa6dee9SAndroid Build Coastguard Worker
343*1fa6dee9SAndroid Build Coastguard Worker	for _, prop1 := range map1 {
344*1fa6dee9SAndroid Build Coastguard Worker		inMap1[prop1.Name] = prop1
345*1fa6dee9SAndroid Build Coastguard Worker	}
346*1fa6dee9SAndroid Build Coastguard Worker
347*1fa6dee9SAndroid Build Coastguard Worker	for _, prop2 := range map2 {
348*1fa6dee9SAndroid Build Coastguard Worker		inMap2[prop2.Name] = prop2
349*1fa6dee9SAndroid Build Coastguard Worker		if _, ok := inMap1[prop2.Name]; ok {
350*1fa6dee9SAndroid Build Coastguard Worker			inBoth[prop2.Name] = prop2
351*1fa6dee9SAndroid Build Coastguard Worker		}
352*1fa6dee9SAndroid Build Coastguard Worker	}
353*1fa6dee9SAndroid Build Coastguard Worker
354*1fa6dee9SAndroid Build Coastguard Worker	for _, prop1 := range map1 {
355*1fa6dee9SAndroid Build Coastguard Worker		if prop2, ok := inBoth[prop1.Name]; ok {
356*1fa6dee9SAndroid Build Coastguard Worker			var err error
357*1fa6dee9SAndroid Build Coastguard Worker			newProp := *prop1
358*1fa6dee9SAndroid Build Coastguard Worker			newProp.Value, err = evaluateOperator(scope, '+', prop1.Value, prop2.Value)
359*1fa6dee9SAndroid Build Coastguard Worker			if err != nil {
360*1fa6dee9SAndroid Build Coastguard Worker				return nil, err
361*1fa6dee9SAndroid Build Coastguard Worker			}
362*1fa6dee9SAndroid Build Coastguard Worker			ret = append(ret, &newProp)
363*1fa6dee9SAndroid Build Coastguard Worker		} else {
364*1fa6dee9SAndroid Build Coastguard Worker			ret = append(ret, prop1)
365*1fa6dee9SAndroid Build Coastguard Worker		}
366*1fa6dee9SAndroid Build Coastguard Worker	}
367*1fa6dee9SAndroid Build Coastguard Worker
368*1fa6dee9SAndroid Build Coastguard Worker	for _, prop2 := range map2 {
369*1fa6dee9SAndroid Build Coastguard Worker		if _, ok := inBoth[prop2.Name]; !ok {
370*1fa6dee9SAndroid Build Coastguard Worker			ret = append(ret, prop2)
371*1fa6dee9SAndroid Build Coastguard Worker		}
372*1fa6dee9SAndroid Build Coastguard Worker	}
373*1fa6dee9SAndroid Build Coastguard Worker
374*1fa6dee9SAndroid Build Coastguard Worker	return ret, nil
375*1fa6dee9SAndroid Build Coastguard Worker}
376*1fa6dee9SAndroid Build Coastguard Worker
377*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) PrintfInto(value string) error {
378*1fa6dee9SAndroid Build Coastguard Worker	if err := x.Args[0].PrintfInto(value); err != nil {
379*1fa6dee9SAndroid Build Coastguard Worker		return err
380*1fa6dee9SAndroid Build Coastguard Worker	}
381*1fa6dee9SAndroid Build Coastguard Worker	return x.Args[1].PrintfInto(value)
382*1fa6dee9SAndroid Build Coastguard Worker}
383*1fa6dee9SAndroid Build Coastguard Worker
384*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) MarkReferencedVariables(scope *Scope) {
385*1fa6dee9SAndroid Build Coastguard Worker	x.Args[0].MarkReferencedVariables(scope)
386*1fa6dee9SAndroid Build Coastguard Worker	x.Args[1].MarkReferencedVariables(scope)
387*1fa6dee9SAndroid Build Coastguard Worker}
388*1fa6dee9SAndroid Build Coastguard Worker
389*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() }
390*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) End() scanner.Position { return x.Args[1].End() }
391*1fa6dee9SAndroid Build Coastguard Worker
392*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Operator) String() string {
393*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("(%s %c %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(),
394*1fa6dee9SAndroid Build Coastguard Worker		x.OperatorPos)
395*1fa6dee9SAndroid Build Coastguard Worker}
396*1fa6dee9SAndroid Build Coastguard Worker
397*1fa6dee9SAndroid Build Coastguard Workertype Variable struct {
398*1fa6dee9SAndroid Build Coastguard Worker	Name    string
399*1fa6dee9SAndroid Build Coastguard Worker	NamePos scanner.Position
400*1fa6dee9SAndroid Build Coastguard Worker	Type_   Type
401*1fa6dee9SAndroid Build Coastguard Worker}
402*1fa6dee9SAndroid Build Coastguard Worker
403*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Pos() scanner.Position { return x.NamePos }
404*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) }
405*1fa6dee9SAndroid Build Coastguard Worker
406*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Copy() Expression {
407*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
408*1fa6dee9SAndroid Build Coastguard Worker	return &ret
409*1fa6dee9SAndroid Build Coastguard Worker}
410*1fa6dee9SAndroid Build Coastguard Worker
411*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Eval(scope *Scope) (Expression, error) {
412*1fa6dee9SAndroid Build Coastguard Worker	if assignment := scope.Get(x.Name); assignment != nil {
413*1fa6dee9SAndroid Build Coastguard Worker		assignment.Referenced = true
414*1fa6dee9SAndroid Build Coastguard Worker		return assignment.Value, nil
415*1fa6dee9SAndroid Build Coastguard Worker	}
416*1fa6dee9SAndroid Build Coastguard Worker	return nil, fmt.Errorf("undefined variable %s", x.Name)
417*1fa6dee9SAndroid Build Coastguard Worker}
418*1fa6dee9SAndroid Build Coastguard Worker
419*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) PrintfInto(value string) error {
420*1fa6dee9SAndroid Build Coastguard Worker	return nil
421*1fa6dee9SAndroid Build Coastguard Worker}
422*1fa6dee9SAndroid Build Coastguard Worker
423*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) MarkReferencedVariables(scope *Scope) {
424*1fa6dee9SAndroid Build Coastguard Worker	if assignment := scope.Get(x.Name); assignment != nil {
425*1fa6dee9SAndroid Build Coastguard Worker		assignment.Referenced = true
426*1fa6dee9SAndroid Build Coastguard Worker	}
427*1fa6dee9SAndroid Build Coastguard Worker}
428*1fa6dee9SAndroid Build Coastguard Worker
429*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) String() string {
430*1fa6dee9SAndroid Build Coastguard Worker	return x.Name
431*1fa6dee9SAndroid Build Coastguard Worker}
432*1fa6dee9SAndroid Build Coastguard Worker
433*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Variable) Type() Type {
434*1fa6dee9SAndroid Build Coastguard Worker	// Variables do not normally have a type associated with them, this is only
435*1fa6dee9SAndroid Build Coastguard Worker	// filled out in the androidmk tool
436*1fa6dee9SAndroid Build Coastguard Worker	return x.Type_
437*1fa6dee9SAndroid Build Coastguard Worker}
438*1fa6dee9SAndroid Build Coastguard Worker
439*1fa6dee9SAndroid Build Coastguard Workertype Map struct {
440*1fa6dee9SAndroid Build Coastguard Worker	LBracePos  scanner.Position
441*1fa6dee9SAndroid Build Coastguard Worker	RBracePos  scanner.Position
442*1fa6dee9SAndroid Build Coastguard Worker	Properties []*Property
443*1fa6dee9SAndroid Build Coastguard Worker}
444*1fa6dee9SAndroid Build Coastguard Worker
445*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Pos() scanner.Position { return x.LBracePos }
446*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) }
447*1fa6dee9SAndroid Build Coastguard Worker
448*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Copy() Expression {
449*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
450*1fa6dee9SAndroid Build Coastguard Worker	ret.Properties = make([]*Property, len(x.Properties))
451*1fa6dee9SAndroid Build Coastguard Worker	for i := range x.Properties {
452*1fa6dee9SAndroid Build Coastguard Worker		ret.Properties[i] = x.Properties[i].Copy()
453*1fa6dee9SAndroid Build Coastguard Worker	}
454*1fa6dee9SAndroid Build Coastguard Worker	return &ret
455*1fa6dee9SAndroid Build Coastguard Worker}
456*1fa6dee9SAndroid Build Coastguard Worker
457*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Eval(scope *Scope) (Expression, error) {
458*1fa6dee9SAndroid Build Coastguard Worker	newProps := make([]*Property, len(x.Properties))
459*1fa6dee9SAndroid Build Coastguard Worker	for i, prop := range x.Properties {
460*1fa6dee9SAndroid Build Coastguard Worker		newVal, err := prop.Value.Eval(scope)
461*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
462*1fa6dee9SAndroid Build Coastguard Worker			return nil, err
463*1fa6dee9SAndroid Build Coastguard Worker		}
464*1fa6dee9SAndroid Build Coastguard Worker		newProps[i] = &Property{
465*1fa6dee9SAndroid Build Coastguard Worker			Name:     prop.Name,
466*1fa6dee9SAndroid Build Coastguard Worker			NamePos:  prop.NamePos,
467*1fa6dee9SAndroid Build Coastguard Worker			ColonPos: prop.ColonPos,
468*1fa6dee9SAndroid Build Coastguard Worker			Value:    newVal,
469*1fa6dee9SAndroid Build Coastguard Worker		}
470*1fa6dee9SAndroid Build Coastguard Worker	}
471*1fa6dee9SAndroid Build Coastguard Worker	return &Map{
472*1fa6dee9SAndroid Build Coastguard Worker		LBracePos:  x.LBracePos,
473*1fa6dee9SAndroid Build Coastguard Worker		RBracePos:  x.RBracePos,
474*1fa6dee9SAndroid Build Coastguard Worker		Properties: newProps,
475*1fa6dee9SAndroid Build Coastguard Worker	}, nil
476*1fa6dee9SAndroid Build Coastguard Worker}
477*1fa6dee9SAndroid Build Coastguard Worker
478*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) PrintfInto(value string) error {
479*1fa6dee9SAndroid Build Coastguard Worker	// We should never reach this because selects cannot hold maps
480*1fa6dee9SAndroid Build Coastguard Worker	panic("printfinto() is unsupported on maps")
481*1fa6dee9SAndroid Build Coastguard Worker}
482*1fa6dee9SAndroid Build Coastguard Worker
483*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) MarkReferencedVariables(scope *Scope) {
484*1fa6dee9SAndroid Build Coastguard Worker	for _, prop := range x.Properties {
485*1fa6dee9SAndroid Build Coastguard Worker		prop.MarkReferencedVariables(scope)
486*1fa6dee9SAndroid Build Coastguard Worker	}
487*1fa6dee9SAndroid Build Coastguard Worker}
488*1fa6dee9SAndroid Build Coastguard Worker
489*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) String() string {
490*1fa6dee9SAndroid Build Coastguard Worker	propertyStrings := make([]string, len(x.Properties))
491*1fa6dee9SAndroid Build Coastguard Worker	for i, property := range x.Properties {
492*1fa6dee9SAndroid Build Coastguard Worker		propertyStrings[i] = property.String()
493*1fa6dee9SAndroid Build Coastguard Worker	}
494*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos,
495*1fa6dee9SAndroid Build Coastguard Worker		strings.Join(propertyStrings, ", "))
496*1fa6dee9SAndroid Build Coastguard Worker}
497*1fa6dee9SAndroid Build Coastguard Worker
498*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) Type() Type { return MapType }
499*1fa6dee9SAndroid Build Coastguard Worker
500*1fa6dee9SAndroid Build Coastguard Worker// GetProperty looks for a property with the given name.
501*1fa6dee9SAndroid Build Coastguard Worker// It resembles the bracket operator of a built-in Golang map.
502*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) GetProperty(name string) (Property *Property, found bool) {
503*1fa6dee9SAndroid Build Coastguard Worker	prop, found, _ := x.getPropertyImpl(name)
504*1fa6dee9SAndroid Build Coastguard Worker	return prop, found // we don't currently expose the index to callers
505*1fa6dee9SAndroid Build Coastguard Worker}
506*1fa6dee9SAndroid Build Coastguard Worker
507*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) {
508*1fa6dee9SAndroid Build Coastguard Worker	for i, prop := range x.Properties {
509*1fa6dee9SAndroid Build Coastguard Worker		if prop.Name == name {
510*1fa6dee9SAndroid Build Coastguard Worker			return prop, true, i
511*1fa6dee9SAndroid Build Coastguard Worker		}
512*1fa6dee9SAndroid Build Coastguard Worker	}
513*1fa6dee9SAndroid Build Coastguard Worker	return nil, false, -1
514*1fa6dee9SAndroid Build Coastguard Worker}
515*1fa6dee9SAndroid Build Coastguard Worker
516*1fa6dee9SAndroid Build Coastguard Worker// RemoveProperty removes the property with the given name, if it exists.
517*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) RemoveProperty(propertyName string) (removed bool) {
518*1fa6dee9SAndroid Build Coastguard Worker	_, found, index := x.getPropertyImpl(propertyName)
519*1fa6dee9SAndroid Build Coastguard Worker	if found {
520*1fa6dee9SAndroid Build Coastguard Worker		x.Properties = append(x.Properties[:index], x.Properties[index+1:]...)
521*1fa6dee9SAndroid Build Coastguard Worker	}
522*1fa6dee9SAndroid Build Coastguard Worker	return found
523*1fa6dee9SAndroid Build Coastguard Worker}
524*1fa6dee9SAndroid Build Coastguard Worker
525*1fa6dee9SAndroid Build Coastguard Worker// MovePropertyContents moves the contents of propertyName into property newLocation
526*1fa6dee9SAndroid Build Coastguard Worker// If property newLocation doesn't exist, MovePropertyContents renames propertyName as newLocation.
527*1fa6dee9SAndroid Build Coastguard Worker// Otherwise, MovePropertyContents only supports moving contents that are a List of String.
528*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Map) MovePropertyContents(propertyName string, newLocation string) (removed bool) {
529*1fa6dee9SAndroid Build Coastguard Worker	oldProp, oldFound, _ := x.getPropertyImpl(propertyName)
530*1fa6dee9SAndroid Build Coastguard Worker	newProp, newFound, _ := x.getPropertyImpl(newLocation)
531*1fa6dee9SAndroid Build Coastguard Worker
532*1fa6dee9SAndroid Build Coastguard Worker	// newLoc doesn't exist, simply renaming property
533*1fa6dee9SAndroid Build Coastguard Worker	if oldFound && !newFound {
534*1fa6dee9SAndroid Build Coastguard Worker		oldProp.Name = newLocation
535*1fa6dee9SAndroid Build Coastguard Worker		return oldFound
536*1fa6dee9SAndroid Build Coastguard Worker	}
537*1fa6dee9SAndroid Build Coastguard Worker
538*1fa6dee9SAndroid Build Coastguard Worker	if oldFound {
539*1fa6dee9SAndroid Build Coastguard Worker		old, oldOk := oldProp.Value.(*List)
540*1fa6dee9SAndroid Build Coastguard Worker		new, newOk := newProp.Value.(*List)
541*1fa6dee9SAndroid Build Coastguard Worker		if oldOk && newOk {
542*1fa6dee9SAndroid Build Coastguard Worker			toBeMoved := make([]string, len(old.Values)) //
543*1fa6dee9SAndroid Build Coastguard Worker			for i, p := range old.Values {
544*1fa6dee9SAndroid Build Coastguard Worker				toBeMoved[i] = p.(*String).Value
545*1fa6dee9SAndroid Build Coastguard Worker			}
546*1fa6dee9SAndroid Build Coastguard Worker
547*1fa6dee9SAndroid Build Coastguard Worker			for _, moved := range toBeMoved {
548*1fa6dee9SAndroid Build Coastguard Worker				RemoveStringFromList(old, moved)
549*1fa6dee9SAndroid Build Coastguard Worker				AddStringToList(new, moved)
550*1fa6dee9SAndroid Build Coastguard Worker			}
551*1fa6dee9SAndroid Build Coastguard Worker			// oldProp should now be empty and needs to be deleted
552*1fa6dee9SAndroid Build Coastguard Worker			x.RemoveProperty(oldProp.Name)
553*1fa6dee9SAndroid Build Coastguard Worker		} else {
554*1fa6dee9SAndroid Build Coastguard Worker			print(`MovePropertyContents currently only supports moving PropertyName
555*1fa6dee9SAndroid Build Coastguard Worker					with List of Strings into an existing newLocation with List of Strings\n`)
556*1fa6dee9SAndroid Build Coastguard Worker		}
557*1fa6dee9SAndroid Build Coastguard Worker	}
558*1fa6dee9SAndroid Build Coastguard Worker	return oldFound
559*1fa6dee9SAndroid Build Coastguard Worker}
560*1fa6dee9SAndroid Build Coastguard Worker
561*1fa6dee9SAndroid Build Coastguard Workertype List struct {
562*1fa6dee9SAndroid Build Coastguard Worker	LBracePos scanner.Position
563*1fa6dee9SAndroid Build Coastguard Worker	RBracePos scanner.Position
564*1fa6dee9SAndroid Build Coastguard Worker	Values    []Expression
565*1fa6dee9SAndroid Build Coastguard Worker}
566*1fa6dee9SAndroid Build Coastguard Worker
567*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Pos() scanner.Position { return x.LBracePos }
568*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) }
569*1fa6dee9SAndroid Build Coastguard Worker
570*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Copy() Expression {
571*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
572*1fa6dee9SAndroid Build Coastguard Worker	ret.Values = make([]Expression, len(x.Values))
573*1fa6dee9SAndroid Build Coastguard Worker	for i := range ret.Values {
574*1fa6dee9SAndroid Build Coastguard Worker		ret.Values[i] = x.Values[i].Copy()
575*1fa6dee9SAndroid Build Coastguard Worker	}
576*1fa6dee9SAndroid Build Coastguard Worker	return &ret
577*1fa6dee9SAndroid Build Coastguard Worker}
578*1fa6dee9SAndroid Build Coastguard Worker
579*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Eval(scope *Scope) (Expression, error) {
580*1fa6dee9SAndroid Build Coastguard Worker	newValues := make([]Expression, len(x.Values))
581*1fa6dee9SAndroid Build Coastguard Worker	for i, val := range x.Values {
582*1fa6dee9SAndroid Build Coastguard Worker		newVal, err := val.Eval(scope)
583*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
584*1fa6dee9SAndroid Build Coastguard Worker			return nil, err
585*1fa6dee9SAndroid Build Coastguard Worker		}
586*1fa6dee9SAndroid Build Coastguard Worker		newValues[i] = newVal
587*1fa6dee9SAndroid Build Coastguard Worker	}
588*1fa6dee9SAndroid Build Coastguard Worker	return &List{
589*1fa6dee9SAndroid Build Coastguard Worker		LBracePos: x.LBracePos,
590*1fa6dee9SAndroid Build Coastguard Worker		RBracePos: x.RBracePos,
591*1fa6dee9SAndroid Build Coastguard Worker		Values:    newValues,
592*1fa6dee9SAndroid Build Coastguard Worker	}, nil
593*1fa6dee9SAndroid Build Coastguard Worker}
594*1fa6dee9SAndroid Build Coastguard Worker
595*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) PrintfInto(value string) error {
596*1fa6dee9SAndroid Build Coastguard Worker	for _, val := range x.Values {
597*1fa6dee9SAndroid Build Coastguard Worker		if err := val.PrintfInto(value); err != nil {
598*1fa6dee9SAndroid Build Coastguard Worker			return err
599*1fa6dee9SAndroid Build Coastguard Worker		}
600*1fa6dee9SAndroid Build Coastguard Worker	}
601*1fa6dee9SAndroid Build Coastguard Worker	return nil
602*1fa6dee9SAndroid Build Coastguard Worker}
603*1fa6dee9SAndroid Build Coastguard Worker
604*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) MarkReferencedVariables(scope *Scope) {
605*1fa6dee9SAndroid Build Coastguard Worker	for _, val := range x.Values {
606*1fa6dee9SAndroid Build Coastguard Worker		val.MarkReferencedVariables(scope)
607*1fa6dee9SAndroid Build Coastguard Worker	}
608*1fa6dee9SAndroid Build Coastguard Worker}
609*1fa6dee9SAndroid Build Coastguard Worker
610*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) String() string {
611*1fa6dee9SAndroid Build Coastguard Worker	valueStrings := make([]string, len(x.Values))
612*1fa6dee9SAndroid Build Coastguard Worker	for i, value := range x.Values {
613*1fa6dee9SAndroid Build Coastguard Worker		valueStrings[i] = value.String()
614*1fa6dee9SAndroid Build Coastguard Worker	}
615*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos,
616*1fa6dee9SAndroid Build Coastguard Worker		strings.Join(valueStrings, ", "))
617*1fa6dee9SAndroid Build Coastguard Worker}
618*1fa6dee9SAndroid Build Coastguard Worker
619*1fa6dee9SAndroid Build Coastguard Workerfunc (x *List) Type() Type { return ListType }
620*1fa6dee9SAndroid Build Coastguard Worker
621*1fa6dee9SAndroid Build Coastguard Workertype String struct {
622*1fa6dee9SAndroid Build Coastguard Worker	LiteralPos scanner.Position
623*1fa6dee9SAndroid Build Coastguard Worker	Value      string
624*1fa6dee9SAndroid Build Coastguard Worker}
625*1fa6dee9SAndroid Build Coastguard Worker
626*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Pos() scanner.Position { return x.LiteralPos }
627*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) }
628*1fa6dee9SAndroid Build Coastguard Worker
629*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Copy() Expression {
630*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
631*1fa6dee9SAndroid Build Coastguard Worker	return &ret
632*1fa6dee9SAndroid Build Coastguard Worker}
633*1fa6dee9SAndroid Build Coastguard Worker
634*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Eval(scope *Scope) (Expression, error) {
635*1fa6dee9SAndroid Build Coastguard Worker	return x, nil
636*1fa6dee9SAndroid Build Coastguard Worker}
637*1fa6dee9SAndroid Build Coastguard Worker
638*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) PrintfInto(value string) error {
639*1fa6dee9SAndroid Build Coastguard Worker	count := strings.Count(x.Value, "%")
640*1fa6dee9SAndroid Build Coastguard Worker	if count == 0 {
641*1fa6dee9SAndroid Build Coastguard Worker		return nil
642*1fa6dee9SAndroid Build Coastguard Worker	}
643*1fa6dee9SAndroid Build Coastguard Worker
644*1fa6dee9SAndroid Build Coastguard Worker	if count > 1 {
645*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf("list/value variable properties only support a single '%%'")
646*1fa6dee9SAndroid Build Coastguard Worker	}
647*1fa6dee9SAndroid Build Coastguard Worker
648*1fa6dee9SAndroid Build Coastguard Worker	if !strings.Contains(x.Value, "%s") {
649*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf("unsupported %% in value variable property")
650*1fa6dee9SAndroid Build Coastguard Worker	}
651*1fa6dee9SAndroid Build Coastguard Worker
652*1fa6dee9SAndroid Build Coastguard Worker	x.Value = fmt.Sprintf(x.Value, value)
653*1fa6dee9SAndroid Build Coastguard Worker	return nil
654*1fa6dee9SAndroid Build Coastguard Worker}
655*1fa6dee9SAndroid Build Coastguard Worker
656*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) MarkReferencedVariables(scope *Scope) {
657*1fa6dee9SAndroid Build Coastguard Worker}
658*1fa6dee9SAndroid Build Coastguard Worker
659*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) String() string {
660*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
661*1fa6dee9SAndroid Build Coastguard Worker}
662*1fa6dee9SAndroid Build Coastguard Worker
663*1fa6dee9SAndroid Build Coastguard Workerfunc (x *String) Type() Type {
664*1fa6dee9SAndroid Build Coastguard Worker	return StringType
665*1fa6dee9SAndroid Build Coastguard Worker}
666*1fa6dee9SAndroid Build Coastguard Worker
667*1fa6dee9SAndroid Build Coastguard Workertype Int64 struct {
668*1fa6dee9SAndroid Build Coastguard Worker	LiteralPos scanner.Position
669*1fa6dee9SAndroid Build Coastguard Worker	Value      int64
670*1fa6dee9SAndroid Build Coastguard Worker	Token      string
671*1fa6dee9SAndroid Build Coastguard Worker}
672*1fa6dee9SAndroid Build Coastguard Worker
673*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Pos() scanner.Position { return x.LiteralPos }
674*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }
675*1fa6dee9SAndroid Build Coastguard Worker
676*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Copy() Expression {
677*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
678*1fa6dee9SAndroid Build Coastguard Worker	return &ret
679*1fa6dee9SAndroid Build Coastguard Worker}
680*1fa6dee9SAndroid Build Coastguard Worker
681*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Eval(scope *Scope) (Expression, error) {
682*1fa6dee9SAndroid Build Coastguard Worker	return x, nil
683*1fa6dee9SAndroid Build Coastguard Worker}
684*1fa6dee9SAndroid Build Coastguard Worker
685*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) PrintfInto(value string) error {
686*1fa6dee9SAndroid Build Coastguard Worker	return nil
687*1fa6dee9SAndroid Build Coastguard Worker}
688*1fa6dee9SAndroid Build Coastguard Worker
689*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) MarkReferencedVariables(scope *Scope) {
690*1fa6dee9SAndroid Build Coastguard Worker}
691*1fa6dee9SAndroid Build Coastguard Worker
692*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) String() string {
693*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
694*1fa6dee9SAndroid Build Coastguard Worker}
695*1fa6dee9SAndroid Build Coastguard Worker
696*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Int64) Type() Type {
697*1fa6dee9SAndroid Build Coastguard Worker	return Int64Type
698*1fa6dee9SAndroid Build Coastguard Worker}
699*1fa6dee9SAndroid Build Coastguard Worker
700*1fa6dee9SAndroid Build Coastguard Workertype Bool struct {
701*1fa6dee9SAndroid Build Coastguard Worker	LiteralPos scanner.Position
702*1fa6dee9SAndroid Build Coastguard Worker	Value      bool
703*1fa6dee9SAndroid Build Coastguard Worker	Token      string
704*1fa6dee9SAndroid Build Coastguard Worker}
705*1fa6dee9SAndroid Build Coastguard Worker
706*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Pos() scanner.Position { return x.LiteralPos }
707*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }
708*1fa6dee9SAndroid Build Coastguard Worker
709*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Copy() Expression {
710*1fa6dee9SAndroid Build Coastguard Worker	ret := *x
711*1fa6dee9SAndroid Build Coastguard Worker	return &ret
712*1fa6dee9SAndroid Build Coastguard Worker}
713*1fa6dee9SAndroid Build Coastguard Worker
714*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Eval(scope *Scope) (Expression, error) {
715*1fa6dee9SAndroid Build Coastguard Worker	return x, nil
716*1fa6dee9SAndroid Build Coastguard Worker}
717*1fa6dee9SAndroid Build Coastguard Worker
718*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) PrintfInto(value string) error {
719*1fa6dee9SAndroid Build Coastguard Worker	return nil
720*1fa6dee9SAndroid Build Coastguard Worker}
721*1fa6dee9SAndroid Build Coastguard Worker
722*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) MarkReferencedVariables(scope *Scope) {
723*1fa6dee9SAndroid Build Coastguard Worker}
724*1fa6dee9SAndroid Build Coastguard Worker
725*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) String() string {
726*1fa6dee9SAndroid Build Coastguard Worker	return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos)
727*1fa6dee9SAndroid Build Coastguard Worker}
728*1fa6dee9SAndroid Build Coastguard Worker
729*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Bool) Type() Type {
730*1fa6dee9SAndroid Build Coastguard Worker	return BoolType
731*1fa6dee9SAndroid Build Coastguard Worker}
732*1fa6dee9SAndroid Build Coastguard Worker
733*1fa6dee9SAndroid Build Coastguard Workertype CommentGroup struct {
734*1fa6dee9SAndroid Build Coastguard Worker	Comments []*Comment
735*1fa6dee9SAndroid Build Coastguard Worker}
736*1fa6dee9SAndroid Build Coastguard Worker
737*1fa6dee9SAndroid Build Coastguard Workerfunc (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() }
738*1fa6dee9SAndroid Build Coastguard Workerfunc (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() }
739*1fa6dee9SAndroid Build Coastguard Worker
740*1fa6dee9SAndroid Build Coastguard Workertype Comment struct {
741*1fa6dee9SAndroid Build Coastguard Worker	Comment []string
742*1fa6dee9SAndroid Build Coastguard Worker	Slash   scanner.Position
743*1fa6dee9SAndroid Build Coastguard Worker}
744*1fa6dee9SAndroid Build Coastguard Worker
745*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) Pos() scanner.Position {
746*1fa6dee9SAndroid Build Coastguard Worker	return c.Slash
747*1fa6dee9SAndroid Build Coastguard Worker}
748*1fa6dee9SAndroid Build Coastguard Worker
749*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) End() scanner.Position {
750*1fa6dee9SAndroid Build Coastguard Worker	pos := c.Slash
751*1fa6dee9SAndroid Build Coastguard Worker	for _, comment := range c.Comment {
752*1fa6dee9SAndroid Build Coastguard Worker		pos.Offset += len(comment) + 1
753*1fa6dee9SAndroid Build Coastguard Worker		pos.Column = len(comment) + 1
754*1fa6dee9SAndroid Build Coastguard Worker	}
755*1fa6dee9SAndroid Build Coastguard Worker	pos.Line += len(c.Comment) - 1
756*1fa6dee9SAndroid Build Coastguard Worker	return pos
757*1fa6dee9SAndroid Build Coastguard Worker}
758*1fa6dee9SAndroid Build Coastguard Worker
759*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) String() string {
760*1fa6dee9SAndroid Build Coastguard Worker	l := 0
761*1fa6dee9SAndroid Build Coastguard Worker	for _, comment := range c.Comment {
762*1fa6dee9SAndroid Build Coastguard Worker		l += len(comment) + 1
763*1fa6dee9SAndroid Build Coastguard Worker	}
764*1fa6dee9SAndroid Build Coastguard Worker	buf := make([]byte, 0, l)
765*1fa6dee9SAndroid Build Coastguard Worker	for _, comment := range c.Comment {
766*1fa6dee9SAndroid Build Coastguard Worker		buf = append(buf, comment...)
767*1fa6dee9SAndroid Build Coastguard Worker		buf = append(buf, '\n')
768*1fa6dee9SAndroid Build Coastguard Worker	}
769*1fa6dee9SAndroid Build Coastguard Worker
770*1fa6dee9SAndroid Build Coastguard Worker	return string(buf) + "@" + c.Slash.String()
771*1fa6dee9SAndroid Build Coastguard Worker}
772*1fa6dee9SAndroid Build Coastguard Worker
773*1fa6dee9SAndroid Build Coastguard Worker// Return the text of the comment with // or /* and */ stripped
774*1fa6dee9SAndroid Build Coastguard Workerfunc (c Comment) Text() string {
775*1fa6dee9SAndroid Build Coastguard Worker	l := 0
776*1fa6dee9SAndroid Build Coastguard Worker	for _, comment := range c.Comment {
777*1fa6dee9SAndroid Build Coastguard Worker		l += len(comment) + 1
778*1fa6dee9SAndroid Build Coastguard Worker	}
779*1fa6dee9SAndroid Build Coastguard Worker	buf := make([]byte, 0, l)
780*1fa6dee9SAndroid Build Coastguard Worker
781*1fa6dee9SAndroid Build Coastguard Worker	blockComment := false
782*1fa6dee9SAndroid Build Coastguard Worker	if strings.HasPrefix(c.Comment[0], "/*") {
783*1fa6dee9SAndroid Build Coastguard Worker		blockComment = true
784*1fa6dee9SAndroid Build Coastguard Worker	}
785*1fa6dee9SAndroid Build Coastguard Worker
786*1fa6dee9SAndroid Build Coastguard Worker	for i, comment := range c.Comment {
787*1fa6dee9SAndroid Build Coastguard Worker		if blockComment {
788*1fa6dee9SAndroid Build Coastguard Worker			if i == 0 {
789*1fa6dee9SAndroid Build Coastguard Worker				comment = strings.TrimPrefix(comment, "/*")
790*1fa6dee9SAndroid Build Coastguard Worker			}
791*1fa6dee9SAndroid Build Coastguard Worker			if i == len(c.Comment)-1 {
792*1fa6dee9SAndroid Build Coastguard Worker				comment = strings.TrimSuffix(comment, "*/")
793*1fa6dee9SAndroid Build Coastguard Worker			}
794*1fa6dee9SAndroid Build Coastguard Worker		} else {
795*1fa6dee9SAndroid Build Coastguard Worker			comment = strings.TrimPrefix(comment, "//")
796*1fa6dee9SAndroid Build Coastguard Worker		}
797*1fa6dee9SAndroid Build Coastguard Worker		buf = append(buf, comment...)
798*1fa6dee9SAndroid Build Coastguard Worker		buf = append(buf, '\n')
799*1fa6dee9SAndroid Build Coastguard Worker	}
800*1fa6dee9SAndroid Build Coastguard Worker
801*1fa6dee9SAndroid Build Coastguard Worker	return string(buf)
802*1fa6dee9SAndroid Build Coastguard Worker}
803*1fa6dee9SAndroid Build Coastguard Worker
804*1fa6dee9SAndroid Build Coastguard Workerfunc endPos(pos scanner.Position, n int) scanner.Position {
805*1fa6dee9SAndroid Build Coastguard Worker	pos.Offset += n
806*1fa6dee9SAndroid Build Coastguard Worker	pos.Column += n
807*1fa6dee9SAndroid Build Coastguard Worker	return pos
808*1fa6dee9SAndroid Build Coastguard Worker}
809*1fa6dee9SAndroid Build Coastguard Worker
810*1fa6dee9SAndroid Build Coastguard Workertype ConfigurableCondition struct {
811*1fa6dee9SAndroid Build Coastguard Worker	position     scanner.Position
812*1fa6dee9SAndroid Build Coastguard Worker	FunctionName string
813*1fa6dee9SAndroid Build Coastguard Worker	Args         []String
814*1fa6dee9SAndroid Build Coastguard Worker}
815*1fa6dee9SAndroid Build Coastguard Worker
816*1fa6dee9SAndroid Build Coastguard Workerfunc (c *ConfigurableCondition) Equals(other ConfigurableCondition) bool {
817*1fa6dee9SAndroid Build Coastguard Worker	if c.FunctionName != other.FunctionName {
818*1fa6dee9SAndroid Build Coastguard Worker		return false
819*1fa6dee9SAndroid Build Coastguard Worker	}
820*1fa6dee9SAndroid Build Coastguard Worker	if len(c.Args) != len(other.Args) {
821*1fa6dee9SAndroid Build Coastguard Worker		return false
822*1fa6dee9SAndroid Build Coastguard Worker	}
823*1fa6dee9SAndroid Build Coastguard Worker	for i := range c.Args {
824*1fa6dee9SAndroid Build Coastguard Worker		if c.Args[i] != other.Args[i] {
825*1fa6dee9SAndroid Build Coastguard Worker			return false
826*1fa6dee9SAndroid Build Coastguard Worker		}
827*1fa6dee9SAndroid Build Coastguard Worker	}
828*1fa6dee9SAndroid Build Coastguard Worker	return true
829*1fa6dee9SAndroid Build Coastguard Worker}
830*1fa6dee9SAndroid Build Coastguard Worker
831*1fa6dee9SAndroid Build Coastguard Workerfunc (c *ConfigurableCondition) String() string {
832*1fa6dee9SAndroid Build Coastguard Worker	var sb strings.Builder
833*1fa6dee9SAndroid Build Coastguard Worker	sb.WriteString(c.FunctionName)
834*1fa6dee9SAndroid Build Coastguard Worker	sb.WriteRune('(')
835*1fa6dee9SAndroid Build Coastguard Worker	for i, arg := range c.Args {
836*1fa6dee9SAndroid Build Coastguard Worker		sb.WriteRune('"')
837*1fa6dee9SAndroid Build Coastguard Worker		sb.WriteString(arg.Value)
838*1fa6dee9SAndroid Build Coastguard Worker		sb.WriteRune('"')
839*1fa6dee9SAndroid Build Coastguard Worker		if i < len(c.Args)-1 {
840*1fa6dee9SAndroid Build Coastguard Worker			sb.WriteString(", ")
841*1fa6dee9SAndroid Build Coastguard Worker		}
842*1fa6dee9SAndroid Build Coastguard Worker	}
843*1fa6dee9SAndroid Build Coastguard Worker	sb.WriteRune(')')
844*1fa6dee9SAndroid Build Coastguard Worker	return sb.String()
845*1fa6dee9SAndroid Build Coastguard Worker}
846*1fa6dee9SAndroid Build Coastguard Worker
847*1fa6dee9SAndroid Build Coastguard Workertype Select struct {
848*1fa6dee9SAndroid Build Coastguard Worker	Scope      *Scope           // scope used to evaluate the body of the select later on
849*1fa6dee9SAndroid Build Coastguard Worker	KeywordPos scanner.Position // the keyword "select"
850*1fa6dee9SAndroid Build Coastguard Worker	Conditions []ConfigurableCondition
851*1fa6dee9SAndroid Build Coastguard Worker	LBracePos  scanner.Position
852*1fa6dee9SAndroid Build Coastguard Worker	RBracePos  scanner.Position
853*1fa6dee9SAndroid Build Coastguard Worker	Cases      []*SelectCase // the case statements
854*1fa6dee9SAndroid Build Coastguard Worker	Append     Expression
855*1fa6dee9SAndroid Build Coastguard Worker}
856*1fa6dee9SAndroid Build Coastguard Worker
857*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Pos() scanner.Position { return s.KeywordPos }
858*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) End() scanner.Position { return endPos(s.RBracePos, 1) }
859*1fa6dee9SAndroid Build Coastguard Worker
860*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Copy() Expression {
861*1fa6dee9SAndroid Build Coastguard Worker	ret := *s
862*1fa6dee9SAndroid Build Coastguard Worker	ret.Cases = make([]*SelectCase, len(ret.Cases))
863*1fa6dee9SAndroid Build Coastguard Worker	for i, selectCase := range s.Cases {
864*1fa6dee9SAndroid Build Coastguard Worker		ret.Cases[i] = selectCase.Copy()
865*1fa6dee9SAndroid Build Coastguard Worker	}
866*1fa6dee9SAndroid Build Coastguard Worker	if s.Append != nil {
867*1fa6dee9SAndroid Build Coastguard Worker		ret.Append = s.Append.Copy()
868*1fa6dee9SAndroid Build Coastguard Worker	}
869*1fa6dee9SAndroid Build Coastguard Worker	return &ret
870*1fa6dee9SAndroid Build Coastguard Worker}
871*1fa6dee9SAndroid Build Coastguard Worker
872*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Eval(scope *Scope) (Expression, error) {
873*1fa6dee9SAndroid Build Coastguard Worker	s.Scope = scope
874*1fa6dee9SAndroid Build Coastguard Worker	s.MarkReferencedVariables(scope)
875*1fa6dee9SAndroid Build Coastguard Worker	return s, nil
876*1fa6dee9SAndroid Build Coastguard Worker}
877*1fa6dee9SAndroid Build Coastguard Worker
878*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Select) PrintfInto(value string) error {
879*1fa6dee9SAndroid Build Coastguard Worker	// PrintfInto will be handled at the Configurable object level
880*1fa6dee9SAndroid Build Coastguard Worker	panic("Cannot call PrintfInto on a select expression")
881*1fa6dee9SAndroid Build Coastguard Worker}
882*1fa6dee9SAndroid Build Coastguard Worker
883*1fa6dee9SAndroid Build Coastguard Workerfunc (x *Select) MarkReferencedVariables(scope *Scope) {
884*1fa6dee9SAndroid Build Coastguard Worker	for _, c := range x.Cases {
885*1fa6dee9SAndroid Build Coastguard Worker		c.MarkReferencedVariables(scope)
886*1fa6dee9SAndroid Build Coastguard Worker	}
887*1fa6dee9SAndroid Build Coastguard Worker	if x.Append != nil {
888*1fa6dee9SAndroid Build Coastguard Worker		x.Append.MarkReferencedVariables(scope)
889*1fa6dee9SAndroid Build Coastguard Worker	}
890*1fa6dee9SAndroid Build Coastguard Worker}
891*1fa6dee9SAndroid Build Coastguard Worker
892*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) String() string {
893*1fa6dee9SAndroid Build Coastguard Worker	return "<select>"
894*1fa6dee9SAndroid Build Coastguard Worker}
895*1fa6dee9SAndroid Build Coastguard Worker
896*1fa6dee9SAndroid Build Coastguard Workerfunc (s *Select) Type() Type {
897*1fa6dee9SAndroid Build Coastguard Worker	if len(s.Cases) == 0 {
898*1fa6dee9SAndroid Build Coastguard Worker		return UnsetType
899*1fa6dee9SAndroid Build Coastguard Worker	}
900*1fa6dee9SAndroid Build Coastguard Worker	return UnknownType
901*1fa6dee9SAndroid Build Coastguard Worker}
902*1fa6dee9SAndroid Build Coastguard Worker
903*1fa6dee9SAndroid Build Coastguard Workertype SelectPattern struct {
904*1fa6dee9SAndroid Build Coastguard Worker	Value   Expression
905*1fa6dee9SAndroid Build Coastguard Worker	Binding Variable
906*1fa6dee9SAndroid Build Coastguard Worker}
907*1fa6dee9SAndroid Build Coastguard Worker
908*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectPattern) Pos() scanner.Position { return c.Value.Pos() }
909*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectPattern) End() scanner.Position {
910*1fa6dee9SAndroid Build Coastguard Worker	if c.Binding.NamePos.IsValid() {
911*1fa6dee9SAndroid Build Coastguard Worker		return c.Binding.End()
912*1fa6dee9SAndroid Build Coastguard Worker	}
913*1fa6dee9SAndroid Build Coastguard Worker	return c.Value.End()
914*1fa6dee9SAndroid Build Coastguard Worker}
915*1fa6dee9SAndroid Build Coastguard Worker
916*1fa6dee9SAndroid Build Coastguard Workertype SelectCase struct {
917*1fa6dee9SAndroid Build Coastguard Worker	Patterns []SelectPattern
918*1fa6dee9SAndroid Build Coastguard Worker	ColonPos scanner.Position
919*1fa6dee9SAndroid Build Coastguard Worker	Value    Expression
920*1fa6dee9SAndroid Build Coastguard Worker}
921*1fa6dee9SAndroid Build Coastguard Worker
922*1fa6dee9SAndroid Build Coastguard Workerfunc (x *SelectCase) MarkReferencedVariables(scope *Scope) {
923*1fa6dee9SAndroid Build Coastguard Worker	x.Value.MarkReferencedVariables(scope)
924*1fa6dee9SAndroid Build Coastguard Worker}
925*1fa6dee9SAndroid Build Coastguard Worker
926*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) Copy() *SelectCase {
927*1fa6dee9SAndroid Build Coastguard Worker	ret := *c
928*1fa6dee9SAndroid Build Coastguard Worker	ret.Value = c.Value.Copy()
929*1fa6dee9SAndroid Build Coastguard Worker	return &ret
930*1fa6dee9SAndroid Build Coastguard Worker}
931*1fa6dee9SAndroid Build Coastguard Worker
932*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) String() string {
933*1fa6dee9SAndroid Build Coastguard Worker	return "<select case>"
934*1fa6dee9SAndroid Build Coastguard Worker}
935*1fa6dee9SAndroid Build Coastguard Worker
936*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) Pos() scanner.Position { return c.Patterns[0].Pos() }
937*1fa6dee9SAndroid Build Coastguard Workerfunc (c *SelectCase) End() scanner.Position { return c.Value.End() }
938*1fa6dee9SAndroid Build Coastguard Worker
939*1fa6dee9SAndroid Build Coastguard Worker// UnsetProperty is the expression type of the "unset" keyword that can be
940*1fa6dee9SAndroid Build Coastguard Worker// used in select statements to make the property unset. For example:
941*1fa6dee9SAndroid Build Coastguard Worker//
942*1fa6dee9SAndroid Build Coastguard Worker//	my_module_type {
943*1fa6dee9SAndroid Build Coastguard Worker//	  name: "foo",
944*1fa6dee9SAndroid Build Coastguard Worker//	  some_prop: select(soong_config_variable("my_namespace", "my_var"), {
945*1fa6dee9SAndroid Build Coastguard Worker//	    "foo": unset,
946*1fa6dee9SAndroid Build Coastguard Worker//	    "default": "bar",
947*1fa6dee9SAndroid Build Coastguard Worker//	  })
948*1fa6dee9SAndroid Build Coastguard Worker//	}
949*1fa6dee9SAndroid Build Coastguard Workertype UnsetProperty struct {
950*1fa6dee9SAndroid Build Coastguard Worker	Position scanner.Position
951*1fa6dee9SAndroid Build Coastguard Worker}
952*1fa6dee9SAndroid Build Coastguard Worker
953*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Copy() Expression {
954*1fa6dee9SAndroid Build Coastguard Worker	return &UnsetProperty{Position: n.Position}
955*1fa6dee9SAndroid Build Coastguard Worker}
956*1fa6dee9SAndroid Build Coastguard Worker
957*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) String() string {
958*1fa6dee9SAndroid Build Coastguard Worker	return "unset"
959*1fa6dee9SAndroid Build Coastguard Worker}
960*1fa6dee9SAndroid Build Coastguard Worker
961*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Type() Type {
962*1fa6dee9SAndroid Build Coastguard Worker	return UnsetType
963*1fa6dee9SAndroid Build Coastguard Worker}
964*1fa6dee9SAndroid Build Coastguard Worker
965*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Eval(scope *Scope) (Expression, error) {
966*1fa6dee9SAndroid Build Coastguard Worker	return n, nil
967*1fa6dee9SAndroid Build Coastguard Worker}
968*1fa6dee9SAndroid Build Coastguard Worker
969*1fa6dee9SAndroid Build Coastguard Workerfunc (x *UnsetProperty) PrintfInto(value string) error {
970*1fa6dee9SAndroid Build Coastguard Worker	return nil
971*1fa6dee9SAndroid Build Coastguard Worker}
972*1fa6dee9SAndroid Build Coastguard Worker
973*1fa6dee9SAndroid Build Coastguard Workerfunc (x *UnsetProperty) MarkReferencedVariables(scope *Scope) {
974*1fa6dee9SAndroid Build Coastguard Worker}
975*1fa6dee9SAndroid Build Coastguard Worker
976*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) Pos() scanner.Position { return n.Position }
977*1fa6dee9SAndroid Build Coastguard Workerfunc (n *UnsetProperty) End() scanner.Position { return n.Position }
978