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	"strings"
20	"text/scanner"
21)
22
23type Node interface {
24	// Pos returns the position of the first token in the Node
25	Pos() scanner.Position
26	// End returns the position of the character after the last token in the Node
27	End() scanner.Position
28}
29
30// Definition is an Assignment or a Module at the top level of a Blueprints file
31type Definition interface {
32	Node
33	String() string
34	definitionTag()
35}
36
37// An Assignment is a variable assignment at the top level of a Blueprints file, scoped to the
38// file and subdirs.
39type Assignment struct {
40	Name       string
41	NamePos    scanner.Position
42	Value      Expression
43	OrigValue  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 (%s) %t", a.Name, a.EqualsPos, a.Assigner, a.Value, a.OrigValue, 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
134// An Expression is a Value in a Property or Assignment.  It can be a literal (String or Bool), a
135// Map, a List, an Operator that combines two expressions of the same type, or a Variable that
136// references and Assignment.
137type Expression interface {
138	Node
139	// Copy returns a copy of the Expression that will not affect the original if mutated
140	Copy() Expression
141	String() string
142	// Type returns the underlying Type enum of the Expression if it were to be evaluated
143	Type() Type
144	// Eval returns an expression that is fully evaluated to a simple type (List, Map, String, or
145	// Bool).  It will return the same object for every call to Eval().
146	Eval() Expression
147}
148
149// ExpressionsAreSame tells whether the two values are the same Expression.
150// This includes the symbolic representation of each Expression but not their positions in the original source tree.
151// This does not apply any simplification to the expressions before comparing them
152// (for example, "!!a" wouldn't be deemed equal to "a")
153func ExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
154	return hackyExpressionsAreSame(a, b)
155}
156
157// TODO(jeffrygaston) once positions are removed from Expression structs,
158// remove this function and have callers use reflect.DeepEqual(a, b)
159func hackyExpressionsAreSame(a Expression, b Expression) (equal bool, err error) {
160	if a.Type() != b.Type() {
161		return false, nil
162	}
163	left, err := hackyFingerprint(a)
164	if err != nil {
165		return false, nil
166	}
167	right, err := hackyFingerprint(b)
168	if err != nil {
169		return false, nil
170	}
171	areEqual := string(left) == string(right)
172	return areEqual, nil
173}
174
175func hackyFingerprint(expression Expression) (fingerprint []byte, err error) {
176	assignment := &Assignment{"a", noPos, expression, expression, noPos, "=", false}
177	module := &File{}
178	module.Defs = append(module.Defs, assignment)
179	p := newPrinter(module)
180	return p.Print()
181}
182
183type Type int
184
185const (
186	BoolType Type = iota + 1
187	StringType
188	Int64Type
189	ListType
190	MapType
191	NotEvaluatedType
192	UnsetType
193)
194
195func (t Type) String() string {
196	switch t {
197	case BoolType:
198		return "bool"
199	case StringType:
200		return "string"
201	case Int64Type:
202		return "int64"
203	case ListType:
204		return "list"
205	case MapType:
206		return "map"
207	case NotEvaluatedType:
208		return "notevaluated"
209	case UnsetType:
210		return "unset"
211	default:
212		panic(fmt.Errorf("Unknown type %d", t))
213	}
214}
215
216type Operator struct {
217	Args        [2]Expression
218	Operator    rune
219	OperatorPos scanner.Position
220	Value       Expression
221}
222
223func (x *Operator) Copy() Expression {
224	ret := *x
225	ret.Args[0] = x.Args[0].Copy()
226	ret.Args[1] = x.Args[1].Copy()
227	return &ret
228}
229
230func (x *Operator) Eval() Expression {
231	return x.Value.Eval()
232}
233
234func (x *Operator) Type() Type {
235	return x.Args[0].Type()
236}
237
238func (x *Operator) Pos() scanner.Position { return x.Args[0].Pos() }
239func (x *Operator) End() scanner.Position { return x.Args[1].End() }
240
241func (x *Operator) String() string {
242	return fmt.Sprintf("(%s %c %s = %s)@%s", x.Args[0].String(), x.Operator, x.Args[1].String(),
243		x.Value, x.OperatorPos)
244}
245
246type Variable struct {
247	Name    string
248	NamePos scanner.Position
249	Value   Expression
250}
251
252func (x *Variable) Pos() scanner.Position { return x.NamePos }
253func (x *Variable) End() scanner.Position { return endPos(x.NamePos, len(x.Name)) }
254
255func (x *Variable) Copy() Expression {
256	ret := *x
257	return &ret
258}
259
260func (x *Variable) Eval() Expression {
261	return x.Value.Eval()
262}
263
264func (x *Variable) String() string {
265	return x.Name + " = " + x.Value.String()
266}
267
268func (x *Variable) Type() Type { return x.Value.Type() }
269
270type Map struct {
271	LBracePos  scanner.Position
272	RBracePos  scanner.Position
273	Properties []*Property
274}
275
276func (x *Map) Pos() scanner.Position { return x.LBracePos }
277func (x *Map) End() scanner.Position { return endPos(x.RBracePos, 1) }
278
279func (x *Map) Copy() Expression {
280	ret := *x
281	ret.Properties = make([]*Property, len(x.Properties))
282	for i := range x.Properties {
283		ret.Properties[i] = x.Properties[i].Copy()
284	}
285	return &ret
286}
287
288func (x *Map) Eval() Expression {
289	return x
290}
291
292func (x *Map) String() string {
293	propertyStrings := make([]string, len(x.Properties))
294	for i, property := range x.Properties {
295		propertyStrings[i] = property.String()
296	}
297	return fmt.Sprintf("@%s-%s{%s}", x.LBracePos, x.RBracePos,
298		strings.Join(propertyStrings, ", "))
299}
300
301func (x *Map) Type() Type { return MapType }
302
303// GetProperty looks for a property with the given name.
304// It resembles the bracket operator of a built-in Golang map.
305func (x *Map) GetProperty(name string) (Property *Property, found bool) {
306	prop, found, _ := x.getPropertyImpl(name)
307	return prop, found // we don't currently expose the index to callers
308}
309
310func (x *Map) getPropertyImpl(name string) (Property *Property, found bool, index int) {
311	for i, prop := range x.Properties {
312		if prop.Name == name {
313			return prop, true, i
314		}
315	}
316	return nil, false, -1
317}
318
319// RemoveProperty removes the property with the given name, if it exists.
320func (x *Map) RemoveProperty(propertyName string) (removed bool) {
321	_, found, index := x.getPropertyImpl(propertyName)
322	if found {
323		x.Properties = append(x.Properties[:index], x.Properties[index+1:]...)
324	}
325	return found
326}
327
328// MovePropertyContents moves the contents of propertyName into property newLocation
329// If property newLocation doesn't exist, MovePropertyContents renames propertyName as newLocation.
330// Otherwise, MovePropertyContents only supports moving contents that are a List of String.
331func (x *Map) MovePropertyContents(propertyName string, newLocation string) (removed bool) {
332	oldProp, oldFound, _ := x.getPropertyImpl(propertyName)
333	newProp, newFound, _ := x.getPropertyImpl(newLocation)
334
335	// newLoc doesn't exist, simply renaming property
336	if oldFound && !newFound {
337		oldProp.Name = newLocation
338		return oldFound
339	}
340
341	if oldFound {
342		old, oldOk := oldProp.Value.(*List)
343		new, newOk := newProp.Value.(*List)
344		if oldOk && newOk {
345			toBeMoved := make([]string, len(old.Values)) //
346			for i, p := range old.Values {
347				toBeMoved[i] = p.(*String).Value
348			}
349
350			for _, moved := range toBeMoved {
351				RemoveStringFromList(old, moved)
352				AddStringToList(new, moved)
353			}
354			// oldProp should now be empty and needs to be deleted
355			x.RemoveProperty(oldProp.Name)
356		} else {
357			print(`MovePropertyContents currently only supports moving PropertyName
358					with List of Strings into an existing newLocation with List of Strings\n`)
359		}
360	}
361	return oldFound
362}
363
364type List struct {
365	LBracePos scanner.Position
366	RBracePos scanner.Position
367	Values    []Expression
368}
369
370func (x *List) Pos() scanner.Position { return x.LBracePos }
371func (x *List) End() scanner.Position { return endPos(x.RBracePos, 1) }
372
373func (x *List) Copy() Expression {
374	ret := *x
375	ret.Values = make([]Expression, len(x.Values))
376	for i := range ret.Values {
377		ret.Values[i] = x.Values[i].Copy()
378	}
379	return &ret
380}
381
382func (x *List) Eval() Expression {
383	return x
384}
385
386func (x *List) String() string {
387	valueStrings := make([]string, len(x.Values))
388	for i, value := range x.Values {
389		valueStrings[i] = value.String()
390	}
391	return fmt.Sprintf("@%s-%s[%s]", x.LBracePos, x.RBracePos,
392		strings.Join(valueStrings, ", "))
393}
394
395func (x *List) Type() Type { return ListType }
396
397type String struct {
398	LiteralPos scanner.Position
399	Value      string
400}
401
402func (x *String) Pos() scanner.Position { return x.LiteralPos }
403func (x *String) End() scanner.Position { return endPos(x.LiteralPos, len(x.Value)+2) }
404
405func (x *String) Copy() Expression {
406	ret := *x
407	return &ret
408}
409
410func (x *String) Eval() Expression {
411	return x
412}
413
414func (x *String) String() string {
415	return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
416}
417
418func (x *String) Type() Type {
419	return StringType
420}
421
422type Int64 struct {
423	LiteralPos scanner.Position
424	Value      int64
425	Token      string
426}
427
428func (x *Int64) Pos() scanner.Position { return x.LiteralPos }
429func (x *Int64) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }
430
431func (x *Int64) Copy() Expression {
432	ret := *x
433	return &ret
434}
435
436func (x *Int64) Eval() Expression {
437	return x
438}
439
440func (x *Int64) String() string {
441	return fmt.Sprintf("%q@%s", x.Value, x.LiteralPos)
442}
443
444func (x *Int64) Type() Type {
445	return Int64Type
446}
447
448type Bool struct {
449	LiteralPos scanner.Position
450	Value      bool
451	Token      string
452}
453
454func (x *Bool) Pos() scanner.Position { return x.LiteralPos }
455func (x *Bool) End() scanner.Position { return endPos(x.LiteralPos, len(x.Token)) }
456
457func (x *Bool) Copy() Expression {
458	ret := *x
459	return &ret
460}
461
462func (x *Bool) Eval() Expression {
463	return x
464}
465
466func (x *Bool) String() string {
467	return fmt.Sprintf("%t@%s", x.Value, x.LiteralPos)
468}
469
470func (x *Bool) Type() Type {
471	return BoolType
472}
473
474type CommentGroup struct {
475	Comments []*Comment
476}
477
478func (x *CommentGroup) Pos() scanner.Position { return x.Comments[0].Pos() }
479func (x *CommentGroup) End() scanner.Position { return x.Comments[len(x.Comments)-1].End() }
480
481type Comment struct {
482	Comment []string
483	Slash   scanner.Position
484}
485
486func (c Comment) Pos() scanner.Position {
487	return c.Slash
488}
489
490func (c Comment) End() scanner.Position {
491	pos := c.Slash
492	for _, comment := range c.Comment {
493		pos.Offset += len(comment) + 1
494		pos.Column = len(comment) + 1
495	}
496	pos.Line += len(c.Comment) - 1
497	return pos
498}
499
500func (c Comment) String() string {
501	l := 0
502	for _, comment := range c.Comment {
503		l += len(comment) + 1
504	}
505	buf := make([]byte, 0, l)
506	for _, comment := range c.Comment {
507		buf = append(buf, comment...)
508		buf = append(buf, '\n')
509	}
510
511	return string(buf) + "@" + c.Slash.String()
512}
513
514// Return the text of the comment with // or /* and */ stripped
515func (c Comment) Text() string {
516	l := 0
517	for _, comment := range c.Comment {
518		l += len(comment) + 1
519	}
520	buf := make([]byte, 0, l)
521
522	blockComment := false
523	if strings.HasPrefix(c.Comment[0], "/*") {
524		blockComment = true
525	}
526
527	for i, comment := range c.Comment {
528		if blockComment {
529			if i == 0 {
530				comment = strings.TrimPrefix(comment, "/*")
531			}
532			if i == len(c.Comment)-1 {
533				comment = strings.TrimSuffix(comment, "*/")
534			}
535		} else {
536			comment = strings.TrimPrefix(comment, "//")
537		}
538		buf = append(buf, comment...)
539		buf = append(buf, '\n')
540	}
541
542	return string(buf)
543}
544
545type NotEvaluated struct {
546	Position scanner.Position
547}
548
549func (n NotEvaluated) Copy() Expression {
550	return NotEvaluated{Position: n.Position}
551}
552
553func (n NotEvaluated) String() string {
554	return "Not Evaluated"
555}
556
557func (n NotEvaluated) Type() Type {
558	return NotEvaluatedType
559}
560
561func (n NotEvaluated) Eval() Expression {
562	return NotEvaluated{Position: n.Position}
563}
564
565func (n NotEvaluated) Pos() scanner.Position { return n.Position }
566func (n NotEvaluated) End() scanner.Position { return n.Position }
567
568func endPos(pos scanner.Position, n int) scanner.Position {
569	pos.Offset += n
570	pos.Column += n
571	return pos
572}
573
574type ConfigurableCondition struct {
575	position     scanner.Position
576	FunctionName string
577	Args         []String
578}
579
580func (c *ConfigurableCondition) Equals(other ConfigurableCondition) bool {
581	if c.FunctionName != other.FunctionName {
582		return false
583	}
584	if len(c.Args) != len(other.Args) {
585		return false
586	}
587	for i := range c.Args {
588		if c.Args[i] != other.Args[i] {
589			return false
590		}
591	}
592	return true
593}
594
595func (c *ConfigurableCondition) String() string {
596	var sb strings.Builder
597	sb.WriteString(c.FunctionName)
598	sb.WriteRune('(')
599	for i, arg := range c.Args {
600		sb.WriteRune('"')
601		sb.WriteString(arg.Value)
602		sb.WriteRune('"')
603		if i < len(c.Args)-1 {
604			sb.WriteString(", ")
605		}
606	}
607	sb.WriteRune(')')
608	return sb.String()
609}
610
611type Select struct {
612	KeywordPos     scanner.Position // the keyword "select"
613	Conditions     []ConfigurableCondition
614	LBracePos      scanner.Position
615	RBracePos      scanner.Position
616	Cases          []*SelectCase // the case statements
617	Append         Expression
618	ExpressionType Type
619}
620
621func (s *Select) Pos() scanner.Position { return s.KeywordPos }
622func (s *Select) End() scanner.Position { return endPos(s.RBracePos, 1) }
623
624func (s *Select) Copy() Expression {
625	ret := *s
626	ret.Cases = make([]*SelectCase, len(ret.Cases))
627	for i, selectCase := range s.Cases {
628		ret.Cases[i] = selectCase.Copy()
629	}
630	if s.Append != nil {
631		ret.Append = s.Append.Copy()
632	}
633	return &ret
634}
635
636func (s *Select) Eval() Expression {
637	return s
638}
639
640func (s *Select) String() string {
641	return "<select>"
642}
643
644func (s *Select) Type() Type {
645	if s.ExpressionType == UnsetType && s.Append != nil {
646		return s.Append.Type()
647	}
648	return s.ExpressionType
649}
650
651type SelectCase struct {
652	Patterns []Expression
653	ColonPos scanner.Position
654	Value    Expression
655}
656
657func (c *SelectCase) Copy() *SelectCase {
658	ret := *c
659	ret.Value = c.Value.Copy()
660	return &ret
661}
662
663func (c *SelectCase) String() string {
664	return "<select case>"
665}
666
667func (c *SelectCase) Pos() scanner.Position { return c.Patterns[0].Pos() }
668func (c *SelectCase) End() scanner.Position { return c.Value.End() }
669
670// UnsetProperty is the expression type of the "unset" keyword that can be
671// used in select statements to make the property unset. For example:
672//
673//	my_module_type {
674//	  name: "foo",
675//	  some_prop: select(soong_config_variable("my_namespace", "my_var"), {
676//	    "foo": unset,
677//	    "default": "bar",
678//	  })
679//	}
680type UnsetProperty struct {
681	Position scanner.Position
682}
683
684func (n UnsetProperty) Copy() Expression {
685	return UnsetProperty{Position: n.Position}
686}
687
688func (n UnsetProperty) String() string {
689	return "unset"
690}
691
692func (n UnsetProperty) Type() Type {
693	return UnsetType
694}
695
696func (n UnsetProperty) Eval() Expression {
697	return UnsetProperty{Position: n.Position}
698}
699
700func (n UnsetProperty) Pos() scanner.Position { return n.Position }
701func (n UnsetProperty) End() scanner.Position { return n.Position }
702