github.com/NeowayLabs/nash@v0.2.2-0.20200127205349-a227041ffd50/parser/parse.go (about)

     1  package parser
     2  
     3  import (
     4  	"fmt"
     5  	"runtime"
     6  
     7  	"strconv"
     8  
     9  	"github.com/madlambda/nash/ast"
    10  	"github.com/madlambda/nash/errors"
    11  	"github.com/madlambda/nash/scanner"
    12  	"github.com/madlambda/nash/token"
    13  )
    14  
    15  type (
    16  	// Parser parses an nash file
    17  	Parser struct {
    18  		name       string // filename or name of the buffer
    19  		content    string
    20  		l          *scanner.Lexer
    21  		tok        *scanner.Token // token saved for lookahead
    22  		openblocks int
    23  
    24  		insidePipe bool
    25  
    26  		keywordParsers map[token.Token]parserFn
    27  	}
    28  
    29  	parserFn func(tok scanner.Token) (ast.Node, error)
    30  
    31  	exprConfig struct {
    32  		allowArg      bool
    33  		allowVariadic bool
    34  		allowFuncall  bool
    35  		allowConcat   bool
    36  	}
    37  )
    38  
    39  // NewParser creates a new parser
    40  func NewParser(name, content string) *Parser {
    41  	p := &Parser{
    42  		name:    name,
    43  		content: content,
    44  		l:       scanner.Lex(name, content),
    45  	}
    46  
    47  	p.keywordParsers = map[token.Token]parserFn{
    48  		token.For:     p.parseFor,
    49  		token.If:      p.parseIf,
    50  		token.Fn:      p.parseFnDecl,
    51  		token.Var:     p.parseVar,
    52  		token.Return:  p.parseReturn,
    53  		token.Import:  p.parseImport,
    54  		token.SetEnv:  p.parseSetenv,
    55  		token.Rfork:   p.parseRfork,
    56  		token.BindFn:  p.parseBindFn,
    57  		token.Comment: p.parseComment,
    58  		token.Illegal: p.parseError,
    59  	}
    60  
    61  	return p
    62  }
    63  
    64  // Parse starts the parsing.
    65  func (p *Parser) Parse() (tr *ast.Tree, err error) {
    66  	var root *ast.BlockNode
    67  
    68  	defer func() {
    69  		if r := recover(); r != nil {
    70  			if _, ok := r.(runtime.Error); ok {
    71  				panic(r)
    72  			}
    73  
    74  			err = r.(error)
    75  		}
    76  	}()
    77  
    78  	root, err = p.parseBlock(1, 0)
    79  
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	tr = ast.NewTree(p.name)
    85  	tr.Root = root
    86  
    87  	return tr, nil
    88  }
    89  
    90  // next returns the next item from lookahead buffer if not empty or
    91  // from the Lexer
    92  func (p *Parser) next() scanner.Token {
    93  	if p.tok != nil {
    94  		t := p.tok
    95  		p.tok = nil
    96  		return *t
    97  	}
    98  
    99  	tok := <-p.l.Tokens
   100  
   101  	if tok.Type() == token.Illegal {
   102  		panic(errors.NewError(tok.Value()))
   103  	}
   104  
   105  	return tok
   106  }
   107  
   108  // backup puts the item into the lookahead buffer
   109  func (p *Parser) backup(it scanner.Token) error {
   110  	if p.tok != nil {
   111  		panic(errors.NewError("only one slot for backup/lookahead: %s", it))
   112  	}
   113  
   114  	p.tok = &it
   115  
   116  	return nil
   117  }
   118  
   119  // ignores the next item
   120  func (p *Parser) ignore() {
   121  	if p.tok != nil {
   122  		p.tok = nil
   123  	} else {
   124  		<-p.l.Tokens
   125  	}
   126  }
   127  
   128  // peek gets but do not discards the next item (lookahead)
   129  func (p *Parser) peek() scanner.Token {
   130  	i := p.next()
   131  	p.tok = &i
   132  	return i
   133  }
   134  
   135  func (p *Parser) parseBlock(lineStart, columnStart int) (*ast.BlockNode, error) {
   136  	ln := ast.NewBlockNode(token.NewFileInfo(lineStart, columnStart))
   137  
   138  	for {
   139  		it := p.peek()
   140  
   141  		switch it.Type() {
   142  		case token.EOF:
   143  			goto finish
   144  		case token.LBrace:
   145  			p.ignore()
   146  
   147  			return nil, newParserError(it, p.name,
   148  				"Unexpected '{'")
   149  		case token.RBrace:
   150  			p.ignore()
   151  
   152  			if p.openblocks <= 0 {
   153  				return nil, newParserError(it, p.name,
   154  					"No block open for close")
   155  			}
   156  
   157  			p.openblocks--
   158  			return ln, nil
   159  		default:
   160  			n, err := p.parseStatement()
   161  
   162  			if err != nil {
   163  				return nil, err
   164  			}
   165  
   166  			ln.Push(n)
   167  		}
   168  	}
   169  
   170  finish:
   171  	if p.openblocks != 0 {
   172  		return nil, errors.NewUnfinishedBlockError(p.name, p.peek())
   173  	}
   174  
   175  	return ln, nil
   176  }
   177  
   178  func (p *Parser) parseStatement() (ast.Node, error) {
   179  	it := p.next()
   180  	next := p.peek()
   181  
   182  	if fn, ok := p.keywordParsers[it.Type()]; ok {
   183  		return fn(it)
   184  	}
   185  
   186  	// statement starting with ident:
   187  	// - fn call
   188  	// - variable assignment
   189  	// - variable exec assignment
   190  	// - Command
   191  
   192  	if isFuncall(it.Type(), next.Type()) {
   193  		return p.parseFnInv(it, true)
   194  	}
   195  
   196  	if it.Type() == token.Ident {
   197  		if isAssignment(next.Type()) {
   198  			return p.parseAssignment(it)
   199  		}
   200  
   201  		return p.parseCommand(it)
   202  	} else if it.Type() == token.Arg {
   203  		return p.parseCommand(it)
   204  	}
   205  
   206  	// statement starting with '('
   207  	// -multiline command (echo hello)
   208  	if it.Type() == token.LParen {
   209  		return p.parseCommand(it)
   210  	}
   211  
   212  	return nil, newParserError(it, p.name, "Unexpected token parsing statement '%+v'", it)
   213  }
   214  
   215  func (p *Parser) parseIndexing() (ast.Expr, error) {
   216  	it := p.next()
   217  
   218  	if it.Type() != token.Number && it.Type() != token.Variable {
   219  		return nil, newParserError(it, p.name,
   220  			"Expected number or variable in index. Found %v", it)
   221  	}
   222  
   223  	var (
   224  		index ast.Expr
   225  		err   error
   226  	)
   227  
   228  	if it.Type() == token.Number {
   229  		// only supports base10
   230  		intval, err := strconv.Atoi(it.Value())
   231  
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  
   236  		index = ast.NewIntExpr(it.FileInfo, intval)
   237  	} else {
   238  		index, err = p.parseVariable(&it, false)
   239  
   240  		if err != nil {
   241  			return nil, err
   242  		}
   243  	}
   244  
   245  	it = p.next()
   246  
   247  	if it.Type() != token.RBrack {
   248  		return nil, newParserError(it, p.name,
   249  			"Unexpected token %v. Expecting ']'", it)
   250  	}
   251  
   252  	return index, nil
   253  }
   254  
   255  func (p *Parser) parseVariable(tok *scanner.Token, allowVararg bool) (ast.Expr, error) {
   256  	var it scanner.Token
   257  
   258  	if tok == nil {
   259  		it = p.next()
   260  	} else {
   261  		it = *tok
   262  	}
   263  
   264  	if it.Type() != token.Variable {
   265  		return nil, newParserError(it, p.name,
   266  			"Unexpected token %v. Expected VARIABLE", it)
   267  	}
   268  
   269  	variadicErr := func(tok scanner.Token) (ast.Node, error) {
   270  		return nil, newParserError(it, p.name,
   271  			"Unexpected token '...'. Varargs allowed only in fn call and fn decl")
   272  	}
   273  
   274  	varTok := it
   275  	it = p.peek()
   276  	if it.Type() == token.LBrack {
   277  		variable := ast.NewVarExpr(varTok.FileInfo, varTok.Value())
   278  		p.ignore()
   279  		index, err := p.parseIndexing()
   280  		if err != nil {
   281  			return nil, err
   282  		}
   283  
   284  		isVariadic := p.peek().Type() == token.Dotdotdot
   285  		if isVariadic && !allowVararg {
   286  			return variadicErr(p.peek())
   287  		}
   288  		indexedVar := ast.NewIndexVariadicExpr(variable.FileInfo, variable, index, isVariadic)
   289  		if isVariadic {
   290  			p.ignore()
   291  		}
   292  		return indexedVar, nil
   293  	}
   294  
   295  	isVariadic := p.peek().Type() == token.Dotdotdot
   296  	if isVariadic {
   297  		if !allowVararg {
   298  			return variadicErr(p.peek())
   299  		}
   300  		p.ignore()
   301  	}
   302  
   303  	return ast.NewVarVariadicExpr(varTok.FileInfo, varTok.Value(), isVariadic), nil
   304  }
   305  
   306  func (p *Parser) parsePipe(first *ast.CommandNode) (ast.Node, error) {
   307  	it := p.next()
   308  
   309  	n := ast.NewPipeNode(it.FileInfo, first.IsMulti())
   310  	first.SetMulti(false)
   311  
   312  	n.AddCmd(first)
   313  
   314  	for it = p.peek(); it.Type() == token.Ident || it.Type() == token.Arg; it = p.peek() {
   315  		p.next()
   316  		cmd, err := p.parseCommand(it)
   317  
   318  		if err != nil {
   319  			return nil, err
   320  		}
   321  
   322  		n.AddCmd(cmd.(*ast.CommandNode))
   323  
   324  		if !p.insidePipe {
   325  			break
   326  		}
   327  	}
   328  
   329  	if n.IsMulti() {
   330  		it = p.peek()
   331  		if it.Type() != token.RParen {
   332  			if it.Type() == token.EOF {
   333  				return nil, errors.NewUnfinishedCmdError(p.name, it)
   334  			}
   335  
   336  			return nil, newParserError(it, p.name, "Unexpected symbol '%s'", it)
   337  		}
   338  
   339  		p.ignore()
   340  	}
   341  
   342  	it = p.peek()
   343  
   344  	if it.Type() == token.RBrace {
   345  		return n, nil
   346  	}
   347  
   348  	if it.Type() != token.Semicolon {
   349  		return nil, newParserError(it, p.name, "Unexpected symbol %s", it)
   350  	}
   351  
   352  	p.ignore()
   353  
   354  	return n, nil
   355  }
   356  
   357  func (p *Parser) parseCommand(it scanner.Token) (ast.Node, error) {
   358  	isMulti := false
   359  
   360  	if it.Type() == token.LParen {
   361  		// multiline command
   362  		isMulti = true
   363  
   364  		it = p.next()
   365  	}
   366  
   367  	if it.Type() != token.Ident && it.Type() != token.Arg {
   368  		if isMulti && it.Type() == token.EOF {
   369  			return nil, errors.NewUnfinishedCmdError(p.name, it)
   370  		}
   371  
   372  		return nil, newParserError(it, p.name, "Unexpected token %v. Expecting IDENT or ARG", it)
   373  	}
   374  
   375  	n := ast.NewCommandNode(it.FileInfo, it.Value(), isMulti)
   376  
   377  cmdLoop:
   378  	for {
   379  		it = p.peek()
   380  
   381  		switch typ := it.Type(); {
   382  		case typ == token.RBrace:
   383  			if p.openblocks > 0 {
   384  				if p.insidePipe {
   385  					p.insidePipe = false
   386  				}
   387  
   388  				return n, nil
   389  			}
   390  
   391  			break cmdLoop
   392  		case isValidArgument(it):
   393  			arg, err := p.getArgument(nil, exprConfig{
   394  				allowConcat:   true,
   395  				allowArg:      true,
   396  				allowVariadic: true,
   397  				allowFuncall:  false,
   398  			})
   399  
   400  			if err != nil {
   401  				return nil, err
   402  			}
   403  
   404  			n.AddArg(arg)
   405  		case typ == token.Plus:
   406  			return nil, newParserError(it, p.name,
   407  				"Unexpected '+'")
   408  		case typ == token.Gt:
   409  			p.next()
   410  			redir, err := p.parseRedirection(it)
   411  
   412  			if err != nil {
   413  				return nil, err
   414  			}
   415  
   416  			n.AddRedirect(redir)
   417  		case typ == token.Pipe:
   418  			if p.insidePipe {
   419  				p.next()
   420  				// TODO(i4k): test against pipes and multiline cmds
   421  				return n, nil
   422  			}
   423  
   424  			p.insidePipe = true
   425  			return p.parsePipe(n)
   426  		case typ == token.EOF:
   427  			break cmdLoop
   428  		case typ == token.Illegal:
   429  			return nil, errors.NewError(it.Value())
   430  		default:
   431  			break cmdLoop
   432  		}
   433  	}
   434  
   435  	it = p.peek()
   436  
   437  	if isMulti {
   438  		if it.Type() != token.RParen {
   439  			if it.Type() == token.EOF {
   440  				return nil, errors.NewUnfinishedCmdError(p.name, it)
   441  			}
   442  
   443  			return nil, newParserError(it, p.name, "Unexpected symbol '%s'", it)
   444  		}
   445  
   446  		p.ignore()
   447  
   448  		it = p.peek()
   449  	}
   450  
   451  	if p.insidePipe {
   452  		p.insidePipe = false
   453  		return n, nil
   454  	}
   455  
   456  	if it.Type() != token.Semicolon {
   457  		return nil, newParserError(it, p.name, "Unexpected symbol '%s'", it)
   458  	}
   459  
   460  	p.ignore()
   461  
   462  	return n, nil
   463  }
   464  
   465  func (p *Parser) parseRedirection(it scanner.Token) (*ast.RedirectNode, error) {
   466  	var (
   467  		lval, rval int = ast.RedirMapNoValue, ast.RedirMapNoValue
   468  		err        error
   469  	)
   470  
   471  	redir := ast.NewRedirectNode(it.FileInfo)
   472  
   473  	it = p.peek()
   474  
   475  	if !isValidArgument(it) && it.Type() != token.LBrack {
   476  		return nil, newParserError(it, p.name, "Unexpected token: %v", it)
   477  	}
   478  
   479  	// [
   480  	if it.Type() == token.LBrack {
   481  		p.next()
   482  		it = p.peek()
   483  
   484  		if it.Type() != token.Number {
   485  			return nil, newParserError(it, p.name, "Expected lefthand side of redirection map, but found '%s'",
   486  				it.Value())
   487  		}
   488  
   489  		lval, err = strconv.Atoi(it.Value())
   490  
   491  		if err != nil {
   492  			return nil, newParserError(it, p.name, "Redirection map expects integers. Found: %s",
   493  				it.Value())
   494  		}
   495  
   496  		p.next()
   497  		it = p.peek()
   498  
   499  		if it.Type() != token.Assign && it.Type() != token.RBrack {
   500  			return nil, newParserError(it, p.name, "Unexpected token %v. Expecting ASSIGN or ]",
   501  				it)
   502  		}
   503  
   504  		// [xxx=
   505  		if it.Type() == token.Assign {
   506  			p.next()
   507  			it = p.peek()
   508  
   509  			if it.Type() != token.Number && it.Type() != token.RBrack {
   510  				return nil, newParserError(it, p.name, "Unexpected token %v. Expecting REDIRMAPRSIDE or ]", it)
   511  			}
   512  
   513  			if it.Type() == token.Number {
   514  				rval, err = strconv.Atoi(it.Value())
   515  
   516  				if err != nil {
   517  					return nil, newParserError(it, p.name, "Redirection map expects integers. Found: %s", it.Value())
   518  				}
   519  
   520  				p.next()
   521  				it = p.peek()
   522  			} else {
   523  				rval = ast.RedirMapSupress
   524  			}
   525  		}
   526  
   527  		if it.Type() != token.RBrack {
   528  			return nil, newParserError(it, p.name, "Unexpected token %v. Expecting ]", it)
   529  		}
   530  
   531  		// [xxx=yyy]
   532  
   533  		redir.SetMap(lval, rval)
   534  
   535  		p.next()
   536  		it = p.peek()
   537  	}
   538  
   539  	if !isValidArgument(it) {
   540  		if rval != ast.RedirMapNoValue || lval != ast.RedirMapNoValue {
   541  			return redir, nil
   542  		}
   543  
   544  		return nil, newParserError(it, p.name, "Unexpected token %v. Expecting STRING or ARG or VARIABLE", it)
   545  	}
   546  
   547  	arg, err := p.getArgument(nil, exprConfig{
   548  		allowConcat:   true,
   549  		allowArg:      true,
   550  		allowVariadic: false,
   551  		allowFuncall:  false,
   552  	})
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  
   557  	redir.SetLocation(arg)
   558  
   559  	return redir, nil
   560  }
   561  
   562  func (p *Parser) parseImport(importToken scanner.Token) (ast.Node, error) {
   563  	it := p.next()
   564  
   565  	if it.Type() != token.Arg && it.Type() != token.String && it.Type() != token.Ident {
   566  		return nil, newParserError(it, p.name, "Unexpected token %v. Expecting ARG or STRING", it)
   567  	}
   568  
   569  	var arg *ast.StringExpr
   570  
   571  	if it.Type() == token.String {
   572  		arg = ast.NewStringExpr(it.FileInfo, it.Value(), true)
   573  	} else if it.Type() == token.Arg || it.Type() == token.Ident {
   574  		arg = ast.NewStringExpr(it.FileInfo, it.Value(), false)
   575  	} else {
   576  		return nil, newParserError(it, p.name, "Parser error: Invalid token '%v' for import path", it)
   577  	}
   578  
   579  	if p.peek().Type() == token.Semicolon {
   580  		p.ignore()
   581  	}
   582  
   583  	return ast.NewImportNode(importToken.FileInfo, arg), nil
   584  }
   585  
   586  func (p *Parser) parseSetenv(it scanner.Token) (ast.Node, error) {
   587  	var (
   588  		setenv   *ast.SetenvNode
   589  		assign   ast.Node
   590  		err      error
   591  		fileInfo = it.FileInfo
   592  	)
   593  
   594  	it = p.next()
   595  	next := p.peek()
   596  
   597  	if it.Type() != token.Ident {
   598  		return nil, newParserError(it, p.name, "Unexpected token %v, expected identifier", it)
   599  	}
   600  
   601  	if next.Type() == token.Assign || next.Type() == token.AssignCmd {
   602  		assign, err = p.parseAssignment(it)
   603  
   604  		if err != nil {
   605  			return nil, err
   606  		}
   607  
   608  		setenv, err = ast.NewSetenvNode(fileInfo, it.Value(), assign)
   609  	} else {
   610  		setenv, err = ast.NewSetenvNode(fileInfo, it.Value(), nil)
   611  
   612  		if p.peek().Type() != token.Semicolon {
   613  			return nil, newParserError(p.peek(),
   614  				p.name,
   615  				"Unexpected token %v, expected semicolon (;) or EOL",
   616  				p.peek())
   617  		}
   618  
   619  		p.ignore()
   620  	}
   621  
   622  	if err != nil {
   623  		return nil, err
   624  	}
   625  
   626  	return setenv, nil
   627  }
   628  
   629  func (p *Parser) getArgument(tok *scanner.Token, cfg exprConfig) (ast.Expr, error) {
   630  	var (
   631  		err       error
   632  		it        scanner.Token
   633  		isFuncall bool
   634  	)
   635  
   636  	if tok != nil {
   637  		it = *tok
   638  	} else {
   639  		it = p.next()
   640  	}
   641  	if !isValidArgument(it) {
   642  		return nil, newParserError(it, p.name, "Unexpected token %v. Expected %s, %s, %s or %s",
   643  			it, token.Ident, token.String, token.Variable, token.Arg)
   644  	}
   645  
   646  	firstToken := it
   647  	var arg ast.Expr
   648  
   649  	if firstToken.Type() == token.Variable {
   650  		next := p.peek()
   651  
   652  		if cfg.allowFuncall && next.Type() == token.LParen {
   653  			arg, err = p.parseFnInv(firstToken, false)
   654  			isFuncall = true
   655  		} else {
   656  			// makes "echo $list" == "echo $list..."
   657  			arg, err = p.parseVariable(&firstToken, cfg.allowVariadic)
   658  		}
   659  	} else if firstToken.Type() == token.String {
   660  		arg = ast.NewStringExpr(firstToken.FileInfo, firstToken.Value(), true)
   661  	} else {
   662  		// Arg, Ident, Number, Dotdotdot, etc
   663  
   664  		next := p.peek()
   665  
   666  		if cfg.allowFuncall && next.Type() == token.LParen {
   667  			arg, err = p.parseFnInv(firstToken, false)
   668  			isFuncall = true
   669  		} else {
   670  			arg = ast.NewStringExpr(firstToken.FileInfo, firstToken.Value(), false)
   671  		}
   672  	}
   673  
   674  	if err != nil {
   675  		return nil, err
   676  	}
   677  
   678  	it = p.peek()
   679  	if it.Type() == token.Plus && cfg.allowConcat {
   680  		return p.getConcatArg(arg)
   681  	}
   682  
   683  	if (firstToken.Type() == token.Arg || firstToken.Type() == token.Ident) && (!cfg.allowArg && !isFuncall) {
   684  		return nil, newParserError(it, p.name, "Unquoted string not allowed at pos %d (%s)", it.FileInfo, it.Value())
   685  	}
   686  
   687  	return arg, nil
   688  }
   689  
   690  func (p *Parser) getConcatArg(firstArg ast.Expr) (ast.Expr, error) {
   691  	var (
   692  		it    scanner.Token
   693  		parts []ast.Expr
   694  	)
   695  
   696  	parts = append(parts, firstArg)
   697  
   698  hasConcat:
   699  	it = p.peek()
   700  
   701  	if it.Type() == token.Plus {
   702  		p.ignore()
   703  
   704  		arg, err := p.getArgument(nil, exprConfig{
   705  			allowArg:      false,
   706  			allowConcat:   false,
   707  			allowFuncall:  true,
   708  			allowVariadic: false,
   709  		})
   710  		if err != nil {
   711  			return nil, err
   712  		}
   713  
   714  		parts = append(parts, arg)
   715  		goto hasConcat
   716  	}
   717  
   718  	return ast.NewConcatExpr(token.NewFileInfo(firstArg.Line(), firstArg.Column()), parts), nil
   719  }
   720  
   721  func (p *Parser) parseAssignment(ident scanner.Token) (ast.Node, error) {
   722  	// we're here
   723  	// |
   724  	// V
   725  	// ident = ...
   726  	// ident <= ...
   727  	// ident, ident2, ..., identN = ...
   728  	// ident, ident2, ..., identN <= ...
   729  	it := p.next()
   730  
   731  	if !isAssignment(it.Type()) {
   732  		return nil, newParserError(it, p.name,
   733  			"Unexpected token %v, expected '=' ,'<=', ',' or '['", it)
   734  	}
   735  
   736  	var (
   737  		index ast.Expr
   738  		err   error
   739  	)
   740  
   741  	if it.Type() == token.LBrack {
   742  		index, err = p.parseIndexing()
   743  
   744  		if err != nil {
   745  			return nil, err
   746  		}
   747  
   748  		it = p.next()
   749  	}
   750  
   751  	names := []*ast.NameNode{
   752  		ast.NewNameNode(ident.FileInfo, ident.Value(), index),
   753  	}
   754  
   755  	if it.Type() != token.Comma {
   756  		goto assignOp
   757  	}
   758  
   759  	for it = p.next(); it.Type() == token.Ident; it = p.next() {
   760  		var index ast.Expr
   761  
   762  		name := it
   763  		it = p.next()
   764  
   765  		if it.Type() == token.LBrack {
   766  			index, err = p.parseIndexing()
   767  
   768  			if err != nil {
   769  				return nil, err
   770  			}
   771  
   772  			it = p.next()
   773  		}
   774  
   775  		names = append(names, ast.NewNameNode(name.FileInfo, name.Value(), index))
   776  
   777  		if it.Type() != token.Comma {
   778  			break
   779  		}
   780  	}
   781  
   782  assignOp:
   783  	if it.Type() != token.AssignCmd && it.Type() != token.Assign {
   784  		return nil, newParserError(it, p.name, "Unexpected token %v, expected ',' '=' or '<='", it)
   785  	}
   786  
   787  	if it.Type() == token.AssignCmd {
   788  		return p.parseAssignCmdOut(names)
   789  	}
   790  
   791  	return p.parseAssignValues(names)
   792  }
   793  
   794  func (p *Parser) parseList(tok *scanner.Token) (ast.Node, error) {
   795  	var (
   796  		arg ast.Expr
   797  		err error
   798  		lit scanner.Token
   799  	)
   800  
   801  	if tok != nil {
   802  		lit = *tok
   803  	} else {
   804  		lit = p.next()
   805  	}
   806  
   807  	if lit.Type() != token.LParen {
   808  		return nil, newParserError(lit, p.name, "Unexpected token %v. Expecting (", lit)
   809  	}
   810  
   811  	var values []ast.Expr
   812  
   813  	it := p.peek()
   814  
   815  	for isValidArgument(it) || it.Type() == token.LParen {
   816  		if it.Type() == token.LParen {
   817  			arg, err = p.parseList(nil)
   818  		} else {
   819  			arg, err = p.getArgument(nil, exprConfig{
   820  				allowArg:      true,
   821  				allowConcat:   true,
   822  				allowFuncall:  false,
   823  				allowVariadic: false,
   824  			})
   825  		}
   826  
   827  		if err != nil {
   828  			return nil, err
   829  		}
   830  
   831  		it = p.peek()
   832  
   833  		values = append(values, arg)
   834  	}
   835  
   836  	if it.Type() != token.RParen {
   837  		if it.Type() == token.EOF {
   838  			return nil, errors.NewUnfinishedListError(p.name, it)
   839  		}
   840  
   841  		return nil, newParserError(it, p.name, "Expected ) but found %s", it)
   842  	}
   843  
   844  	p.ignore()
   845  
   846  	var isVariadic bool
   847  	if p.peek().Type() == token.Dotdotdot {
   848  		isVariadic = true
   849  		p.ignore()
   850  	}
   851  	return ast.NewListVariadicExpr(lit.FileInfo, values, isVariadic), nil
   852  }
   853  
   854  func (p *Parser) parseAssignValues(names []*ast.NameNode) (ast.Node, error) {
   855  	var values []ast.Expr
   856  
   857  	if len(names) == 0 {
   858  		return nil, newParserError(p.peek(), p.name, "parser error: expect names non nil")
   859  	}
   860  
   861  	for it := p.peek(); isExpr(it.Type()); it = p.peek() {
   862  		var (
   863  			value ast.Expr
   864  			err   error
   865  		)
   866  
   867  		if it.Type() == token.Variable || it.Type() == token.String {
   868  			value, err = p.getArgument(nil, exprConfig{
   869  				allowArg:      false,
   870  				allowFuncall:  true,
   871  				allowVariadic: false,
   872  				allowConcat:   true,
   873  			})
   874  		} else if it.Type() == token.LParen { // list
   875  			value, err = p.parseList(nil)
   876  		} else {
   877  			return nil, newParserError(it, p.name, "Unexpected token %v. Expecting VARIABLE or STRING or (", it)
   878  		}
   879  
   880  		if err != nil {
   881  			return nil, err
   882  		}
   883  
   884  		values = append(values, value)
   885  
   886  		if p.peek().Type() != token.Comma {
   887  			break
   888  		}
   889  
   890  		p.ignore()
   891  	}
   892  
   893  	if len(values) == 0 {
   894  		return nil, newParserError(p.peek(), p.name, "Unexpected token %v. Expecting VARIABLE, STRING or (", p.peek())
   895  	} else if len(values) != len(names) {
   896  		return nil, newParserError(p.peek(), p.name, "assignment count mismatch: %d = %d",
   897  			len(names), len(values))
   898  	}
   899  
   900  	if p.peek().Type() == token.Semicolon {
   901  		p.ignore()
   902  	}
   903  
   904  	return ast.NewAssignNode(names[0].FileInfo, names, values), nil
   905  }
   906  
   907  func (p *Parser) parseAssignCmdOut(identifiers []*ast.NameNode) (ast.Node, error) {
   908  	var (
   909  		exec ast.Node
   910  		err  error
   911  	)
   912  
   913  	it := p.next()
   914  
   915  	if it.Type() != token.Ident && it.Type() != token.Arg && it.Type() != token.Variable && it.Type() != token.LParen {
   916  		return nil, newParserError(it, p.name,
   917  			"Invalid token %v. Expected command or function invocation", it)
   918  	}
   919  
   920  	if it.Type() == token.LParen {
   921  		// command invocation
   922  		exec, err = p.parseCommand(it)
   923  	} else {
   924  		nextIt := p.peek()
   925  
   926  		if nextIt.Type() != token.LParen {
   927  			// it == (Ident || Arg)
   928  			exec, err = p.parseCommand(it)
   929  		} else {
   930  			// <ident>()
   931  			// <arg>()
   932  			// <var>()
   933  			exec, err = p.parseFnInv(it, true)
   934  		}
   935  	}
   936  
   937  	if err != nil {
   938  		return nil, err
   939  	}
   940  
   941  	if len(identifiers) == 0 {
   942  		// should not happen... pray
   943  		panic("internal error parsing assignment")
   944  	}
   945  
   946  	return ast.NewExecAssignNode(identifiers[0].FileInfo, identifiers, exec)
   947  }
   948  
   949  func (p *Parser) parseRfork(it scanner.Token) (ast.Node, error) {
   950  	n := ast.NewRforkNode(it.FileInfo)
   951  
   952  	it = p.next()
   953  
   954  	if it.Type() != token.Ident {
   955  		return nil, newParserError(it, p.name, "rfork requires one or more of the following flags: %s", ast.RforkFlags)
   956  	}
   957  
   958  	arg := ast.NewStringExpr(it.FileInfo, it.Value(), false)
   959  	n.SetFlags(arg)
   960  
   961  	it = p.peek()
   962  
   963  	if it.Type() == token.LBrace {
   964  		blockPos := it.FileInfo
   965  
   966  		p.ignore() // ignore lookaheaded symbol
   967  		p.openblocks++
   968  
   969  		tree := ast.NewTree("rfork block")
   970  		r, err := p.parseBlock(blockPos.Line(), blockPos.Column())
   971  
   972  		if err != nil {
   973  			return nil, err
   974  		}
   975  
   976  		tree.Root = r
   977  
   978  		n.SetTree(tree)
   979  	}
   980  
   981  	if p.peek().Type() == token.Semicolon {
   982  		p.ignore()
   983  	}
   984  
   985  	return n, nil
   986  }
   987  
   988  func (p *Parser) parseIfExpr() (ast.Node, error) {
   989  	it := p.peek()
   990  	if it.Type() != token.Ident && it.Type() != token.String &&
   991  		it.Type() != token.Variable {
   992  		return nil, newParserError(it, p.name, "if requires lhs/rhs of type string, variable or function invocation. Found %v", it)
   993  	}
   994  
   995  	return p.getArgument(nil, exprConfig{
   996  		allowArg:      false,
   997  		allowVariadic: false,
   998  		allowFuncall:  true,
   999  		allowConcat:   true,
  1000  	})
  1001  }
  1002  
  1003  func (p *Parser) parseIf(it scanner.Token) (ast.Node, error) {
  1004  	n := ast.NewIfNode(it.FileInfo)
  1005  
  1006  	lvalue, err := p.parseIfExpr()
  1007  	if err != nil {
  1008  		return nil, err
  1009  	}
  1010  
  1011  	n.SetLvalue(lvalue)
  1012  
  1013  	it = p.next()
  1014  
  1015  	if it.Type() != token.Equal && it.Type() != token.NotEqual {
  1016  		return nil, newParserError(it, p.name, "Expected comparison, but found %v", it)
  1017  	}
  1018  
  1019  	if it.Value() != "==" && it.Value() != "!=" {
  1020  		return nil, newParserError(it, p.name, "Invalid if operator '%s'. Valid comparison operators are '==' and '!='",
  1021  			it.Value())
  1022  	}
  1023  
  1024  	n.SetOp(it.Value())
  1025  
  1026  	rvalue, err := p.parseIfExpr()
  1027  
  1028  	if err != nil {
  1029  		return nil, err
  1030  	}
  1031  
  1032  	n.SetRvalue(rvalue)
  1033  
  1034  	it = p.next()
  1035  
  1036  	if it.Type() != token.LBrace {
  1037  		return nil, newParserError(it, p.name, "Expected '{' but found %v", it)
  1038  	}
  1039  
  1040  	p.openblocks++
  1041  
  1042  	r, err := p.parseBlock(it.Line(), it.Column())
  1043  
  1044  	if err != nil {
  1045  		return nil, err
  1046  	}
  1047  
  1048  	ifTree := ast.NewTree("if block")
  1049  	ifTree.Root = r
  1050  	n.SetIfTree(ifTree)
  1051  
  1052  	it = p.peek()
  1053  
  1054  	if it.Type() == token.Else {
  1055  		p.next()
  1056  
  1057  		elseBlock, elseIf, err := p.parseElse()
  1058  
  1059  		if err != nil {
  1060  			return nil, err
  1061  		}
  1062  
  1063  		elseTree := ast.NewTree("else tree")
  1064  		elseTree.Root = elseBlock
  1065  
  1066  		n.SetElseif(elseIf)
  1067  		n.SetElseTree(elseTree)
  1068  	}
  1069  
  1070  	return n, nil
  1071  }
  1072  
  1073  func (p *Parser) parseFnArgs() ([]*ast.FnArgNode, error) {
  1074  	var args []*ast.FnArgNode
  1075  
  1076  	if p.peek().Type() == token.RParen {
  1077  		// no argument
  1078  		p.ignore()
  1079  		return args, nil
  1080  	}
  1081  
  1082  	for {
  1083  		it := p.next()
  1084  		if it.Type() == token.Ident {
  1085  			argName := it.Value()
  1086  			isVariadic := false
  1087  			if p.peek().Type() == token.Dotdotdot {
  1088  				isVariadic = true
  1089  				p.ignore()
  1090  			}
  1091  			args = append(args, ast.NewFnArgNode(it.FileInfo,
  1092  				argName, isVariadic))
  1093  		} else {
  1094  			return nil, newParserError(it, p.name, "Unexpected token %v. Expected identifier or ')'", it)
  1095  		}
  1096  
  1097  		it = p.peek()
  1098  		if it.Type() == token.Comma {
  1099  			p.ignore()
  1100  			it = p.peek()
  1101  
  1102  			if it.Type() == token.RParen {
  1103  				break
  1104  			}
  1105  			continue
  1106  		}
  1107  
  1108  		if it.Type() != token.RParen {
  1109  			return nil, newParserError(it, p.name, "Unexpected '%v'. Expected ')'", it)
  1110  		}
  1111  
  1112  		p.ignore()
  1113  		break
  1114  	}
  1115  
  1116  	return args, nil
  1117  }
  1118  
  1119  func (p *Parser) parseVar(it scanner.Token) (ast.Node, error) {
  1120  	var varTok = it
  1121  
  1122  	it = p.next()
  1123  	next := p.peek()
  1124  
  1125  	if it.Type() != token.Ident {
  1126  		return nil, newParserError(it, p.name,
  1127  			"Unexpected token %v. Expected IDENT",
  1128  			next,
  1129  		)
  1130  	}
  1131  
  1132  	if !isAssignment(next.Type()) {
  1133  		return nil, newParserError(next, p.name,
  1134  			"Unexpected token %v. Expected '=' or ','",
  1135  			next,
  1136  		)
  1137  	}
  1138  
  1139  	assign, err := p.parseAssignment(it)
  1140  	if err != nil {
  1141  		return nil, err
  1142  	}
  1143  
  1144  	switch assign.Type() {
  1145  	case ast.NodeAssign:
  1146  		return ast.NewVarAssignDecl(
  1147  			varTok.FileInfo,
  1148  			assign.(*ast.AssignNode),
  1149  		), nil
  1150  	case ast.NodeExecAssign:
  1151  		return ast.NewVarExecAssignDecl(
  1152  			varTok.FileInfo,
  1153  			assign.(*ast.ExecAssignNode),
  1154  		), nil
  1155  	}
  1156  
  1157  	return nil, newParserError(next, p.name,
  1158  		"Unexpected token %v. Expected ASSIGN or EXECASSIGN",
  1159  		next,
  1160  	)
  1161  }
  1162  
  1163  func (p *Parser) parseFnDecl(it scanner.Token) (ast.Node, error) {
  1164  	var n *ast.FnDeclNode
  1165  
  1166  	it = p.next()
  1167  	if it.Type() == token.Ident {
  1168  		n = ast.NewFnDeclNode(it.FileInfo, it.Value())
  1169  		it = p.next()
  1170  	} else {
  1171  		n = ast.NewFnDeclNode(it.FileInfo, "")
  1172  	}
  1173  
  1174  	if it.Type() != token.LParen {
  1175  		return nil, newParserError(it, p.name,
  1176  			"Unexpected token %v. Expected '('", it)
  1177  	}
  1178  
  1179  	args, err := p.parseFnArgs()
  1180  	if err != nil {
  1181  		return nil, err
  1182  	}
  1183  
  1184  	for _, arg := range args {
  1185  		n.AddArg(arg)
  1186  	}
  1187  
  1188  	it = p.next()
  1189  	if it.Type() != token.LBrace {
  1190  		return nil, newParserError(it, p.name,
  1191  			"Unexpected token %v. Expected '{'", it)
  1192  	}
  1193  
  1194  	p.openblocks++
  1195  
  1196  	tree := ast.NewTree(fmt.Sprintf("fn %s body", n.Name()))
  1197  	r, err := p.parseBlock(it.Line(), it.Column())
  1198  
  1199  	if err != nil {
  1200  		return nil, err
  1201  	}
  1202  
  1203  	tree.Root = r
  1204  	n.SetTree(tree)
  1205  	return n, nil
  1206  }
  1207  
  1208  func (p *Parser) parseFnInv(ident scanner.Token, allowSemicolon bool) (ast.Node, error) {
  1209  	n := ast.NewFnInvNode(ident.FileInfo, ident.Value())
  1210  
  1211  	it := p.next()
  1212  	if it.Type() != token.LParen {
  1213  		return nil, newParserError(it, p.name, "Invalid token %v. Expected '('", it)
  1214  	}
  1215  
  1216  	for {
  1217  		it = p.next()
  1218  		next := p.peek()
  1219  		if isFuncall(it.Type(), next.Type()) ||
  1220  			isValidArgument(it) {
  1221  			arg, err := p.getArgument(&it, exprConfig{
  1222  				allowArg:      false,
  1223  				allowFuncall:  true,
  1224  				allowConcat:   true,
  1225  				allowVariadic: true,
  1226  			})
  1227  			if err != nil {
  1228  				return nil, err
  1229  			}
  1230  
  1231  			n.AddArg(arg)
  1232  		} else if it.Type() == token.LParen {
  1233  			listArg, err := p.parseList(&it)
  1234  			if err != nil {
  1235  				return nil, err
  1236  			}
  1237  			n.AddArg(listArg)
  1238  		} else if it.Type() == token.RParen {
  1239  			//			p.next()
  1240  			break
  1241  		} else if it.Type() == token.EOF {
  1242  			goto parseError
  1243  		}
  1244  
  1245  		it = p.peek()
  1246  		if it.Type() == token.Comma {
  1247  			p.ignore()
  1248  
  1249  			continue
  1250  		}
  1251  
  1252  		if it.Type() == token.RParen {
  1253  			p.next()
  1254  			break
  1255  		}
  1256  
  1257  		goto parseError
  1258  	}
  1259  
  1260  	// semicolon is optional here
  1261  	if allowSemicolon && p.peek().Type() == token.Semicolon {
  1262  		p.next()
  1263  	}
  1264  
  1265  	return n, nil
  1266  
  1267  parseError:
  1268  	return nil, newParserError(it, p.name,
  1269  		"Unexpected token %v. Expecting STRING, VARIABLE or )", it)
  1270  }
  1271  
  1272  func (p *Parser) parseElse() (*ast.BlockNode, bool, error) {
  1273  	it := p.next()
  1274  
  1275  	if it.Type() == token.LBrace {
  1276  		p.openblocks++
  1277  
  1278  		elseBlock, err := p.parseBlock(it.Line(), it.Column())
  1279  
  1280  		if err != nil {
  1281  			return nil, false, err
  1282  		}
  1283  
  1284  		return elseBlock, false, nil
  1285  	}
  1286  
  1287  	if it.Type() == token.If {
  1288  		ifNode, err := p.parseIf(it)
  1289  
  1290  		if err != nil {
  1291  			return nil, false, err
  1292  		}
  1293  
  1294  		block := ast.NewBlockNode(it.FileInfo)
  1295  		block.Push(ifNode)
  1296  
  1297  		return block, true, nil
  1298  	}
  1299  
  1300  	return nil, false, newParserError(it, p.name, "Unexpected token: %v", it)
  1301  }
  1302  
  1303  func (p *Parser) parseBindFn(bindIt scanner.Token) (ast.Node, error) {
  1304  	nameIt := p.next()
  1305  
  1306  	if nameIt.Type() != token.Ident {
  1307  		return nil, newParserError(nameIt, p.name,
  1308  			"Expected identifier, but found '%v'", nameIt)
  1309  	}
  1310  
  1311  	cmdIt := p.next()
  1312  
  1313  	if cmdIt.Type() != token.Ident {
  1314  		return nil, newParserError(cmdIt, p.name, "Expected identifier, but found '%v'", cmdIt)
  1315  	}
  1316  
  1317  	if p.peek().Type() == token.Semicolon {
  1318  		p.ignore()
  1319  	}
  1320  
  1321  	n := ast.NewBindFnNode(bindIt.FileInfo, nameIt.Value(), cmdIt.Value())
  1322  	return n, nil
  1323  }
  1324  
  1325  func (p *Parser) parseReturn(retTok scanner.Token) (ast.Node, error) {
  1326  	ret := ast.NewReturnNode(retTok.FileInfo)
  1327  
  1328  	tok := p.peek()
  1329  
  1330  	// return;
  1331  	// return }
  1332  	// return $v
  1333  	// return "<some>"
  1334  	// return ( ... values ... )
  1335  	// return <fn name>()
  1336  	// return "val1", "val2", $val3, test()
  1337  	if tok.Type() != token.Semicolon &&
  1338  		tok.Type() != token.RBrace &&
  1339  		tok.Type() != token.Variable &&
  1340  		tok.Type() != token.String &&
  1341  		tok.Type() != token.LParen &&
  1342  		tok.Type() != token.Ident {
  1343  		return nil, newParserError(tok, p.name,
  1344  			"Expected ';', STRING, VARIABLE, FUNCALL or LPAREN, but found %v",
  1345  			tok)
  1346  	}
  1347  
  1348  	var returnExprs []ast.Expr
  1349  
  1350  	for {
  1351  		tok = p.peek()
  1352  		if tok.Type() == token.Semicolon {
  1353  			p.ignore()
  1354  			break
  1355  		}
  1356  
  1357  		if tok.Type() == token.RBrace {
  1358  			break
  1359  		}
  1360  
  1361  		if tok.Type() == token.LParen {
  1362  			listArg, err := p.parseList(nil)
  1363  			if err != nil {
  1364  				return nil, err
  1365  			}
  1366  			returnExprs = append(returnExprs, listArg)
  1367  		} else if tok.Type() == token.Ident {
  1368  			p.next()
  1369  			next := p.peek()
  1370  
  1371  			if next.Type() != token.LParen {
  1372  				return nil, newParserError(tok, p.name,
  1373  					"Expected FUNCALL, STRING, VARIABLE or LPAREN, but found '%v' %v",
  1374  					tok.Value(), next)
  1375  			}
  1376  
  1377  			arg, err := p.parseFnInv(tok, true)
  1378  			if err != nil {
  1379  				return nil, err
  1380  			}
  1381  
  1382  			returnExprs = append(returnExprs, arg)
  1383  		} else {
  1384  			arg, err := p.getArgument(nil, exprConfig{
  1385  				allowArg:      false,
  1386  				allowConcat:   true,
  1387  				allowFuncall:  true,
  1388  				allowVariadic: false,
  1389  			})
  1390  			if err != nil {
  1391  				return nil, err
  1392  			}
  1393  
  1394  			returnExprs = append(returnExprs, arg)
  1395  		}
  1396  
  1397  		next := p.peek()
  1398  
  1399  		if next.Type() == token.Comma {
  1400  			p.ignore()
  1401  			continue
  1402  		}
  1403  
  1404  		if next.Type() == token.Semicolon {
  1405  			p.ignore()
  1406  		}
  1407  
  1408  		break
  1409  	}
  1410  
  1411  	ret.Returns = returnExprs
  1412  
  1413  	return ret, nil
  1414  }
  1415  
  1416  func (p *Parser) parseFor(it scanner.Token) (ast.Node, error) {
  1417  	var (
  1418  		inExpr ast.Expr
  1419  		err    error
  1420  		next   scanner.Token
  1421  	)
  1422  
  1423  	forStmt := ast.NewForNode(it.FileInfo)
  1424  
  1425  	it = p.peek()
  1426  
  1427  	if it.Type() != token.Ident {
  1428  		goto forBlockParse
  1429  	}
  1430  
  1431  	p.next()
  1432  
  1433  	forStmt.SetIdentifier(it.Value())
  1434  
  1435  	it = p.next()
  1436  
  1437  	if it.Type() != token.Ident || it.Value() != "in" {
  1438  		return nil, newParserError(it, p.name,
  1439  			"Expected 'in' but found %q", it)
  1440  	}
  1441  
  1442  	// ignores 'in' keyword
  1443  	// TODO: make 'in' a real keyword
  1444  
  1445  	it = p.next()
  1446  	next = p.peek()
  1447  
  1448  	if it.Type() != token.Variable &&
  1449  		(it.Type() != token.Ident || (it.Type() == token.Ident && next.Type() != token.LParen)) &&
  1450  		it.Type() != token.LParen {
  1451  		return nil, newParserError(it, p.name,
  1452  			"Expected (variable, list or fn invocation) but found %q", it)
  1453  	}
  1454  
  1455  	if (it.Type() == token.Ident || it.Type() == token.Variable) && next.Type() == token.LParen {
  1456  		inExpr, err = p.parseFnInv(it, false)
  1457  	} else if it.Type() == token.Variable {
  1458  		inExpr, err = p.parseVariable(&it, false)
  1459  	} else if it.Type() == token.LParen {
  1460  		inExpr, err = p.parseList(&it)
  1461  	}
  1462  
  1463  	if err != nil {
  1464  		return nil, err
  1465  	}
  1466  
  1467  	forStmt.SetInExpr(inExpr)
  1468  forBlockParse:
  1469  	it = p.peek()
  1470  
  1471  	if it.Type() != token.LBrace {
  1472  		return nil, newParserError(it, p.name,
  1473  			"Expected '{' but found %q", it)
  1474  	}
  1475  
  1476  	blockPos := it.FileInfo
  1477  
  1478  	p.ignore() // ignore lookaheaded symbol
  1479  	p.openblocks++
  1480  
  1481  	tree := ast.NewTree("for block")
  1482  
  1483  	r, err := p.parseBlock(blockPos.Line(), blockPos.Column())
  1484  
  1485  	if err != nil {
  1486  		return nil, err
  1487  	}
  1488  
  1489  	tree.Root = r
  1490  	forStmt.SetTree(tree)
  1491  
  1492  	return forStmt, nil
  1493  }
  1494  
  1495  func (p *Parser) parseComment(it scanner.Token) (ast.Node, error) {
  1496  	return ast.NewCommentNode(it.FileInfo, it.Value()), nil
  1497  }
  1498  
  1499  func (p *Parser) parseError(it scanner.Token) (ast.Node, error) {
  1500  	return nil, errors.NewError(it.Value())
  1501  }
  1502  
  1503  func newParserError(item scanner.Token, name, format string, args ...interface{}) error {
  1504  	if item.Type() == token.Illegal {
  1505  		// scanner error
  1506  		return errors.NewError(item.Value())
  1507  	}
  1508  
  1509  	errstr := fmt.Sprintf(format, args...)
  1510  
  1511  	return errors.NewError("%s:%d:%d: %s", name, item.Line(), item.Column(), errstr)
  1512  }
  1513  
  1514  func isValidArgument(t scanner.Token) bool {
  1515  	if t.Type() == token.String ||
  1516  		t.Type() == token.Number ||
  1517  		t.Type() == token.Arg ||
  1518  		t.Type() == token.Dotdotdot ||
  1519  		t.Type() == token.Ident ||
  1520  		token.IsKeyword(t.Type()) ||
  1521  		t.Type() == token.Variable {
  1522  		return true
  1523  	}
  1524  
  1525  	return false
  1526  }
  1527  
  1528  func isFuncall(tok, next token.Token) bool {
  1529  	return (tok == token.Ident || tok == token.Variable) &&
  1530  		next == token.LParen
  1531  }
  1532  
  1533  func isAssignment(tok token.Token) bool {
  1534  	return tok == token.Assign ||
  1535  		tok == token.AssignCmd ||
  1536  		tok == token.LBrack ||
  1537  		tok == token.Comma
  1538  }
  1539  
  1540  func isExpr(tok token.Token) bool {
  1541  	return tok == token.Variable ||
  1542  		tok == token.String ||
  1543  		tok == token.LParen
  1544  }