xref: /aosp_15_r20/build/blueprint/parser/parser.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1// Copyright 2014 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	"errors"
19	"fmt"
20	"io"
21	"sort"
22	"strconv"
23	"strings"
24	"text/scanner"
25)
26
27var errTooManyErrors = errors.New("too many errors")
28
29const maxErrors = 1
30
31const default_select_branch_name = "__soong_conditions_default__"
32const any_select_branch_name = "__soong_conditions_any__"
33
34type ParseError struct {
35	Err error
36	Pos scanner.Position
37}
38
39func (e *ParseError) Error() string {
40	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
41}
42
43type File struct {
44	Name     string
45	Defs     []Definition
46	Comments []*CommentGroup
47}
48
49func parse(p *parser) (file *File, errs []error) {
50	defer func() {
51		if r := recover(); r != nil {
52			if r == errTooManyErrors {
53				errs = p.errors
54				return
55			}
56			panic(r)
57		}
58	}()
59
60	p.next()
61	defs := p.parseDefinitions()
62	p.accept(scanner.EOF)
63	errs = p.errors
64	comments := p.comments
65
66	return &File{
67		Name:     p.scanner.Filename,
68		Defs:     defs,
69		Comments: comments,
70	}, errs
71
72}
73
74func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
75	file, errs = Parse(filename, r)
76	if len(errs) > 0 {
77		return nil, errs
78	}
79
80	// evaluate all module properties
81	var newDefs []Definition
82	for _, def := range file.Defs {
83		switch d := def.(type) {
84		case *Module:
85			for _, prop := range d.Map.Properties {
86				newval, err := prop.Value.Eval(scope)
87				if err != nil {
88					return nil, []error{err}
89				}
90				switch newval.(type) {
91				case *String, *Bool, *Int64, *Select, *Map, *List:
92					// ok
93				default:
94					panic(fmt.Sprintf("Evaled but got %#v\n", newval))
95				}
96				prop.Value = newval
97			}
98			newDefs = append(newDefs, d)
99		case *Assignment:
100			if err := scope.HandleAssignment(d); err != nil {
101				return nil, []error{err}
102			}
103		}
104	}
105
106	// This is not strictly necessary, but removing the assignments from
107	// the result makes it clearer that this is an evaluated file.
108	// We could also consider adding a "EvaluatedFile" type to return.
109	file.Defs = newDefs
110
111	return file, nil
112}
113
114func Parse(filename string, r io.Reader) (file *File, errs []error) {
115	p := newParser(r)
116	p.scanner.Filename = filename
117
118	return parse(p)
119}
120
121func ParseExpression(r io.Reader) (value Expression, errs []error) {
122	p := newParser(r)
123	p.next()
124	value = p.parseExpression()
125	p.accept(scanner.EOF)
126	errs = p.errors
127	return
128}
129
130type parser struct {
131	scanner  scanner.Scanner
132	tok      rune
133	errors   []error
134	comments []*CommentGroup
135}
136
137func newParser(r io.Reader) *parser {
138	p := &parser{}
139	p.scanner.Init(r)
140	p.scanner.Error = func(sc *scanner.Scanner, msg string) {
141		p.errorf(msg)
142	}
143	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings |
144		scanner.ScanRawStrings | scanner.ScanComments
145	return p
146}
147
148func (p *parser) error(err error) {
149	pos := p.scanner.Position
150	if !pos.IsValid() {
151		pos = p.scanner.Pos()
152	}
153	err = &ParseError{
154		Err: err,
155		Pos: pos,
156	}
157	p.errors = append(p.errors, err)
158	if len(p.errors) >= maxErrors {
159		panic(errTooManyErrors)
160	}
161}
162
163func (p *parser) errorf(format string, args ...interface{}) {
164	p.error(fmt.Errorf(format, args...))
165}
166
167func (p *parser) accept(toks ...rune) bool {
168	for _, tok := range toks {
169		if p.tok != tok {
170			p.errorf("expected %s, found %s", scanner.TokenString(tok),
171				scanner.TokenString(p.tok))
172			return false
173		}
174		p.next()
175	}
176	return true
177}
178
179func (p *parser) next() {
180	if p.tok != scanner.EOF {
181		p.tok = p.scanner.Scan()
182		if p.tok == scanner.Comment {
183			var comments []*Comment
184			for p.tok == scanner.Comment {
185				lines := strings.Split(p.scanner.TokenText(), "\n")
186				if len(comments) > 0 && p.scanner.Position.Line > comments[len(comments)-1].End().Line+1 {
187					p.comments = append(p.comments, &CommentGroup{Comments: comments})
188					comments = nil
189				}
190				comments = append(comments, &Comment{lines, p.scanner.Position})
191				p.tok = p.scanner.Scan()
192			}
193			p.comments = append(p.comments, &CommentGroup{Comments: comments})
194		}
195	}
196}
197
198func (p *parser) parseDefinitions() (defs []Definition) {
199	for {
200		switch p.tok {
201		case scanner.Ident:
202			ident := p.scanner.TokenText()
203			pos := p.scanner.Position
204
205			p.accept(scanner.Ident)
206
207			switch p.tok {
208			case '+':
209				p.accept('+')
210				defs = append(defs, p.parseAssignment(ident, pos, "+="))
211			case '=':
212				defs = append(defs, p.parseAssignment(ident, pos, "="))
213			case '{', '(':
214				defs = append(defs, p.parseModule(ident, pos))
215			default:
216				p.errorf("expected \"=\" or \"+=\" or \"{\" or \"(\", found %s",
217					scanner.TokenString(p.tok))
218			}
219		case scanner.EOF:
220			return
221		default:
222			p.errorf("expected assignment or module definition, found %s",
223				scanner.TokenString(p.tok))
224			return
225		}
226	}
227}
228
229func (p *parser) parseAssignment(name string, namePos scanner.Position,
230	assigner string) (assignment *Assignment) {
231
232	// These are used as keywords in select statements, prevent making variables
233	// with the same name to avoid any confusion.
234	switch name {
235	case "default", "unset":
236		p.errorf("'default' and 'unset' are reserved keywords, and cannot be used as variable names")
237		return nil
238	}
239
240	assignment = new(Assignment)
241
242	pos := p.scanner.Position
243	if !p.accept('=') {
244		return
245	}
246	value := p.parseExpression()
247
248	assignment.Name = name
249	assignment.NamePos = namePos
250	assignment.Value = value
251	assignment.EqualsPos = pos
252	assignment.Assigner = assigner
253
254	return
255}
256
257func (p *parser) parseModule(typ string, typPos scanner.Position) *Module {
258
259	compat := false
260	lbracePos := p.scanner.Position
261	if p.tok == '{' {
262		compat = true
263	}
264
265	if !p.accept(p.tok) {
266		return nil
267	}
268	properties := p.parsePropertyList(true, compat)
269	rbracePos := p.scanner.Position
270	if !compat {
271		p.accept(')')
272	} else {
273		p.accept('}')
274	}
275
276	return &Module{
277		Type:    typ,
278		TypePos: typPos,
279		Map: Map{
280			Properties: properties,
281			LBracePos:  lbracePos,
282			RBracePos:  rbracePos,
283		},
284	}
285}
286
287func (p *parser) parsePropertyList(isModule, compat bool) (properties []*Property) {
288	for p.tok == scanner.Ident {
289		properties = append(properties, p.parseProperty(isModule, compat))
290
291		if p.tok != ',' {
292			// There was no comma, so the list is done.
293			break
294		}
295
296		p.accept(',')
297	}
298
299	return
300}
301
302func (p *parser) parseProperty(isModule, compat bool) (property *Property) {
303	property = new(Property)
304
305	name := p.scanner.TokenText()
306	namePos := p.scanner.Position
307	p.accept(scanner.Ident)
308	pos := p.scanner.Position
309
310	if isModule {
311		if compat {
312			if !p.accept(':') {
313				return
314			}
315		} else {
316			if !p.accept('=') {
317				return
318			}
319		}
320	} else {
321		if !p.accept(':') {
322			return
323		}
324	}
325
326	value := p.parseExpression()
327
328	property.Name = name
329	property.NamePos = namePos
330	property.Value = value
331	property.ColonPos = pos
332
333	return
334}
335
336func (p *parser) parseExpression() (value Expression) {
337	value = p.parseValue()
338	switch p.tok {
339	case '+':
340		return p.parseOperator(value)
341	case '-':
342		p.errorf("subtraction not supported: %s", p.scanner.String())
343		return value
344	default:
345		return value
346	}
347}
348
349func (p *parser) parseOperator(value1 Expression) Expression {
350	operator := p.tok
351	pos := p.scanner.Position
352	p.accept(operator)
353
354	value2 := p.parseExpression()
355
356	return &Operator{
357		Args:        [2]Expression{value1, value2},
358		Operator:    operator,
359		OperatorPos: pos,
360	}
361}
362
363func (p *parser) parseValue() (value Expression) {
364	switch p.tok {
365	case scanner.Ident:
366		switch text := p.scanner.TokenText(); text {
367		case "true", "false":
368			return p.parseBoolean()
369		case "select":
370			return p.parseSelect()
371		default:
372			return p.parseVariable()
373		}
374	case '-', scanner.Int: // Integer might have '-' sign ahead ('+' is only treated as operator now)
375		return p.parseIntValue()
376	case scanner.String, scanner.RawString:
377		return p.parseStringValue()
378	case '[':
379		return p.parseListValue()
380	case '{':
381		return p.parseMapValue()
382	default:
383		p.errorf("expected bool, list, or string value; found %s",
384			scanner.TokenString(p.tok))
385		return
386	}
387}
388
389func (p *parser) parseBoolean() Expression {
390	switch text := p.scanner.TokenText(); text {
391	case "true", "false":
392		result := &Bool{
393			LiteralPos: p.scanner.Position,
394			Value:      text == "true",
395			Token:      text,
396		}
397		p.accept(scanner.Ident)
398		return result
399	default:
400		p.errorf("Expected true/false, got %q", text)
401		return nil
402	}
403}
404
405func (p *parser) parseVariable() Expression {
406	var value Expression
407
408	text := p.scanner.TokenText()
409	value = &Variable{
410		Name:    text,
411		NamePos: p.scanner.Position,
412	}
413
414	p.accept(scanner.Ident)
415	return value
416}
417
418func (p *parser) parseSelect() Expression {
419	result := &Select{
420		KeywordPos: p.scanner.Position,
421	}
422	// Read the "select("
423	p.accept(scanner.Ident)
424	if !p.accept('(') {
425		return nil
426	}
427
428	// If we see another '(', there's probably multiple conditions and there must
429	// be a ')' after. Set the multipleConditions variable to remind us to check for
430	// the ')' after.
431	multipleConditions := false
432	if p.tok == '(' {
433		multipleConditions = true
434		p.accept('(')
435	}
436
437	// Read all individual conditions
438	conditions := []ConfigurableCondition{}
439	for first := true; first || multipleConditions; first = false {
440		condition := ConfigurableCondition{
441			position:     p.scanner.Position,
442			FunctionName: p.scanner.TokenText(),
443		}
444		if !p.accept(scanner.Ident) {
445			return nil
446		}
447		if !p.accept('(') {
448			return nil
449		}
450
451		for p.tok != ')' {
452			if s := p.parseStringValue(); s != nil {
453				condition.Args = append(condition.Args, *s)
454			} else {
455				return nil
456			}
457			if p.tok == ')' {
458				break
459			}
460			if !p.accept(',') {
461				return nil
462			}
463		}
464		p.accept(')')
465
466		for _, c := range conditions {
467			if c.Equals(condition) {
468				p.errorf("Duplicate select condition found: %s", c.String())
469			}
470		}
471
472		conditions = append(conditions, condition)
473
474		if multipleConditions {
475			if p.tok == ')' {
476				p.next()
477				break
478			}
479			if !p.accept(',') {
480				return nil
481			}
482			// Retry the closing parent to allow for a trailing comma
483			if p.tok == ')' {
484				p.next()
485				break
486			}
487		}
488	}
489
490	if multipleConditions && len(conditions) < 2 {
491		p.errorf("Expected multiple select conditions due to the extra parenthesis, but only found 1. Please remove the extra parenthesis.")
492		return nil
493	}
494
495	result.Conditions = conditions
496
497	if !p.accept(',') {
498		return nil
499	}
500
501	result.LBracePos = p.scanner.Position
502	if !p.accept('{') {
503		return nil
504	}
505
506	maybeParseBinding := func() (Variable, bool) {
507		if p.scanner.TokenText() != "@" {
508			return Variable{}, false
509		}
510		p.next()
511		value := Variable{
512			Name:    p.scanner.TokenText(),
513			NamePos: p.scanner.Position,
514		}
515		p.accept(scanner.Ident)
516		return value, true
517	}
518
519	parseOnePattern := func() SelectPattern {
520		var result SelectPattern
521		switch p.tok {
522		case scanner.Ident:
523			switch p.scanner.TokenText() {
524			case "any":
525				result.Value = &String{
526					LiteralPos: p.scanner.Position,
527					Value:      any_select_branch_name,
528				}
529				p.next()
530				if binding, exists := maybeParseBinding(); exists {
531					result.Binding = binding
532				}
533				return result
534			case "default":
535				result.Value = &String{
536					LiteralPos: p.scanner.Position,
537					Value:      default_select_branch_name,
538				}
539				p.next()
540				return result
541			case "true":
542				result.Value = &Bool{
543					LiteralPos: p.scanner.Position,
544					Value:      true,
545				}
546				p.next()
547				return result
548			case "false":
549				result.Value = &Bool{
550					LiteralPos: p.scanner.Position,
551					Value:      false,
552				}
553				p.next()
554				return result
555			default:
556				p.errorf("Expected a string, true, false, or default, got %s", p.scanner.TokenText())
557			}
558		case scanner.String:
559			if s := p.parseStringValue(); s != nil {
560				if strings.HasPrefix(s.Value, "__soong") {
561					p.errorf("select branch patterns starting with __soong are reserved for internal use")
562					return result
563				}
564				result.Value = s
565				return result
566			}
567			fallthrough
568		default:
569			p.errorf("Expected a string, true, false, or default, got %s", p.scanner.TokenText())
570		}
571		return result
572	}
573
574	hasNonUnsetValue := false
575	for p.tok != '}' {
576		c := &SelectCase{}
577
578		if multipleConditions {
579			if !p.accept('(') {
580				return nil
581			}
582			for i := 0; i < len(conditions); i++ {
583				c.Patterns = append(c.Patterns, parseOnePattern())
584				if i < len(conditions)-1 {
585					if !p.accept(',') {
586						return nil
587					}
588				} else if p.tok == ',' {
589					// allow optional trailing comma
590					p.next()
591				}
592			}
593			if !p.accept(')') {
594				return nil
595			}
596		} else {
597			c.Patterns = append(c.Patterns, parseOnePattern())
598		}
599		c.ColonPos = p.scanner.Position
600		if !p.accept(':') {
601			return nil
602		}
603		if p.tok == scanner.Ident && p.scanner.TokenText() == "unset" {
604			c.Value = &UnsetProperty{Position: p.scanner.Position}
605			p.accept(scanner.Ident)
606		} else {
607			hasNonUnsetValue = true
608			c.Value = p.parseExpression()
609		}
610		// allow trailing comma, require it if not seeing a }
611		if p.tok != '}' {
612			if !p.accept(',') {
613				return nil
614			}
615		}
616		result.Cases = append(result.Cases, c)
617	}
618
619	// If all branches have the value "unset", then this is equivalent
620	// to an empty select.
621	if !hasNonUnsetValue {
622		p.errorf("This select statement is empty, remove it")
623		return nil
624	}
625
626	patternsEqual := func(a, b SelectPattern) bool {
627		// We can ignore the bindings, they don't affect which pattern is matched
628		switch a2 := a.Value.(type) {
629		case *String:
630			if b2, ok := b.Value.(*String); ok {
631				return a2.Value == b2.Value
632			} else {
633				return false
634			}
635		case *Bool:
636			if b2, ok := b.Value.(*Bool); ok {
637				return a2.Value == b2.Value
638			} else {
639				return false
640			}
641		default:
642			// true so that we produce an error in this unexpected scenario
643			return true
644		}
645	}
646
647	patternListsEqual := func(a, b []SelectPattern) bool {
648		if len(a) != len(b) {
649			return false
650		}
651		for i := range a {
652			if !patternsEqual(a[i], b[i]) {
653				return false
654			}
655		}
656		return true
657	}
658
659	for i, c := range result.Cases {
660		// Check for duplicate patterns across different branches
661		for _, d := range result.Cases[i+1:] {
662			if patternListsEqual(c.Patterns, d.Patterns) {
663				p.errorf("Found duplicate select patterns: %v", c.Patterns)
664				return nil
665			}
666		}
667		// check for duplicate bindings within this branch
668		for i := range c.Patterns {
669			if c.Patterns[i].Binding.Name != "" {
670				for j := i + 1; j < len(c.Patterns); j++ {
671					if c.Patterns[i].Binding.Name == c.Patterns[j].Binding.Name {
672						p.errorf("Found duplicate select pattern binding: %s", c.Patterns[i].Binding.Name)
673						return nil
674					}
675				}
676			}
677		}
678		// Check that the only all-default cases is the last one
679		if i < len(result.Cases)-1 {
680			isAllDefault := true
681			for _, x := range c.Patterns {
682				if x2, ok := x.Value.(*String); !ok || x2.Value != default_select_branch_name {
683					isAllDefault = false
684					break
685				}
686			}
687			if isAllDefault {
688				p.errorf("Found a default select branch at index %d, expected it to be last (index %d)", i, len(result.Cases)-1)
689				return nil
690			}
691		}
692	}
693
694	result.RBracePos = p.scanner.Position
695	if !p.accept('}') {
696		return nil
697	}
698	if !p.accept(')') {
699		return nil
700	}
701	return result
702}
703
704func (p *parser) parseStringValue() *String {
705	str, err := strconv.Unquote(p.scanner.TokenText())
706	if err != nil {
707		p.errorf("couldn't parse string: %s", err)
708		return nil
709	}
710
711	value := &String{
712		LiteralPos: p.scanner.Position,
713		Value:      str,
714	}
715	p.accept(p.tok)
716	return value
717}
718
719func (p *parser) parseIntValue() *Int64 {
720	var str string
721	literalPos := p.scanner.Position
722	if p.tok == '-' {
723		str += string(p.tok)
724		p.accept(p.tok)
725		if p.tok != scanner.Int {
726			p.errorf("expected int; found %s", scanner.TokenString(p.tok))
727			return nil
728		}
729	}
730	str += p.scanner.TokenText()
731	i, err := strconv.ParseInt(str, 10, 64)
732	if err != nil {
733		p.errorf("couldn't parse int: %s", err)
734		return nil
735	}
736
737	value := &Int64{
738		LiteralPos: literalPos,
739		Value:      i,
740		Token:      str,
741	}
742	p.accept(scanner.Int)
743	return value
744}
745
746func (p *parser) parseListValue() *List {
747	lBracePos := p.scanner.Position
748	if !p.accept('[') {
749		return nil
750	}
751
752	var elements []Expression
753	for p.tok != ']' {
754		element := p.parseExpression()
755		elements = append(elements, element)
756
757		if p.tok != ',' {
758			// There was no comma, so the list is done.
759			break
760		}
761
762		p.accept(',')
763	}
764
765	rBracePos := p.scanner.Position
766	p.accept(']')
767
768	return &List{
769		LBracePos: lBracePos,
770		RBracePos: rBracePos,
771		Values:    elements,
772	}
773}
774
775func (p *parser) parseMapValue() *Map {
776	lBracePos := p.scanner.Position
777	if !p.accept('{') {
778		return nil
779	}
780
781	properties := p.parsePropertyList(false, false)
782
783	rBracePos := p.scanner.Position
784	p.accept('}')
785
786	return &Map{
787		LBracePos:  lBracePos,
788		RBracePos:  rBracePos,
789		Properties: properties,
790	}
791}
792
793type Scope struct {
794	vars              map[string]*Assignment
795	preventInheriting map[string]bool
796	parentScope       *Scope
797}
798
799func NewScope(s *Scope) *Scope {
800	return &Scope{
801		vars:              make(map[string]*Assignment),
802		preventInheriting: make(map[string]bool),
803		parentScope:       s,
804	}
805}
806
807func (s *Scope) HandleAssignment(assignment *Assignment) error {
808	switch assignment.Assigner {
809	case "+=":
810		if !s.preventInheriting[assignment.Name] && s.parentScope.Get(assignment.Name) != nil {
811			return fmt.Errorf("modified non-local variable %q with +=", assignment.Name)
812		}
813		if old, ok := s.vars[assignment.Name]; !ok {
814			return fmt.Errorf("modified non-existent variable %q with +=", assignment.Name)
815		} else if old.Referenced {
816			return fmt.Errorf("modified variable %q with += after referencing", assignment.Name)
817		} else {
818			newValue, err := evaluateOperator(s, '+', old.Value, assignment.Value)
819			if err != nil {
820				return err
821			}
822			old.Value = newValue
823		}
824	case "=":
825		if old, ok := s.vars[assignment.Name]; ok {
826			return fmt.Errorf("variable already set, previous assignment: %s", old)
827		}
828
829		if old := s.parentScope.Get(assignment.Name); old != nil && !s.preventInheriting[assignment.Name] {
830			return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old)
831		}
832
833		if newValue, err := assignment.Value.Eval(s); err != nil {
834			return err
835		} else {
836			assignment.Value = newValue
837		}
838		s.vars[assignment.Name] = assignment
839	default:
840		return fmt.Errorf("Unknown assigner '%s'", assignment.Assigner)
841	}
842	return nil
843}
844
845func (s *Scope) Get(name string) *Assignment {
846	if s == nil {
847		return nil
848	}
849	if a, ok := s.vars[name]; ok {
850		return a
851	}
852	if s.preventInheriting[name] {
853		return nil
854	}
855	return s.parentScope.Get(name)
856}
857
858func (s *Scope) GetLocal(name string) *Assignment {
859	if s == nil {
860		return nil
861	}
862	if a, ok := s.vars[name]; ok {
863		return a
864	}
865	return nil
866}
867
868// DontInherit prevents this scope from inheriting the given variable from its
869// parent scope.
870func (s *Scope) DontInherit(name string) {
871	s.preventInheriting[name] = true
872}
873
874func (s *Scope) String() string {
875	var sb strings.Builder
876	s.stringInner(&sb)
877	return sb.String()
878}
879
880func (s *Scope) stringInner(sb *strings.Builder) {
881	if s == nil {
882		return
883	}
884	vars := make([]string, 0, len(s.vars))
885	for k := range s.vars {
886		vars = append(vars, k)
887	}
888
889	sort.Strings(vars)
890
891	for _, v := range vars {
892		sb.WriteString(s.vars[v].String())
893		sb.WriteRune('\n')
894	}
895
896	s.parentScope.stringInner(sb)
897}
898