github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/blueprint/parser/parser.go (about)

     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  
    15  package parser
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"text/scanner"
    25  )
    26  
    27  var errTooManyErrors = errors.New("too many errors")
    28  
    29  const maxErrors = 1
    30  
    31  type ParseError struct {
    32  	Err error
    33  	Pos scanner.Position
    34  }
    35  
    36  func (e *ParseError) Error() string {
    37  	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
    38  }
    39  
    40  type File struct {
    41  	Name     string
    42  	Defs     []Definition
    43  	Comments []*CommentGroup
    44  }
    45  
    46  func (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  
    55  func (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  
    62  func 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  
    86  func 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  
    94  func 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  
   101  type parser struct {
   102  	scanner  scanner.Scanner
   103  	tok      rune
   104  	errors   []error
   105  	scope    *Scope
   106  	comments []*CommentGroup
   107  	eval     bool
   108  }
   109  
   110  func 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  
   123  func (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  
   138  func (p *parser) errorf(format string, args ...interface{}) {
   139  	p.error(fmt.Errorf(format, args...))
   140  }
   141  
   142  func (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  
   154  func (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  
   174  func (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  
   205  func (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  
   250  func (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  
   280  func (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  
   296  func (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 && p.tok == ':' {
   306  			p.accept(':')
   307  		} else {
   308  			if !p.accept('=') {
   309  				return
   310  			}
   311  		}
   312  	} else {
   313  		if !p.accept(':') {
   314  			return
   315  		}
   316  	}
   317  
   318  	value := p.parseExpression()
   319  
   320  	property.Name = name
   321  	property.NamePos = namePos
   322  	property.Value = value
   323  	property.ColonPos = pos
   324  
   325  	return
   326  }
   327  
   328  func (p *parser) parseExpression() (value Expression) {
   329  	value = p.parseValue()
   330  	switch p.tok {
   331  	case '+':
   332  		return p.parseOperator(value)
   333  	case '-':
   334  		p.errorf("subtraction not supported: %s", p.scanner.String())
   335  		return value
   336  	default:
   337  		return value
   338  	}
   339  }
   340  
   341  func (p *parser) evaluateOperator(value1, value2 Expression, operator rune,
   342  	pos scanner.Position) (*Operator, error) {
   343  
   344  	value := value1
   345  
   346  	if p.eval {
   347  		e1 := value1.Eval()
   348  		e2 := value2.Eval()
   349  		if e1.Type() != e2.Type() {
   350  			return nil, fmt.Errorf("mismatched type in operator %c: %s != %s", operator,
   351  				e1.Type(), e2.Type())
   352  		}
   353  
   354  		value = e1.Copy()
   355  
   356  		switch operator {
   357  		case '+':
   358  			switch v := value.(type) {
   359  			case *String:
   360  				v.Value += e2.(*String).Value
   361  			case *Int64:
   362  				v.Value += e2.(*Int64).Value
   363  				v.Token = ""
   364  			case *List:
   365  				v.Values = append(v.Values, e2.(*List).Values...)
   366  			case *Map:
   367  				var err error
   368  				v.Properties, err = p.addMaps(v.Properties, e2.(*Map).Properties, pos)
   369  				if err != nil {
   370  					return nil, err
   371  				}
   372  			default:
   373  				return nil, fmt.Errorf("operator %c not supported on type %s", operator, v.Type())
   374  			}
   375  		default:
   376  			panic("unknown operator " + string(operator))
   377  		}
   378  	}
   379  
   380  	return &Operator{
   381  		Args:        [2]Expression{value1, value2},
   382  		Operator:    operator,
   383  		OperatorPos: pos,
   384  		Value:       value,
   385  	}, nil
   386  }
   387  
   388  func (p *parser) addMaps(map1, map2 []*Property, pos scanner.Position) ([]*Property, error) {
   389  	ret := make([]*Property, 0, len(map1))
   390  
   391  	inMap1 := make(map[string]*Property)
   392  	inMap2 := make(map[string]*Property)
   393  	inBoth := make(map[string]*Property)
   394  
   395  	for _, prop1 := range map1 {
   396  		inMap1[prop1.Name] = prop1
   397  	}
   398  
   399  	for _, prop2 := range map2 {
   400  		inMap2[prop2.Name] = prop2
   401  		if _, ok := inMap1[prop2.Name]; ok {
   402  			inBoth[prop2.Name] = prop2
   403  		}
   404  	}
   405  
   406  	for _, prop1 := range map1 {
   407  		if prop2, ok := inBoth[prop1.Name]; ok {
   408  			var err error
   409  			newProp := *prop1
   410  			newProp.Value, err = p.evaluateOperator(prop1.Value, prop2.Value, '+', pos)
   411  			if err != nil {
   412  				return nil, err
   413  			}
   414  			ret = append(ret, &newProp)
   415  		} else {
   416  			ret = append(ret, prop1)
   417  		}
   418  	}
   419  
   420  	for _, prop2 := range map2 {
   421  		if _, ok := inBoth[prop2.Name]; !ok {
   422  			ret = append(ret, prop2)
   423  		}
   424  	}
   425  
   426  	return ret, nil
   427  }
   428  
   429  func (p *parser) parseOperator(value1 Expression) *Operator {
   430  	operator := p.tok
   431  	pos := p.scanner.Position
   432  	p.accept(operator)
   433  
   434  	value2 := p.parseExpression()
   435  
   436  	value, err := p.evaluateOperator(value1, value2, operator, pos)
   437  	if err != nil {
   438  		p.error(err)
   439  		return nil
   440  	}
   441  
   442  	return value
   443  
   444  }
   445  
   446  func (p *parser) parseValue() (value Expression) {
   447  	switch p.tok {
   448  	case scanner.Ident:
   449  		return p.parseVariable()
   450  	case '-', scanner.Int: // Integer might have '-' sign ahead ('+' is only treated as operator now)
   451  		return p.parseIntValue()
   452  	case scanner.String:
   453  		return p.parseStringValue()
   454  	case '[':
   455  		return p.parseListValue()
   456  	case '{':
   457  		return p.parseMapValue()
   458  	default:
   459  		p.errorf("expected bool, list, or string value; found %s",
   460  			scanner.TokenString(p.tok))
   461  		return
   462  	}
   463  }
   464  
   465  func (p *parser) parseVariable() Expression {
   466  	var value Expression
   467  
   468  	switch text := p.scanner.TokenText(); text {
   469  	case "true", "false":
   470  		value = &Bool{
   471  			LiteralPos: p.scanner.Position,
   472  			Value:      text == "true",
   473  			Token:      text,
   474  		}
   475  	default:
   476  		if p.eval {
   477  			if assignment, local := p.scope.Get(text); assignment == nil {
   478  				p.errorf("variable %q is not set", text)
   479  			} else {
   480  				if local {
   481  					assignment.Referenced = true
   482  				}
   483  				value = assignment.Value
   484  			}
   485  		}
   486  		value = &Variable{
   487  			Name:    text,
   488  			NamePos: p.scanner.Position,
   489  			Value:   value,
   490  		}
   491  	}
   492  
   493  	p.accept(scanner.Ident)
   494  	return value
   495  }
   496  
   497  func (p *parser) parseStringValue() *String {
   498  	str, err := strconv.Unquote(p.scanner.TokenText())
   499  	if err != nil {
   500  		p.errorf("couldn't parse string: %s", err)
   501  		return nil
   502  	}
   503  
   504  	value := &String{
   505  		LiteralPos: p.scanner.Position,
   506  		Value:      str,
   507  	}
   508  	p.accept(scanner.String)
   509  	return value
   510  }
   511  
   512  func (p *parser) parseIntValue() *Int64 {
   513  	var str string
   514  	literalPos := p.scanner.Position
   515  	if p.tok == '-' {
   516  		str += string(p.tok)
   517  		p.accept(p.tok)
   518  		if p.tok != scanner.Int {
   519  			p.errorf("expected int; found %s", scanner.TokenString(p.tok))
   520  			return nil
   521  		}
   522  	}
   523  	str += p.scanner.TokenText()
   524  	i, err := strconv.ParseInt(str, 10, 64)
   525  	if err != nil {
   526  		p.errorf("couldn't parse int: %s", err)
   527  		return nil
   528  	}
   529  
   530  	value := &Int64{
   531  		LiteralPos: literalPos,
   532  		Value:      i,
   533  		Token:      str,
   534  	}
   535  	p.accept(scanner.Int)
   536  	return value
   537  }
   538  
   539  func (p *parser) parseListValue() *List {
   540  	lBracePos := p.scanner.Position
   541  	if !p.accept('[') {
   542  		return nil
   543  	}
   544  
   545  	var elements []Expression
   546  	for p.tok != ']' {
   547  		element := p.parseExpression()
   548  		if p.eval && element.Type() != StringType {
   549  			p.errorf("Expected string in list, found %s", element.Type().String())
   550  			return nil
   551  		}
   552  		elements = append(elements, element)
   553  
   554  		if p.tok != ',' {
   555  			// There was no comma, so the list is done.
   556  			break
   557  		}
   558  
   559  		p.accept(',')
   560  	}
   561  
   562  	rBracePos := p.scanner.Position
   563  	p.accept(']')
   564  
   565  	return &List{
   566  		LBracePos: lBracePos,
   567  		RBracePos: rBracePos,
   568  		Values:    elements,
   569  	}
   570  }
   571  
   572  func (p *parser) parseMapValue() *Map {
   573  	lBracePos := p.scanner.Position
   574  	if !p.accept('{') {
   575  		return nil
   576  	}
   577  
   578  	properties := p.parsePropertyList(false, false)
   579  
   580  	rBracePos := p.scanner.Position
   581  	p.accept('}')
   582  
   583  	return &Map{
   584  		LBracePos:  lBracePos,
   585  		RBracePos:  rBracePos,
   586  		Properties: properties,
   587  	}
   588  }
   589  
   590  type Scope struct {
   591  	vars          map[string]*Assignment
   592  	inheritedVars map[string]*Assignment
   593  }
   594  
   595  func NewScope(s *Scope) *Scope {
   596  	newScope := &Scope{
   597  		vars:          make(map[string]*Assignment),
   598  		inheritedVars: make(map[string]*Assignment),
   599  	}
   600  
   601  	if s != nil {
   602  		for k, v := range s.vars {
   603  			newScope.inheritedVars[k] = v
   604  		}
   605  		for k, v := range s.inheritedVars {
   606  			newScope.inheritedVars[k] = v
   607  		}
   608  	}
   609  
   610  	return newScope
   611  }
   612  
   613  func (s *Scope) Add(assignment *Assignment) error {
   614  	if old, ok := s.vars[assignment.Name]; ok {
   615  		return fmt.Errorf("variable already set, previous assignment: %s", old)
   616  	}
   617  
   618  	if old, ok := s.inheritedVars[assignment.Name]; ok {
   619  		return fmt.Errorf("variable already set in inherited scope, previous assignment: %s", old)
   620  	}
   621  
   622  	s.vars[assignment.Name] = assignment
   623  
   624  	return nil
   625  }
   626  
   627  func (s *Scope) Remove(name string) {
   628  	delete(s.vars, name)
   629  	delete(s.inheritedVars, name)
   630  }
   631  
   632  func (s *Scope) Get(name string) (*Assignment, bool) {
   633  	if a, ok := s.vars[name]; ok {
   634  		return a, true
   635  	}
   636  
   637  	if a, ok := s.inheritedVars[name]; ok {
   638  		return a, false
   639  	}
   640  
   641  	return nil, false
   642  }
   643  
   644  func (s *Scope) String() string {
   645  	vars := []string{}
   646  
   647  	for k := range s.vars {
   648  		vars = append(vars, k)
   649  	}
   650  	for k := range s.inheritedVars {
   651  		vars = append(vars, k)
   652  	}
   653  
   654  	sort.Strings(vars)
   655  
   656  	ret := []string{}
   657  	for _, v := range vars {
   658  		if assignment, ok := s.vars[v]; ok {
   659  			ret = append(ret, assignment.String())
   660  		} else {
   661  			ret = append(ret, s.inheritedVars[v].String())
   662  		}
   663  	}
   664  
   665  	return strings.Join(ret, "\n")
   666  }