github.com/ladydascalie/elvish@v0.0.0-20170703214355-2964dd3ece7f/parse/parse.go (about)

     1  // Package parse implements the elvish parser.
     2  package parse
     3  
     4  //go:generate ./boilerplate.py
     5  //go:generate stringer -type=PrimaryType,RedirMode -output=string.go
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"unicode"
    12  )
    13  
    14  // Parse parses Elvish source. If the error is not nil, it always has type
    15  // ParseError.
    16  func Parse(srcname, src string) (*Chunk, error) {
    17  	ps := NewParser(srcname, src)
    18  	n := ParseChunk(ps)
    19  	ps.Done()
    20  	return n, ps.Errors()
    21  }
    22  
    23  // Errors.
    24  var (
    25  	errUnexpectedRune         = errors.New("unexpected rune")
    26  	errShouldBeForm           = newError("", "form")
    27  	errBadLHS                 = errors.New("bad assignment LHS")
    28  	errDuplicateExitusRedir   = newError("duplicate exitus redir")
    29  	errShouldBeThen           = newError("", "then")
    30  	errShouldBeElifOrElseOrFi = newError("", "elif", "else", "fi")
    31  	errShouldBeFi             = newError("", "fi")
    32  	errShouldBeTried          = newError("", "tried")
    33  	errShouldBeDo             = newError("", "do")
    34  	errShouldBeDone           = newError("", "done")
    35  	errShouldBeIn             = newError("", "in")
    36  	errShouldBePipelineSep    = newError("", "';'", "newline")
    37  	errShouldBeEnd            = newError("", "end")
    38  	errBadRedirSign           = newError("bad redir sign", "'<'", "'>'", "'>>'", "'<>'")
    39  	errShouldBeFD             = newError("", "a composite term representing fd")
    40  	errShouldBeFilename       = newError("", "a composite term representing filename")
    41  	errShouldBeArray          = newError("", "spaced")
    42  	errStringUnterminated     = newError("string not terminated")
    43  	errInvalidEscape          = newError("invalid escape sequence")
    44  	errInvalidEscapeOct       = newError("invalid escape sequence", "octal digit")
    45  	errInvalidEscapeHex       = newError("invalid escape sequence", "hex digit")
    46  	errInvalidEscapeControl   = newError("invalid control sequence", "a rune between @ (0x40) and _(0x5F)")
    47  	errShouldBePrimary        = newError("",
    48  		"single-quoted string", "double-quoted string", "bareword")
    49  	errShouldBeVariableName       = newError("", "variable name")
    50  	errShouldBeRBracket           = newError("", "']'")
    51  	errShouldBeRBrace             = newError("", "'}'")
    52  	errShouldBeBraceSepOrRBracket = newError("", "','", "'}'")
    53  	errShouldBeRParen             = newError("", "')'")
    54  	errShouldBeBackquoteOrLParen  = newError("", "'`'", "'('")
    55  	errShouldBeBackquote          = newError("", "'`'")
    56  	errShouldBeCompound           = newError("", "compound")
    57  	errShouldBeEqual              = newError("", "'='")
    58  	errArgListAllowNoSemicolon    = newError("argument list doesn't allow semicolons")
    59  )
    60  
    61  // Chunk = { PipelineSep | Space } { Pipeline { PipelineSep | Space } }
    62  type Chunk struct {
    63  	node
    64  	Pipelines []*Pipeline
    65  }
    66  
    67  func (bn *Chunk) parse(ps *Parser) {
    68  	bn.parseSeps(ps)
    69  	for startsPipeline(ps.peek()) {
    70  		bn.addToPipelines(ParsePipeline(ps))
    71  		if bn.parseSeps(ps) == 0 {
    72  			break
    73  		}
    74  	}
    75  }
    76  
    77  func isPipelineSep(r rune) bool {
    78  	return r == '\n' || r == ';'
    79  }
    80  
    81  // parseSeps parses pipeline separators along with whitespaces. It returns the
    82  // number of pipeline separators parsed.
    83  func (bn *Chunk) parseSeps(ps *Parser) int {
    84  	nseps := 0
    85  	for {
    86  		r := ps.peek()
    87  		if isPipelineSep(r) {
    88  			// parse as a Sep
    89  			parseSep(bn, ps, r)
    90  			nseps++
    91  		} else if IsSpace(r) {
    92  			// parse a run of spaces as a Sep
    93  			parseSpaces(bn, ps)
    94  		} else if r == '#' {
    95  			// parse a comment as a Sep
    96  			for {
    97  				r := ps.peek()
    98  				if r == eof || r == '\n' {
    99  					break
   100  				}
   101  				ps.next()
   102  			}
   103  			addSep(bn, ps)
   104  			nseps++
   105  		} else {
   106  			break
   107  		}
   108  	}
   109  	return nseps
   110  }
   111  
   112  // Pipeline = Form { '|' Form }
   113  type Pipeline struct {
   114  	node
   115  	Forms      []*Form
   116  	Background bool
   117  }
   118  
   119  func (pn *Pipeline) parse(ps *Parser) {
   120  	pn.addToForms(ParseForm(ps))
   121  	for parseSep(pn, ps, '|') {
   122  		parseSpacesAndNewlines(pn, ps)
   123  		if !startsForm(ps.peek()) {
   124  			ps.error(errShouldBeForm)
   125  			return
   126  		}
   127  		pn.addToForms(ParseForm(ps))
   128  	}
   129  	parseSpaces(pn, ps)
   130  	if ps.peek() == '&' {
   131  		ps.next()
   132  		addSep(pn, ps)
   133  		pn.Background = true
   134  		parseSpaces(pn, ps)
   135  	}
   136  }
   137  
   138  func startsPipeline(r rune) bool {
   139  	return startsForm(r)
   140  }
   141  
   142  // Form = { Space } { { Assignment } { Space } }
   143  //        { Compound } { Space } { ( Compound | MapPair | Redir | ExitusRedir ) { Space } }
   144  type Form struct {
   145  	node
   146  	Assignments []*Assignment
   147  	Head        *Compound
   148  	// Left-hand-sides for the spacey assignment. Right-hand-sides are in Args.
   149  	Vars        []*Compound
   150  	Args        []*Compound
   151  	Opts        []*MapPair
   152  	Redirs      []*Redir
   153  	ExitusRedir *ExitusRedir
   154  }
   155  
   156  func (fn *Form) parse(ps *Parser) {
   157  	parseSpaces(fn, ps)
   158  	for fn.tryAssignment(ps) {
   159  		parseSpaces(fn, ps)
   160  	}
   161  
   162  	// Parse head.
   163  	if !startsCompound(ps.peek(), true) {
   164  		if len(fn.Assignments) > 0 {
   165  			// Assignment-only form.
   166  			return
   167  		}
   168  		// Bad form.
   169  		ps.error(fmt.Errorf("bad rune at form head: %q", ps.peek()))
   170  	}
   171  	fn.setHead(ParseCompound(ps, true))
   172  	parseSpaces(fn, ps)
   173  
   174  	for {
   175  		r := ps.peek()
   176  		switch {
   177  		case r == '&':
   178  			ps.next()
   179  			hasMapPair := startsCompound(ps.peek(), false)
   180  			ps.backup()
   181  			if !hasMapPair {
   182  				// background indicator
   183  				return
   184  			}
   185  			fn.addToOpts(ParseMapPair(ps))
   186  		case startsCompound(r, false):
   187  			if ps.hasPrefix("?>") {
   188  				if fn.ExitusRedir != nil {
   189  					ps.error(errDuplicateExitusRedir)
   190  					// Parse the duplicate redir anyway.
   191  					addChild(fn, ParseExitusRedir(ps))
   192  				} else {
   193  					fn.setExitusRedir(ParseExitusRedir(ps))
   194  				}
   195  				continue
   196  			}
   197  			cn := ParseCompound(ps, false)
   198  			if isRedirSign(ps.peek()) {
   199  				// Redir
   200  				fn.addToRedirs(ParseRedir(ps, cn))
   201  			} else if cn.sourceText == "=" {
   202  				// Spacey assignment.
   203  				// Turn the equal sign into a Sep.
   204  				addChild(fn, NewSep(ps.src, cn.begin, cn.end))
   205  				// Turn the head and preceding arguments into LHSs.
   206  				addLHS := func(cn *Compound) {
   207  					if len(cn.Indexings) == 1 && checkVariableInAssignment(cn.Indexings[0].Head, ps) {
   208  						fn.Vars = append(fn.Vars, cn)
   209  					} else {
   210  						ps.errorp(cn.begin, cn.end, errBadLHS)
   211  					}
   212  				}
   213  				addLHS(fn.Head)
   214  				fn.Head = nil
   215  				for _, cn := range fn.Args {
   216  					addLHS(cn)
   217  				}
   218  				fn.Args = nil
   219  			} else {
   220  				fn.addToArgs(cn)
   221  			}
   222  		case isRedirSign(r):
   223  			fn.addToRedirs(ParseRedir(ps, nil))
   224  		default:
   225  			return
   226  		}
   227  		parseSpaces(fn, ps)
   228  	}
   229  }
   230  
   231  // tryAssignment tries to parse an assignment. If succeeded, it adds the parsed
   232  // assignment to fn.Assignments and returns true. Otherwise it rewinds the
   233  // parser and returns false.
   234  func (fn *Form) tryAssignment(ps *Parser) bool {
   235  	if !startsIndexing(ps.peek(), false) || ps.peek() == '=' {
   236  		return false
   237  	}
   238  
   239  	pos := ps.pos
   240  	errorEntries := ps.errors.Entries
   241  	an := ParseAssignment(ps)
   242  	// If errors were added, revert
   243  	if len(ps.errors.Entries) > len(errorEntries) {
   244  		ps.errors.Entries = errorEntries
   245  		ps.pos = pos
   246  		return false
   247  	}
   248  	fn.addToAssignments(an)
   249  	return true
   250  }
   251  
   252  func startsForm(r rune) bool {
   253  	return IsSpace(r) || startsCompound(r, true)
   254  }
   255  
   256  // Assignment = Indexing '=' Compound
   257  type Assignment struct {
   258  	node
   259  	Left  *Indexing
   260  	Right *Compound
   261  }
   262  
   263  func (an *Assignment) parse(ps *Parser) {
   264  	ps.cut('=')
   265  	an.setLeft(ParseIndexing(ps, false))
   266  	head := an.Left.Head
   267  	if !checkVariableInAssignment(head, ps) {
   268  		ps.errorp(head.Begin(), head.End(), errShouldBeVariableName)
   269  	}
   270  	ps.uncut('=')
   271  
   272  	if !parseSep(an, ps, '=') {
   273  		ps.error(errShouldBeEqual)
   274  	}
   275  	an.setRight(ParseCompound(ps, false))
   276  }
   277  
   278  func checkVariableInAssignment(p *Primary, ps *Parser) bool {
   279  	if p.Type == Braced {
   280  		// XXX don't check further inside braced expression
   281  		return true
   282  	}
   283  	if p.Type != Bareword && p.Type != SingleQuoted && p.Type != DoubleQuoted {
   284  		return false
   285  	}
   286  	if p.Value == "" {
   287  		return false
   288  	}
   289  	for _, r := range p.Value {
   290  		// XXX special case '&' and '@'.
   291  		if !allowedInVariableName(r) && r != '&' && r != '@' {
   292  			return false
   293  		}
   294  	}
   295  	return true
   296  }
   297  
   298  // ExitusRedir = '?' '>' { Space } Compound
   299  type ExitusRedir struct {
   300  	node
   301  	Dest *Compound
   302  }
   303  
   304  func (ern *ExitusRedir) parse(ps *Parser) {
   305  	ps.next()
   306  	ps.next()
   307  	addSep(ern, ps)
   308  	parseSpaces(ern, ps)
   309  	ern.setDest(ParseCompound(ps, false))
   310  }
   311  
   312  // Redir = { Compound } { '<'|'>'|'<>'|'>>' } { Space } ( '&'? Compound )
   313  type Redir struct {
   314  	node
   315  	Left      *Compound
   316  	Mode      RedirMode
   317  	RightIsFd bool
   318  	Right     *Compound
   319  }
   320  
   321  func (rn *Redir) parse(ps *Parser, dest *Compound) {
   322  	// The parsing of the Left part is done in Form.parse.
   323  	if dest != nil {
   324  		rn.setLeft(dest)
   325  		rn.begin = dest.begin
   326  	}
   327  
   328  	begin := ps.pos
   329  	for isRedirSign(ps.peek()) {
   330  		ps.next()
   331  	}
   332  	sign := ps.src[begin:ps.pos]
   333  	switch sign {
   334  	case "<":
   335  		rn.Mode = Read
   336  	case ">":
   337  		rn.Mode = Write
   338  	case ">>":
   339  		rn.Mode = Append
   340  	case "<>":
   341  		rn.Mode = ReadWrite
   342  	default:
   343  		ps.error(errBadRedirSign)
   344  	}
   345  	addSep(rn, ps)
   346  	parseSpaces(rn, ps)
   347  	if parseSep(rn, ps, '&') {
   348  		rn.RightIsFd = true
   349  	}
   350  	rn.setRight(ParseCompound(ps, false))
   351  	if len(rn.Right.Indexings) == 0 {
   352  		if rn.RightIsFd {
   353  			ps.error(errShouldBeFD)
   354  		} else {
   355  			ps.error(errShouldBeFilename)
   356  		}
   357  		return
   358  	}
   359  }
   360  
   361  func isRedirSign(r rune) bool {
   362  	return r == '<' || r == '>'
   363  }
   364  
   365  // RedirMode records the mode of an IO redirection.
   366  type RedirMode int
   367  
   368  // Possible values for RedirMode.
   369  const (
   370  	BadRedirMode RedirMode = iota
   371  	Read
   372  	Write
   373  	ReadWrite
   374  	Append
   375  )
   376  
   377  // Compound = { Indexing }
   378  type Compound struct {
   379  	node
   380  	Indexings []*Indexing
   381  }
   382  
   383  func (cn *Compound) parse(ps *Parser, head bool) {
   384  	cn.tilde(ps)
   385  	for startsIndexing(ps.peek(), head) {
   386  		cn.addToIndexings(ParseIndexing(ps, head))
   387  	}
   388  }
   389  
   390  // tilde parses a tilde if there is one. It is implemented here instead of
   391  // within Primary since a tilde can only appear as the first part of a
   392  // Compound. Elsewhere tildes are barewords.
   393  func (cn *Compound) tilde(ps *Parser) {
   394  	if ps.peek() == '~' {
   395  		ps.next()
   396  		base := node{nil, ps.pos - 1, ps.pos, "~", nil}
   397  		pn := &Primary{node: base, Type: Tilde, Value: "~"}
   398  		in := &Indexing{node: base}
   399  		in.setHead(pn)
   400  		cn.addToIndexings(in)
   401  	}
   402  }
   403  
   404  func startsCompound(r rune, head bool) bool {
   405  	return startsIndexing(r, head)
   406  }
   407  
   408  // Indexing = Primary { '[' Array ']' }
   409  type Indexing struct {
   410  	node
   411  	Head     *Primary
   412  	Indicies []*Array
   413  }
   414  
   415  func (in *Indexing) parse(ps *Parser, head bool) {
   416  	in.setHead(ParsePrimary(ps, head))
   417  	for parseSep(in, ps, '[') {
   418  		if !startsArray(ps.peek()) {
   419  			ps.error(errShouldBeArray)
   420  		}
   421  
   422  		ps.pushCutset()
   423  		in.addToIndicies(ParseArray(ps, false))
   424  		ps.popCutset()
   425  
   426  		if !parseSep(in, ps, ']') {
   427  			ps.error(errShouldBeRBracket)
   428  			return
   429  		}
   430  	}
   431  }
   432  
   433  func startsIndexing(r rune, head bool) bool {
   434  	return startsPrimary(r, head)
   435  }
   436  
   437  // Array = { Space | '\n' } { Compound { Space | '\n' } }
   438  type Array struct {
   439  	node
   440  	Compounds []*Compound
   441  	// When non-empty, records the occurrences of semicolons by the indices of
   442  	// the compounds they appear before. For instance, [; ; a b; c d;] results
   443  	// in Semicolons={0 0 2 4}.
   444  	Semicolons []int
   445  }
   446  
   447  func (sn *Array) parse(ps *Parser, allowSemicolon bool) {
   448  	parseSep := func() {
   449  		parseSpacesAndNewlines(sn, ps)
   450  		if allowSemicolon {
   451  			for parseSep(sn, ps, ';') {
   452  				sn.Semicolons = append(sn.Semicolons, len(sn.Compounds))
   453  			}
   454  			parseSpacesAndNewlines(sn, ps)
   455  		}
   456  	}
   457  
   458  	parseSep()
   459  	for startsCompound(ps.peek(), false) {
   460  		sn.addToCompounds(ParseCompound(ps, false))
   461  		parseSep()
   462  	}
   463  }
   464  
   465  func IsSpace(r rune) bool {
   466  	return r == ' ' || r == '\t'
   467  }
   468  
   469  func startsArray(r rune) bool {
   470  	return IsSpaceOrNewline(r) || startsIndexing(r, false)
   471  }
   472  
   473  // Primary is the smallest expression unit.
   474  type Primary struct {
   475  	node
   476  	Type PrimaryType
   477  	// The unquoted string value. Valid for Bareword, SingleQuoted,
   478  	// DoubleQuoted, Variable, Wildcard and Tilde.
   479  	Value    string
   480  	List     *Array      // Valid for List and Lambda
   481  	Chunk    *Chunk      // Valid for OutputCapture, ExitusCapture and Lambda
   482  	MapPairs []*MapPair  // Valid for Map
   483  	Braced   []*Compound // Valid for Braced
   484  	IsRange  []bool      // Valid for Braced
   485  }
   486  
   487  // PrimaryType is the type of a Primary.
   488  type PrimaryType int
   489  
   490  // Possible values for PrimaryType.
   491  const (
   492  	BadPrimary PrimaryType = iota
   493  	Bareword
   494  	SingleQuoted
   495  	DoubleQuoted
   496  	Variable
   497  	Wildcard
   498  	Tilde
   499  	ExceptionCapture
   500  	OutputCapture
   501  	List
   502  	Lambda
   503  	Map
   504  	Braced
   505  )
   506  
   507  func (pn *Primary) parse(ps *Parser, head bool) {
   508  	r := ps.peek()
   509  	if !startsPrimary(r, head) {
   510  		ps.error(errShouldBePrimary)
   511  		return
   512  	}
   513  
   514  	// Try bareword early, since it has precedence over wildcard on *
   515  	// when head is true.
   516  	if allowedInBareword(r, head) {
   517  		pn.bareword(ps, head)
   518  		return
   519  	}
   520  
   521  	switch r {
   522  	case '\'':
   523  		pn.singleQuoted(ps)
   524  	case '"':
   525  		pn.doubleQuoted(ps)
   526  	case '$':
   527  		pn.variable(ps)
   528  	case '*':
   529  		pn.wildcard(ps)
   530  	case '?':
   531  		if ps.hasPrefix("?(") {
   532  			pn.exitusCapture(ps)
   533  		} else {
   534  			pn.wildcard(ps)
   535  		}
   536  	case '(', '`':
   537  		pn.outputCapture(ps)
   538  	case '[':
   539  		pn.lbracket(ps)
   540  	case '{':
   541  		pn.lbrace(ps)
   542  	default:
   543  		// Parse an empty bareword.
   544  		pn.Type = Bareword
   545  	}
   546  }
   547  
   548  func (pn *Primary) singleQuoted(ps *Parser) {
   549  	pn.Type = SingleQuoted
   550  	ps.next()
   551  	var buf bytes.Buffer
   552  	defer func() { pn.Value = buf.String() }()
   553  	for {
   554  		switch r := ps.next(); r {
   555  		case eof:
   556  			ps.error(errStringUnterminated)
   557  			return
   558  		case '\'':
   559  			if ps.peek() == '\'' {
   560  				// Two consecutive single quotes
   561  				ps.next()
   562  				buf.WriteByte('\'')
   563  			} else {
   564  				// End of string
   565  				return
   566  			}
   567  		default:
   568  			buf.WriteRune(r)
   569  		}
   570  	}
   571  }
   572  
   573  func (pn *Primary) doubleQuoted(ps *Parser) {
   574  	pn.Type = DoubleQuoted
   575  	ps.next()
   576  	var buf bytes.Buffer
   577  	defer func() { pn.Value = buf.String() }()
   578  	for {
   579  		switch r := ps.next(); r {
   580  		case eof:
   581  			ps.error(errStringUnterminated)
   582  			return
   583  		case '"':
   584  			return
   585  		case '\\':
   586  			switch r := ps.next(); r {
   587  			case 'c', '^':
   588  				// Control sequence
   589  				r := ps.next()
   590  				if r < 0x40 || r >= 0x60 {
   591  					ps.backup()
   592  					ps.error(errInvalidEscapeControl)
   593  					ps.next()
   594  				}
   595  				buf.WriteByte(byte(r - 0x40))
   596  			case 'x', 'u', 'U':
   597  				var n int
   598  				switch r {
   599  				case 'x':
   600  					n = 2
   601  				case 'u':
   602  					n = 4
   603  				case 'U':
   604  					n = 8
   605  				}
   606  				var rr rune
   607  				for i := 0; i < n; i++ {
   608  					d, ok := hexToDigit(ps.next())
   609  					if !ok {
   610  						ps.backup()
   611  						ps.error(errInvalidEscapeHex)
   612  						break
   613  					}
   614  					rr = rr*16 + d
   615  				}
   616  				buf.WriteRune(rr)
   617  			case '0', '1', '2', '3', '4', '5', '6', '7':
   618  				// 2 more octal digits
   619  				rr := r - '0'
   620  				for i := 0; i < 2; i++ {
   621  					r := ps.next()
   622  					if r < '0' || r > '7' {
   623  						ps.backup()
   624  						ps.error(errInvalidEscapeOct)
   625  						break
   626  					}
   627  					rr = rr*8 + (r - '0')
   628  				}
   629  				buf.WriteRune(rr)
   630  			default:
   631  				if rr, ok := doubleEscape[r]; ok {
   632  					buf.WriteRune(rr)
   633  				} else {
   634  					ps.backup()
   635  					ps.error(errInvalidEscape)
   636  					ps.next()
   637  				}
   638  			}
   639  		default:
   640  			buf.WriteRune(r)
   641  		}
   642  	}
   643  }
   644  
   645  // a table for the simple double-quote escape sequences.
   646  var doubleEscape = map[rune]rune{
   647  	// same as golang
   648  	'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r',
   649  	't': '\t', 'v': '\v', '\\': '\\', '"': '"',
   650  	// additional
   651  	'e': '\033',
   652  }
   653  
   654  var doubleUnescape = map[rune]rune{}
   655  
   656  func init() {
   657  	for k, v := range doubleEscape {
   658  		doubleUnescape[v] = k
   659  	}
   660  }
   661  
   662  func hexToDigit(r rune) (rune, bool) {
   663  	switch {
   664  	case '0' <= r && r <= '9':
   665  		return r - '0', true
   666  	case 'a' <= r && r <= 'f':
   667  		return r - 'a' + 10, true
   668  	case 'A' <= r && r <= 'F':
   669  		return r - 'A' + 10, true
   670  	default:
   671  		return -1, false
   672  	}
   673  }
   674  
   675  func (pn *Primary) variable(ps *Parser) {
   676  	pn.Type = Variable
   677  	defer func() { pn.Value = ps.src[pn.begin+1 : ps.pos] }()
   678  	ps.next()
   679  	// The character of the variable name can be anything.
   680  	if ps.next() == eof {
   681  		ps.backup()
   682  		ps.error(errShouldBeVariableName)
   683  		ps.next()
   684  	}
   685  	for allowedInVariableName(ps.peek()) {
   686  		ps.next()
   687  	}
   688  }
   689  
   690  // The following are allowed in variable names:
   691  // * Anything beyond ASCII that is printable
   692  // * Letters and numbers
   693  // * The symbols "-_:&"
   694  func allowedInVariableName(r rune) bool {
   695  	return (r >= 0x80 && unicode.IsPrint(r)) ||
   696  		('0' <= r && r <= '9') ||
   697  		('a' <= r && r <= 'z') ||
   698  		('A' <= r && r <= 'Z') ||
   699  		r == '-' || r == '_' || r == ':' || r == '&'
   700  }
   701  
   702  func (pn *Primary) wildcard(ps *Parser) {
   703  	pn.Type = Wildcard
   704  	for isWildcard(ps.peek()) {
   705  		ps.next()
   706  	}
   707  	pn.Value = ps.src[pn.begin:ps.pos]
   708  }
   709  
   710  func isWildcard(r rune) bool {
   711  	return r == '*' || r == '?'
   712  }
   713  
   714  func (pn *Primary) exitusCapture(ps *Parser) {
   715  	ps.next()
   716  	ps.next()
   717  	addSep(pn, ps)
   718  
   719  	pn.Type = ExceptionCapture
   720  
   721  	ps.pushCutset()
   722  	pn.setChunk(ParseChunk(ps))
   723  	ps.popCutset()
   724  
   725  	if !parseSep(pn, ps, ')') {
   726  		ps.error(errShouldBeRParen)
   727  	}
   728  }
   729  
   730  func (pn *Primary) outputCapture(ps *Parser) {
   731  	pn.Type = OutputCapture
   732  
   733  	var closer rune
   734  	var shouldBeCloser error
   735  
   736  	switch ps.next() {
   737  	case '(':
   738  		closer = ')'
   739  		shouldBeCloser = errShouldBeRParen
   740  	case '`':
   741  		closer = '`'
   742  		shouldBeCloser = errShouldBeBackquote
   743  	default:
   744  		ps.backup()
   745  		ps.error(errShouldBeBackquoteOrLParen)
   746  		ps.next()
   747  		return
   748  	}
   749  	addSep(pn, ps)
   750  
   751  	if closer == '`' {
   752  		ps.pushCutset(closer)
   753  	} else {
   754  		ps.pushCutset()
   755  	}
   756  	pn.setChunk(ParseChunk(ps))
   757  	ps.popCutset()
   758  
   759  	if !parseSep(pn, ps, closer) {
   760  		ps.error(shouldBeCloser)
   761  	}
   762  }
   763  
   764  // List   = '[' { Space } Array ']'
   765  // Lambda = List '{' Chunk '}'
   766  // Map    = '[' { Space } '&' { Space } ']'
   767  //        = '[' { Space } { MapPair { Space } } ']'
   768  
   769  func (pn *Primary) lbracket(ps *Parser) {
   770  	parseSep(pn, ps, '[')
   771  	parseSpacesAndNewlines(pn, ps)
   772  
   773  	r := ps.peek()
   774  	ps.pushCutset()
   775  
   776  	switch {
   777  	case r == '&':
   778  		pn.Type = Map
   779  		// parseSep(pn, ps, '&')
   780  		amp := ps.pos
   781  		ps.next()
   782  		r := ps.peek()
   783  		switch {
   784  		case IsSpace(r), r == ']', r == eof:
   785  			// '&' { Space } ']': '&' is a sep
   786  			addSep(pn, ps)
   787  			parseSpaces(pn, ps)
   788  		default:
   789  			// { MapPair { Space } } ']': Wind back
   790  			ps.pos = amp
   791  			for ps.peek() == '&' {
   792  				pn.addToMapPairs(ParseMapPair(ps))
   793  				parseSpacesAndNewlines(pn, ps)
   794  			}
   795  		}
   796  		ps.popCutset()
   797  		if !parseSep(pn, ps, ']') {
   798  			ps.error(errShouldBeRBracket)
   799  		}
   800  	default:
   801  		pn.setList(ParseArray(ps, true))
   802  		ps.popCutset()
   803  
   804  		if !parseSep(pn, ps, ']') {
   805  			ps.error(errShouldBeRBracket)
   806  		}
   807  		if parseSep(pn, ps, '{') {
   808  			if len(pn.List.Semicolons) > 0 {
   809  				ps.errorp(pn.List.Begin(), pn.List.End(), errArgListAllowNoSemicolon)
   810  			}
   811  			pn.lambda(ps)
   812  		} else {
   813  			pn.Type = List
   814  		}
   815  	}
   816  }
   817  
   818  // lambda parses a lambda expression. The opening brace has been seen.
   819  func (pn *Primary) lambda(ps *Parser) {
   820  	pn.Type = Lambda
   821  	ps.pushCutset()
   822  	pn.setChunk(ParseChunk(ps))
   823  	ps.popCutset()
   824  	if !parseSep(pn, ps, '}') {
   825  		ps.error(errShouldBeRBrace)
   826  	}
   827  }
   828  
   829  // Braced = '{' Compound { BracedSep Compounds } '}'
   830  // BracedSep = { Space | '\n' } [ ',' ] { Space | '\n' }
   831  func (pn *Primary) lbrace(ps *Parser) {
   832  	parseSep(pn, ps, '{')
   833  
   834  	if r := ps.peek(); r == ';' || r == '\n' || IsSpace(r) {
   835  		pn.lambda(ps)
   836  		return
   837  	}
   838  
   839  	pn.Type = Braced
   840  
   841  	ps.pushCutset()
   842  	defer ps.popCutset()
   843  
   844  	// XXX: The compound can be empty, which allows us to parse {,foo}.
   845  	// Allowing compounds to be empty can be fragile in other cases.
   846  	ps.cut(',')
   847  	pn.addToBraced(ParseCompound(ps, false))
   848  	ps.uncut(',')
   849  
   850  	for isBracedSep(ps.peek()) {
   851  		parseSpacesAndNewlines(pn, ps)
   852  		// optional, so ignore the return value
   853  		parseSep(pn, ps, ',')
   854  		parseSpacesAndNewlines(pn, ps)
   855  
   856  		ps.cut(',')
   857  		pn.addToBraced(ParseCompound(ps, false))
   858  		ps.uncut(',')
   859  	}
   860  	if !parseSep(pn, ps, '}') {
   861  		ps.error(errShouldBeBraceSepOrRBracket)
   862  	}
   863  }
   864  
   865  func isBracedSep(r rune) bool {
   866  	return r == ',' || IsSpaceOrNewline(r)
   867  }
   868  
   869  func (pn *Primary) bareword(ps *Parser, head bool) {
   870  	pn.Type = Bareword
   871  	defer func() { pn.Value = ps.src[pn.begin:ps.pos] }()
   872  	for allowedInBareword(ps.peek(), head) {
   873  		ps.next()
   874  	}
   875  }
   876  
   877  // The following are allowed in barewords:
   878  // * Anything allowed in variable names, except &
   879  // * The symbols "%+,./=@~!\"
   880  // * The symbols "<>*^", if the bareword is in head
   881  //
   882  // The seemingly weird inclusion of \ is for easier path manipulation in
   883  // Windows.
   884  func allowedInBareword(r rune, head bool) bool {
   885  	return (r != '&' && allowedInVariableName(r)) ||
   886  		r == '%' || r == '+' || r == ',' || r == '.' ||
   887  		r == '/' || r == '=' || r == '@' || r == '~' || r == '!' || r == '\\' ||
   888  		(head && (r == '<' || r == '>' || r == '*' || r == '^'))
   889  }
   890  
   891  func startsPrimary(r rune, head bool) bool {
   892  	return r == '\'' || r == '"' || r == '$' || allowedInBareword(r, head) ||
   893  		r == '?' || r == '*' || r == '(' || r == '`' || r == '[' || r == '{'
   894  }
   895  
   896  // MapPair = '&' { Space } Compound { Space } Compound
   897  type MapPair struct {
   898  	node
   899  	Key, Value *Compound
   900  }
   901  
   902  func (mpn *MapPair) parse(ps *Parser) {
   903  	parseSep(mpn, ps, '&')
   904  
   905  	// Parse key part, cutting on '='.
   906  	ps.cut('=')
   907  	mpn.setKey(ParseCompound(ps, false))
   908  	if len(mpn.Key.Indexings) == 0 {
   909  		ps.error(errShouldBeCompound)
   910  	}
   911  	ps.uncut('=')
   912  
   913  	if parseSep(mpn, ps, '=') {
   914  		parseSpacesAndNewlines(mpn, ps)
   915  		// Parse value part.
   916  		mpn.setValue(ParseCompound(ps, false))
   917  		// The value part can be empty.
   918  	}
   919  }
   920  
   921  // Sep is the catch-all node type for leaf nodes that lack internal structures
   922  // and semantics, and serve solely for syntactic purposes. The parsing of
   923  // separators depend on the Parent node; as such it lacks a genuine parse
   924  // method.
   925  type Sep struct {
   926  	node
   927  }
   928  
   929  func NewSep(src string, begin, end int) *Sep {
   930  	return &Sep{node{nil, begin, end, src[begin:end], nil}}
   931  }
   932  
   933  func addSep(n Node, ps *Parser) {
   934  	var begin int
   935  	ch := n.Children()
   936  	if len(ch) > 0 {
   937  		begin = ch[len(ch)-1].End()
   938  	} else {
   939  		begin = n.Begin()
   940  	}
   941  	addChild(n, NewSep(ps.src, begin, ps.pos))
   942  }
   943  
   944  func parseSep(n Node, ps *Parser, sep rune) bool {
   945  	if ps.peek() == sep {
   946  		ps.next()
   947  		addSep(n, ps)
   948  		return true
   949  	}
   950  	return false
   951  }
   952  
   953  func parseSpaces(n Node, ps *Parser) {
   954  	if !IsSpace(ps.peek()) {
   955  		return
   956  	}
   957  	ps.next()
   958  	for IsSpace(ps.peek()) {
   959  		ps.next()
   960  	}
   961  	addSep(n, ps)
   962  }
   963  
   964  func parseSpacesAndNewlines(n Node, ps *Parser) {
   965  	// TODO parse comments here.
   966  	if !IsSpaceOrNewline(ps.peek()) {
   967  		return
   968  	}
   969  	ps.next()
   970  	for IsSpaceOrNewline(ps.peek()) {
   971  		ps.next()
   972  	}
   973  	addSep(n, ps)
   974  }
   975  
   976  func IsSpaceOrNewline(r rune) bool {
   977  	return IsSpace(r) || r == '\n'
   978  }
   979  
   980  func addChild(p Node, ch Node) {
   981  	p.n().children = append(p.n().children, ch)
   982  	ch.n().parent = p
   983  }