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