• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
31type ParseError struct {
32	Err error
33	Pos scanner.Position
34}
35
36func (e *ParseError) Error() string {
37	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
38}
39
40type File struct {
41	Name     string
42	Defs     []Definition
43	Comments []*CommentGroup
44}
45
46func (f *File) Pos() scanner.Position {
47	return scanner.Position{
48		Filename: f.Name,
49		Line:     1,
50		Column:   1,
51		Offset:   0,
52	}
53}
54
55func (f *File) End() scanner.Position {
56	if len(f.Defs) > 0 {
57		return f.Defs[len(f.Defs)-1].End()
58	}
59	return noPos
60}
61
62func parse(p *parser) (file *File, errs []error) {
63	defer func() {
64		if r := recover(); r != nil {
65			if r == errTooManyErrors {
66				errs = p.errors
67				return
68			}
69			panic(r)
70		}
71	}()
72
73	defs := p.parseDefinitions()
74	p.accept(scanner.EOF)
75	errs = p.errors
76	comments := p.comments
77
78	return &File{
79		Name:     p.scanner.Filename,
80		Defs:     defs,
81		Comments: comments,
82	}, errs
83
84}
85
86func ParseAndEval(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
87	p := newParser(r, scope)
88	p.eval = true
89	p.scanner.Filename = filename
90
91	return parse(p)
92}
93
94func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error) {
95	p := newParser(r, scope)
96	p.scanner.Filename = filename
97
98	return parse(p)
99}
100
101type parser struct {
102	scanner  scanner.Scanner
103	tok      rune
104	errors   []error
105	scope    *Scope
106	comments []*CommentGroup
107	eval     bool
108}
109
110func newParser(r io.Reader, scope *Scope) *parser {
111	p := &parser{}
112	p.scope = scope
113	p.scanner.Init(r)
114	p.scanner.Error = func(sc *scanner.Scanner, msg string) {
115		p.errorf(msg)
116	}
117	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings |
118		scanner.ScanRawStrings | scanner.ScanComments
119	p.next()
120	return p
121}
122
123func (p *parser) error(err error) {
124	pos := p.scanner.Position
125	if !pos.IsValid() {
126		pos = p.scanner.Pos()
127	}
128	err = &ParseError{
129		Err: err,
130		Pos: pos,
131	}
132	p.errors = append(p.errors, err)
133	if len(p.errors) >= maxErrors {
134		panic(errTooManyErrors)
135	}
136}
137
138func (p *parser) errorf(format string, args ...interface{}) {
139	p.error(fmt.Errorf(format, args...))
140}
141
142func (p *parser) accept(toks ...rune) bool {
143	for _, tok := range toks {
144		if p.tok != tok {
145			p.errorf("expected %s, found %s", scanner.TokenString(tok),
146				scanner.TokenString(p.tok))
147			return false
148		}
149		p.next()
150	}
151	return true
152}
153
154func (p *parser) next() {
155	if p.tok != scanner.EOF {
156		p.tok = p.scanner.Scan()
157		if p.tok == scanner.Comment {
158			var comments []*Comment
159			for p.tok == scanner.Comment {
160				lines := strings.Split(p.scanner.TokenText(), "\n")
161				if len(comments) > 0 && p.scanner.Position.Line > comments[len(comments)-1].End().Line+1 {
162					p.comments = append(p.comments, &CommentGroup{Comments: comments})
163					comments = nil
164				}
165				comments = append(comments, &Comment{lines, p.scanner.Position})
166				p.tok = p.scanner.Scan()
167			}
168			p.comments = append(p.comments, &CommentGroup{Comments: comments})
169		}
170	}
171	return
172}
173
174func (p *parser) parseDefinitions() (defs []Definition) {
175	for {
176		switch p.tok {
177		case scanner.Ident:
178			ident := p.scanner.TokenText()
179			pos := p.scanner.Position
180
181			p.accept(scanner.Ident)
182
183			switch p.tok {
184			case '+':
185				p.accept('+')
186				defs = append(defs, p.parseAssignment(ident, pos, "+="))
187			case '=':
188				defs = append(defs, p.parseAssignment(ident, pos, "="))
189			case '{', '(':
190				defs = append(defs, p.parseModule(ident, pos))
191			default:
192				p.errorf("expected \"=\" or \"+=\" or \"{\" or \"(\", found %s",
193					scanner.TokenString(p.tok))
194			}
195		case scanner.EOF:
196			return
197		default:
198			p.errorf("expected assignment or module definition, found %s",
199				scanner.TokenString(p.tok))
200			return
201		}
202	}
203}
204
205func (p *parser) parseAssignment(name string, namePos scanner.Position,
206	assigner string) (assignment *Assignment) {
207
208	assignment = new(Assignment)
209
210	pos := p.scanner.Position
211	if !p.accept('=') {
212		return
213	}
214	value := p.parseExpression()
215
216	assignment.Name = name
217	assignment.NamePos = namePos
218	assignment.Value = value
219	assignment.OrigValue = value
220	assignment.EqualsPos = pos
221	assignment.Assigner = assigner
222
223	if p.scope != nil {
224		if assigner == "+=" {
225			if old, local := p.scope.Get(assignment.Name); old == nil {
226				p.errorf("modified non-existent variable %q with +=", assignment.Name)
227			} else if !local {
228				p.errorf("modified non-local variable %q with +=", assignment.Name)
229			} else if old.Referenced {
230				p.errorf("modified variable %q with += after referencing", assignment.Name)
231			} else {
232				val, err := p.evaluateOperator(old.Value, assignment.Value, '+', assignment.EqualsPos)
233				if err != nil {
234					p.error(err)
235				} else {
236					old.Value = val
237				}
238			}
239		} else {
240			err := p.scope.Add(assignment)
241			if err != nil {
242				p.error(err)
243			}
244		}
245	}
246
247	return
248}
249
250func (p *parser) parseModule(typ string, typPos scanner.Position) *Module {
251
252	compat := false
253	lbracePos := p.scanner.Position
254	if p.tok == '{' {
255		compat = true
256	}
257
258	if !p.accept(p.tok) {
259		return nil
260	}
261	properties := p.parsePropertyList(true, compat)
262	rbracePos := p.scanner.Position
263	if !compat {
264		p.accept(')')
265	} else {
266		p.accept('}')
267	}
268
269	return &Module{
270		Type:    typ,
271		TypePos: typPos,
272		Map: Map{
273			Properties: properties,
274			LBracePos:  lbracePos,
275			RBracePos:  rbracePos,
276		},
277	}
278}
279
280func (p *parser) parsePropertyList(isModule, compat bool) (properties []*Property) {
281	for p.tok == scanner.Ident {
282		property := p.parseProperty(isModule, compat)
283		properties = append(properties, property)
284
285		if p.tok != ',' {
286			// There was no comma, so the list is done.
287			break
288		}
289
290		p.accept(',')
291	}
292
293	return
294}
295
296func (p *parser) parseProperty(isModule, compat bool) (property *Property) {
297	property = new(Property)
298
299	name := p.scanner.TokenText()
300	namePos := p.scanner.Position
301	p.accept(scanner.Ident)
302	pos := p.scanner.Position
303
304	if isModule {
305		if compat {
306			if !p.accept(':') {
307				return
308			}
309		} else {
310			if !p.accept('=') {
311				return
312			}
313		}
314	} else {
315		if !p.accept(':') {
316			return
317		}
318	}
319
320	value := p.parseExpression()
321
322	property.Name = name
323	property.NamePos = namePos
324	property.Value = value
325	property.ColonPos = pos
326
327	return
328}
329
330func (p *parser) parseExpression() (value Expression) {
331	value = p.parseValue()
332	switch p.tok {
333	case '+':
334		return p.parseOperator(value)
335	case '-':
336		p.errorf("subtraction not supported: %s", p.scanner.String())
337		return value
338	default:
339		return value
340	}
341}
342
343func (p *parser) evaluateOperator(value1, value2 Expression, operator rune,
344	pos scanner.Position) (*Operator, error) {
345
346	value := value1
347
348	if p.eval {
349		e1 := value1.Eval()
350		e2 := value2.Eval()
351		if e1.Type() != e2.Type() {
352			return nil, fmt.Errorf("mismatched type in operator %c: %s != %s", operator,
353				e1.Type(), e2.Type())
354		}
355
356		value = e1.Copy()
357
358		switch operator {
359		case '+':
360			switch v := value.(type) {
361			case *String:
362				v.Value += e2.(*String).Value
363			case *Int64:
364				v.Value += e2.(*Int64).Value
365				v.Token = ""
366			case *List:
367				v.Values = append(v.Values, e2.(*List).Values...)
368			case *Map:
369				var err error
370				v.Properties, err = p.addMaps(v.Properties, e2.(*Map).Properties, pos)
371				if err != nil {
372					return nil, err
373				}
374			default:
375				return nil, fmt.Errorf("operator %c not supported on type %s", operator, v.Type())
376			}
377		default:
378			panic("unknown operator " + string(operator))
379		}
380	}
381
382	return &Operator{
383		Args:        [2]Expression{value1, value2},
384		Operator:    operator,
385		OperatorPos: pos,
386		Value:       value,
387	}, nil
388}
389
390func (p *parser) addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) {
391	ret := make([]*Property, 0, len(map1))
392
393	inMap1 := make(map[string]*Property)
394	inMap2 := make(map[string]*Property)
395	inBoth := make(map[string]*Property)
396
397	for _, prop1 := range map1 {
398		inMap1[prop1.Name] = prop1
399	}
400
401	for _, prop2 := range map2 {
402		inMap2[prop2.Name] = prop2
403		if _, ok := inMap1[prop2.Name]; ok {
404			inBoth[prop2.Name] = prop2
405		}
406	}
407
408	for _, prop1 := range map1 {
409		if prop2, ok := inBoth[prop1.Name]; ok {
410			var err error
411			newProp := *prop1
412			newProp.Value, err = p.evaluateOperator(prop1.Value, prop2.Value, '+', pos)
413			if err != nil {
414				return nil, err
415			}
416			ret = append(ret, &newProp)
417		} else {
418			ret = append(ret, prop1)
419		}
420	}
421
422	for _, prop2 := range map2 {
423		if _, ok := inBoth[prop2.Name]; !ok {
424			ret = append(ret, prop2)
425		}
426	}
427
428	return ret, nil
429}
430
431func (p *parser) parseOperator(value1 Expression) *Operator {
432	operator := p.tok
433	pos := p.scanner.Position
434	p.accept(operator)
435
436	value2 := p.parseExpression()
437
438	value, err := p.evaluateOperator(value1, value2, operator, pos)
439	if err != nil {
440		p.error(err)
441		return nil
442	}
443
444	return value
445
446}
447
448func (p *parser) parseValue() (value Expression) {
449	switch p.tok {
450	case scanner.Ident:
451		return p.parseVariable()
452	case '-', scanner.Int: // Integer might have '-' sign ahead ('+' is only treated as operator now)
453		return p.parseIntValue()
454	case scanner.String:
455		return p.parseStringValue()
456	case '[':
457		return p.parseListValue()
458	case '{':
459		return p.parseMapValue()
460	default:
461		p.errorf("expected bool, list, or string value; found %s",
462			scanner.TokenString(p.tok))
463		return
464	}
465}
466
467func (p *parser) parseVariable() Expression {
468	var value Expression
469
470	switch text := p.scanner.TokenText(); text {
471	case "true", "false":
472		value = &Bool{
473			LiteralPos: p.scanner.Position,
474			Value:      text == "true",
475			Token:      text,
476		}
477	default:
478		if p.eval {
479			if assignment, local := p.scope.Get(text); assignment == nil {
480				p.errorf("variable %q is not set", text)
481			} else {
482				if local {
483					assignment.Referenced = true
484				}
485				value = assignment.Value
486			}
487		}
488		value = &Variable{
489			Name:    text,
490			NamePos: p.scanner.Position,
491			Value:   value,
492		}
493	}
494
495	p.accept(scanner.Ident)
496	return value
497}
498
499func (p *parser) parseStringValue() *String {
500	str, err := strconv.Unquote(p.scanner.TokenText())
501	if err != nil {
502		p.errorf("couldn't parse string: %s", err)
503		return nil
504	}
505
506	value := &String{
507		LiteralPos: p.scanner.Position,
508		Value:      str,
509	}
510	p.accept(scanner.String)
511	return value
512}
513
514func (p *parser) parseIntValue() *Int64 {
515	var str string
516	literalPos := p.scanner.Position
517	if p.tok == '-' {
518		str += string(p.tok)
519		p.accept(p.tok)
520		if p.tok != scanner.Int {
521			p.errorf("expected int; found %s", scanner.TokenString(p.tok))
522			return nil
523		}
524	}
525	str += p.scanner.TokenText()
526	i, err := strconv.ParseInt(str, 10, 64)
527	if err != nil {
528		p.errorf("couldn't parse int: %s", err)
529		return nil
530	}
531
532	value := &Int64{
533		LiteralPos: literalPos,
534		Value:      i,
535		Token:      str,
536	}
537	p.accept(scanner.Int)
538	return value
539}
540
541func (p *parser) parseListValue() *List {
542	lBracePos := p.scanner.Position
543	if !p.accept('[') {
544		return nil
545	}
546
547	var elements []Expression
548	for p.tok != ']' {
549		element := p.parseExpression()
550		if p.eval && element.Type() != StringType {
551			p.errorf("Expected string in list, found %s", element.Type().String())
552			return nil
553		}
554		elements = append(elements, element)
555
556		if p.tok != ',' {
557			// There was no comma, so the list is done.
558			break
559		}
560
561		p.accept(',')
562	}
563
564	rBracePos := p.scanner.Position
565	p.accept(']')
566
567	return &List{
568		LBracePos: lBracePos,
569		RBracePos: rBracePos,
570		Values:    elements,
571	}
572}
573
574func (p *parser) parseMapValue() *Map {
575	lBracePos := p.scanner.Position
576	if !p.accept('{') {
577		return nil
578	}
579
580	properties := p.parsePropertyList(false, false)
581
582	rBracePos := p.scanner.Position
583	p.accept('}')
584
585	return &Map{
586		LBracePos:  lBracePos,
587		RBracePos:  rBracePos,
588		Properties: properties,
589	}
590}
591
592type Scope struct {
593	vars          map[string]*Assignment
594	inheritedVars map[string]*Assignment
595}
596
597func NewScope(s *Scope) *Scope {
598	newScope := &Scope{
599		vars:          make(map[string]*Assignment),
600		inheritedVars: make(map[string]*Assignment),
601	}
602
603	if s != nil {
604		for k, v := range s.vars {
605			newScope.inheritedVars[k] = v
606		}
607		for k, v := range s.inheritedVars {
608			newScope.inheritedVars[k] = v
609		}
610	}
611
612	return newScope
613}
614
615func (s *Scope) Add(assignment *Assignment) error {
616	if old, ok := s.vars[assignment.Name]; ok {
617		return fmt.Errorf("variable already set, previous assignment: %s", old)
618	}
619
620	if old, ok := s.inheritedVars[assignment.Name]; ok {
621		return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old)
622	}
623
624	s.vars[assignment.Name] = assignment
625
626	return nil
627}
628
629func (s *Scope) Remove(name string) {
630	delete(s.vars, name)
631	delete(s.inheritedVars, name)
632}
633
634func (s *Scope) Get(name string) (*Assignment, bool) {
635	if a, ok := s.vars[name]; ok {
636		return a, true
637	}
638
639	if a, ok := s.inheritedVars[name]; ok {
640		return a, false
641	}
642
643	return nil, false
644}
645
646func (s *Scope) String() string {
647	vars := []string{}
648
649	for k := range s.vars {
650		vars = append(vars, k)
651	}
652	for k := range s.inheritedVars {
653		vars = append(vars, k)
654	}
655
656	sort.Strings(vars)
657
658	ret := []string{}
659	for _, v := range vars {
660		if assignment, ok := s.vars[v]; ok {
661			ret = append(ret, assignment.String())
662		} else {
663			ret = append(ret, s.inheritedVars[v].String())
664		}
665	}
666
667	return strings.Join(ret, "\n")
668}
669