mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
Make parse report all errors.
This commit is contained in:
parent
af9ca8cd14
commit
5c8a8d5eec
|
@ -28,7 +28,7 @@ func parserError(text string) Token {
|
|||
|
||||
func tokenize(src string) ([]Token, error) {
|
||||
lastEnd := 0
|
||||
n, err := parse.Parse("[interactive code]", src)
|
||||
n, err := parse.Parse(src)
|
||||
if n == nil {
|
||||
return []Token{{ParserError, src, nil, ""}}, err
|
||||
}
|
||||
|
|
30
errutil/errors.go
Normal file
30
errutil/errors.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package errutil
|
||||
|
||||
import "bytes"
|
||||
|
||||
type Errors struct {
|
||||
Errors []error
|
||||
}
|
||||
|
||||
func (es *Errors) Error() string {
|
||||
switch len(es.Errors) {
|
||||
case 0:
|
||||
return "no error"
|
||||
case 1:
|
||||
return es.Errors[0].Error()
|
||||
default:
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("multiple errors: ")
|
||||
for i, e := range es.Errors {
|
||||
if i > 0 {
|
||||
buf.WriteString("; ")
|
||||
}
|
||||
buf.WriteString(e.Error())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func (es *Errors) Append(e error) {
|
||||
es.Errors = append(es.Errors, e)
|
||||
}
|
13
errutil/pos_error.go
Normal file
13
errutil/pos_error.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package errutil
|
||||
|
||||
import "fmt"
|
||||
|
||||
type PosError struct {
|
||||
Begin int
|
||||
End int
|
||||
Err error
|
||||
}
|
||||
|
||||
func (pe *PosError) Error() string {
|
||||
return fmt.Sprintf("%d-%d: %s", pe.Begin, pe.End, pe.Err.Error())
|
||||
}
|
|
@ -214,7 +214,7 @@ func (ec *evalCtx) mustSingleString(vs []Value, what string, p int) String {
|
|||
|
||||
// SourceText evaluates a chunk of elvish source.
|
||||
func (ev *Evaler) SourceText(name, src, dir string) error {
|
||||
n, err := parse.Parse(name, src)
|
||||
n, err := parse.Parse(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
13
main.go
13
main.go
|
@ -131,7 +131,7 @@ func interact() {
|
|||
fmt.Println("My pid is", os.Getpid())
|
||||
}
|
||||
|
||||
n, err := parse.Parse(name, lr.Line)
|
||||
n, err := parse.Parse(lr.Line)
|
||||
printError(err)
|
||||
|
||||
if err == nil {
|
||||
|
@ -171,9 +171,14 @@ func printError(err error) {
|
|||
if err == nil {
|
||||
return
|
||||
}
|
||||
if ce, ok := err.(*errutil.ContextualError); ok {
|
||||
fmt.Fprint(os.Stderr, ce.Pprint())
|
||||
} else {
|
||||
switch err := err.(type) {
|
||||
case *errutil.ContextualError:
|
||||
fmt.Print(err.Pprint())
|
||||
case *errutil.Errors:
|
||||
for _, e := range err.Errors {
|
||||
printError(e)
|
||||
}
|
||||
default:
|
||||
eval.PprintError(err)
|
||||
fmt.Println()
|
||||
}
|
||||
|
|
|
@ -1,120 +1,25 @@
|
|||
package parse
|
||||
|
||||
func (n *MapPair) setKey(ch *Compound) {
|
||||
n.Key = ch
|
||||
func (n *Chunk) addToPipelines(ch *Pipeline) {
|
||||
n.Pipelines = append(n.Pipelines, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *MapPair) setValue(ch *Compound) {
|
||||
n.Value = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseMapPair(ps *parser, cut runePred) *MapPair {
|
||||
n := &MapPair{node: node{begin: ps.pos}}
|
||||
func parseChunk(ps *parser, cut runePred) *Chunk {
|
||||
n := &Chunk{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Primary) setList(ch *Array) {
|
||||
n.List = ch
|
||||
func (n *Pipeline) addToForms(ch *Form) {
|
||||
n.Forms = append(n.Forms, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Primary) setChunk(ch *Chunk) {
|
||||
n.Chunk = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Primary) addToMapPairs(ch *MapPair) {
|
||||
n.MapPairs = append(n.MapPairs, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Primary) addToBraced(ch *Compound) {
|
||||
n.Braced = append(n.Braced, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parsePrimary(ps *parser, cut runePred) *Primary {
|
||||
n := &Primary{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Indexing) setHead(ch *Primary) {
|
||||
n.Head = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Indexing) addToIndicies(ch *Array) {
|
||||
n.Indicies = append(n.Indicies, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseIndexing(ps *parser, cut runePred) *Indexing {
|
||||
n := &Indexing{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Compound) addToIndexings(ch *Indexing) {
|
||||
n.Indexings = append(n.Indexings, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseCompound(ps *parser, cut runePred) *Compound {
|
||||
n := &Compound{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Array) addToCompounds(ch *Compound) {
|
||||
n.Compounds = append(n.Compounds, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseArray(ps *parser) *Array {
|
||||
n := &Array{node: node{begin: ps.pos}}
|
||||
n.parse(ps)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Redir) setDest(ch *Compound) {
|
||||
n.Dest = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Redir) setSource(ch *Compound) {
|
||||
n.Source = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseRedir(ps *parser, cut runePred, dest *Compound) *Redir {
|
||||
n := &Redir{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut, dest)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *ExitusRedir) setDest(ch *Compound) {
|
||||
n.Dest = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseExitusRedir(ps *parser, cut runePred) *ExitusRedir {
|
||||
n := &ExitusRedir{node: node{begin: ps.pos}}
|
||||
func parsePipeline(ps *parser, cut runePred) *Pipeline {
|
||||
n := &Pipeline{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
|
@ -169,34 +74,129 @@ func (n *Assignment) setSrc(ch *Compound) {
|
|||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseAssignment(ps *parser, cut runePred) *Assignment {
|
||||
func parseAssignment(ps *parser, cut runePred, pok *bool) *Assignment {
|
||||
n := &Assignment{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.parse(ps, cut, pok)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Pipeline) addToForms(ch *Form) {
|
||||
n.Forms = append(n.Forms, ch)
|
||||
func (n *ExitusRedir) setDest(ch *Compound) {
|
||||
n.Dest = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parsePipeline(ps *parser, cut runePred) *Pipeline {
|
||||
n := &Pipeline{node: node{begin: ps.pos}}
|
||||
func parseExitusRedir(ps *parser, cut runePred) *ExitusRedir {
|
||||
n := &ExitusRedir{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Chunk) addToPipelines(ch *Pipeline) {
|
||||
n.Pipelines = append(n.Pipelines, ch)
|
||||
func (n *Redir) setDest(ch *Compound) {
|
||||
n.Dest = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseChunk(ps *parser, cut runePred) *Chunk {
|
||||
n := &Chunk{node: node{begin: ps.pos}}
|
||||
func (n *Redir) setSource(ch *Compound) {
|
||||
n.Source = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseRedir(ps *parser, cut runePred, dest *Compound) *Redir {
|
||||
n := &Redir{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut, dest)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Compound) addToIndexings(ch *Indexing) {
|
||||
n.Indexings = append(n.Indexings, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseCompound(ps *parser, cut runePred) *Compound {
|
||||
n := &Compound{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Indexing) setHead(ch *Primary) {
|
||||
n.Head = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Indexing) addToIndicies(ch *Array) {
|
||||
n.Indicies = append(n.Indicies, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseIndexing(ps *parser, cut runePred) *Indexing {
|
||||
n := &Indexing{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Array) addToCompounds(ch *Compound) {
|
||||
n.Compounds = append(n.Compounds, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseArray(ps *parser) *Array {
|
||||
n := &Array{node: node{begin: ps.pos}}
|
||||
n.parse(ps)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Primary) setList(ch *Array) {
|
||||
n.List = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Primary) setChunk(ch *Chunk) {
|
||||
n.Chunk = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Primary) addToMapPairs(ch *MapPair) {
|
||||
n.MapPairs = append(n.MapPairs, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *Primary) addToBraced(ch *Compound) {
|
||||
n.Braced = append(n.Braced, ch)
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parsePrimary(ps *parser, cut runePred) *Primary {
|
||||
n := &Primary{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *MapPair) setKey(ch *Compound) {
|
||||
n.Key = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func (n *MapPair) setValue(ch *Compound) {
|
||||
n.Value = ch
|
||||
addChild(n, ch)
|
||||
}
|
||||
|
||||
func parseMapPair(ps *parser, cut runePred) *MapPair {
|
||||
n := &MapPair{node: node{begin: ps.pos}}
|
||||
n.parse(ps, cut)
|
||||
n.end = ps.pos
|
||||
n.sourceText = ps.src[n.begin:n.end]
|
||||
|
|
106
parse/parse.go
106
parse/parse.go
|
@ -6,27 +6,26 @@ package parse
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"unicode"
|
||||
|
||||
"github.com/elves/elvish/errutil"
|
||||
)
|
||||
|
||||
func Parse(name, src string) (*Chunk, error) {
|
||||
func Parse(src string) (*Chunk, error) {
|
||||
ps := &parser{src, 0, 0, nil}
|
||||
bn := parseChunk(ps, nil)
|
||||
if ps.error != nil {
|
||||
return bn, errutil.NewContextualError(
|
||||
name, "syntax error", src, ps.pos, ps.error.Error())
|
||||
}
|
||||
if ps.pos != len(src) {
|
||||
return bn, errutil.NewContextualError(
|
||||
name, "syntax error", src, ps.pos, "unexpected rune")
|
||||
ps.error(unexpectedRune)
|
||||
}
|
||||
return bn, nil
|
||||
var err error
|
||||
if ps.errors != nil {
|
||||
err = ps.errors
|
||||
}
|
||||
return bn, err
|
||||
}
|
||||
|
||||
// Errors.
|
||||
var (
|
||||
unexpectedRune = errors.New("unexpected rune")
|
||||
shouldBeForm = newError("", "form")
|
||||
duplicateExitusRedir = newError("duplicate exitus redir")
|
||||
shouldBeEqual = newError("", "=")
|
||||
|
@ -120,7 +119,7 @@ func (pn *Pipeline) parse(ps *parser, cut runePred) {
|
|||
pn.addToForms(parseForm(ps, cut))
|
||||
for !cut.matches('|') && parseSep(pn, ps, '|') {
|
||||
if !startsForm(ps.peek(), cut) {
|
||||
ps.error = shouldBeForm
|
||||
ps.error(shouldBeForm)
|
||||
return
|
||||
}
|
||||
pn.addToForms(parseForm(ps, cut))
|
||||
|
@ -149,7 +148,7 @@ func (fn *Form) parse(ps *parser, cut runePred) {
|
|||
}
|
||||
if !startsCompound(ps.peek(), cut) {
|
||||
if len(fn.Assignments) == 0 {
|
||||
ps.error = shouldBeCompound
|
||||
ps.error(shouldBeCompound)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -166,10 +165,12 @@ loop:
|
|||
case startsCompound(r, cut):
|
||||
if !cut.matches('>') && ps.hasPrefix("?>") {
|
||||
if fn.ExitusRedir != nil {
|
||||
ps.error = duplicateExitusRedir
|
||||
return
|
||||
ps.error(duplicateExitusRedir)
|
||||
// Parse the duplicate redir anyway.
|
||||
addChild(fn, parseExitusRedir(ps, cut))
|
||||
} else {
|
||||
fn.setExitusRedir(parseExitusRedir(ps, cut))
|
||||
}
|
||||
fn.setExitusRedir(parseExitusRedir(ps, cut))
|
||||
continue
|
||||
}
|
||||
cn := parseCompound(ps, cut)
|
||||
|
@ -193,10 +194,10 @@ loop:
|
|||
// parser and returns false.
|
||||
func (fn *Form) tryAssignment(ps *parser, cut runePred) bool {
|
||||
begin := ps.pos
|
||||
an := parseAssignment(ps, cut)
|
||||
if ps.error != nil {
|
||||
var ok bool
|
||||
an := parseAssignment(ps, cut, &ok)
|
||||
if !ok {
|
||||
ps.pos = begin
|
||||
ps.error = nil
|
||||
return false
|
||||
}
|
||||
fn.addToAssignments(an)
|
||||
|
@ -214,16 +215,17 @@ type Assignment struct {
|
|||
Src *Compound
|
||||
}
|
||||
|
||||
func (an *Assignment) parse(ps *parser, cut runePred) {
|
||||
func (an *Assignment) parse(ps *parser, cut runePred, pok *bool) {
|
||||
cutWithEqual := runePred(func(r rune) bool {
|
||||
return cut.matches(r) || r == '='
|
||||
})
|
||||
an.setDst(parseIndexing(ps, cutWithEqual))
|
||||
if !parseSep(an, ps, '=') {
|
||||
ps.error = shouldBeEqual
|
||||
*pok = false
|
||||
return
|
||||
}
|
||||
an.setSrc(parseCompound(ps, cut))
|
||||
*pok = true
|
||||
}
|
||||
|
||||
// ExitusRedir = '?' '>' { Space } Compound
|
||||
|
@ -272,9 +274,7 @@ func (rn *Redir) parse(ps *parser, cut runePred, dest *Compound) {
|
|||
case "<>":
|
||||
rn.Mode = ReadWrite
|
||||
default:
|
||||
ps.pos = begin
|
||||
ps.error = badRedirSign
|
||||
return
|
||||
ps.error(badRedirSign)
|
||||
}
|
||||
addSep(rn, ps)
|
||||
parseSpaces(rn, ps)
|
||||
|
@ -283,9 +283,9 @@ func (rn *Redir) parse(ps *parser, cut runePred, dest *Compound) {
|
|||
}
|
||||
if !startsCompound(ps.peek(), cut) {
|
||||
if rn.SourceIsFd {
|
||||
ps.error = shouldBeFd
|
||||
ps.error(shouldBeFd)
|
||||
} else {
|
||||
ps.error = shouldBeFilename
|
||||
ps.error(shouldBeFilename)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -333,11 +333,11 @@ func (in *Indexing) parse(ps *parser, cut runePred) {
|
|||
in.setHead(parsePrimary(ps, cut))
|
||||
for parseSep(in, ps, '[') {
|
||||
if !startsArray(ps.peek()) {
|
||||
ps.error = shouldBeArray
|
||||
ps.error(shouldBeArray)
|
||||
}
|
||||
in.addToIndicies(parseArray(ps))
|
||||
if !parseSep(in, ps, ']') {
|
||||
ps.error = shouldBeRBracket
|
||||
ps.error(shouldBeRBracket)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ const (
|
|||
func (pn *Primary) parse(ps *parser, cut runePred) {
|
||||
r := ps.peek()
|
||||
if !startsPrimary(r, cut) {
|
||||
ps.error = ShouldBePrimary
|
||||
ps.error(ShouldBePrimary)
|
||||
return
|
||||
}
|
||||
switch r {
|
||||
|
@ -439,7 +439,7 @@ func (pn *Primary) singleQuoted(ps *parser) {
|
|||
for {
|
||||
switch r := ps.next(); r {
|
||||
case EOF:
|
||||
ps.error = StringUnterminated
|
||||
ps.error(StringUnterminated)
|
||||
return
|
||||
case '\'':
|
||||
if ps.peek() == '\'' {
|
||||
|
@ -464,7 +464,7 @@ func (pn *Primary) doubleQuoted(ps *parser) {
|
|||
for {
|
||||
switch r := ps.next(); r {
|
||||
case EOF:
|
||||
ps.error = StringUnterminated
|
||||
ps.error(StringUnterminated)
|
||||
return
|
||||
case '"':
|
||||
return
|
||||
|
@ -475,8 +475,8 @@ func (pn *Primary) doubleQuoted(ps *parser) {
|
|||
r := ps.next()
|
||||
if r < 0x40 || r >= 0x60 {
|
||||
ps.backup()
|
||||
ps.error = InvalidEscapeControl
|
||||
return
|
||||
ps.error(InvalidEscapeControl)
|
||||
ps.next()
|
||||
}
|
||||
buf.WriteByte(byte(r - 0x40))
|
||||
case 'x', 'u', 'U':
|
||||
|
@ -494,8 +494,8 @@ func (pn *Primary) doubleQuoted(ps *parser) {
|
|||
d, ok := hexToDigit(ps.next())
|
||||
if !ok {
|
||||
ps.backup()
|
||||
ps.error = InvalidEscapeHex
|
||||
return
|
||||
ps.error(InvalidEscapeHex)
|
||||
break
|
||||
}
|
||||
rr = rr*16 + d
|
||||
}
|
||||
|
@ -507,8 +507,8 @@ func (pn *Primary) doubleQuoted(ps *parser) {
|
|||
r := ps.next()
|
||||
if r < '0' || r > '7' {
|
||||
ps.backup()
|
||||
ps.error = InvalidEscapeOct
|
||||
return
|
||||
ps.error(InvalidEscapeOct)
|
||||
break
|
||||
}
|
||||
rr = rr*8 + (r - '0')
|
||||
}
|
||||
|
@ -518,7 +518,8 @@ func (pn *Primary) doubleQuoted(ps *parser) {
|
|||
buf.WriteRune(rr)
|
||||
} else {
|
||||
ps.backup()
|
||||
ps.error = InvalidEscape
|
||||
ps.error(InvalidEscape)
|
||||
ps.next()
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
@ -556,8 +557,8 @@ func (pn *Primary) variable(ps *parser, cut runePred) {
|
|||
// The character of the variable name can be anything.
|
||||
if r := ps.next(); cut.matches(r) {
|
||||
ps.backup()
|
||||
ps.error = shouldBeVariableName
|
||||
return
|
||||
ps.error(shouldBeVariableName)
|
||||
ps.next()
|
||||
}
|
||||
for allowedInVariableName(ps.peek()) && !cut.matches(ps.peek()) {
|
||||
ps.next()
|
||||
|
@ -595,12 +596,12 @@ func (pn *Primary) exitusCapture(ps *parser) {
|
|||
|
||||
pn.Type = ErrorCapture
|
||||
if !startsChunk(ps.peek(), nil) && ps.peek() != ')' {
|
||||
ps.error = shouldBeChunk
|
||||
ps.error(shouldBeChunk)
|
||||
return
|
||||
}
|
||||
pn.setChunk(parseChunk(ps, nil))
|
||||
if !parseSep(pn, ps, ')') {
|
||||
ps.error = shouldBeRParen
|
||||
ps.error(shouldBeRParen)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -621,20 +622,21 @@ func (pn *Primary) outputCapture(ps *parser) {
|
|||
cut = isBackquote
|
||||
default:
|
||||
ps.backup()
|
||||
ps.error = shouldBeBackquoteOrLParen
|
||||
ps.error(shouldBeBackquoteOrLParen)
|
||||
ps.next()
|
||||
return
|
||||
}
|
||||
addSep(pn, ps)
|
||||
|
||||
if !startsChunk(ps.peek(), cut) && ps.peek() != closer {
|
||||
ps.error = shouldBeChunk
|
||||
ps.error(shouldBeChunk)
|
||||
return
|
||||
}
|
||||
|
||||
pn.setChunk(parseChunk(ps, cut))
|
||||
|
||||
if !parseSep(pn, ps, closer) {
|
||||
ps.error = shouldBeCloser
|
||||
ps.error(shouldBeCloser)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,7 +657,7 @@ func (pn *Primary) lbracket(ps *parser) {
|
|||
case r == ']' || startsArray(r):
|
||||
pn.setList(parseArray(ps))
|
||||
if !parseSep(pn, ps, ']') {
|
||||
ps.error = shouldBeRBracket
|
||||
ps.error(shouldBeRBracket)
|
||||
return
|
||||
}
|
||||
if parseSep(pn, ps, '{') {
|
||||
|
@ -684,10 +686,10 @@ func (pn *Primary) lbracket(ps *parser) {
|
|||
}
|
||||
}
|
||||
if !parseSep(pn, ps, ']') {
|
||||
ps.error = shouldBeRBracket
|
||||
ps.error(shouldBeRBracket)
|
||||
}
|
||||
default:
|
||||
ps.error = shouldBeAmpersandOrArray
|
||||
ps.error(shouldBeAmpersandOrArray)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,12 +697,12 @@ func (pn *Primary) lbracket(ps *parser) {
|
|||
func (pn *Primary) lambda(ps *parser) {
|
||||
pn.Type = Lambda
|
||||
if !startsChunk(ps.peek(), nil) && ps.peek() != '}' {
|
||||
ps.error = shouldBeChunk
|
||||
ps.error(shouldBeChunk)
|
||||
return
|
||||
}
|
||||
pn.setChunk(parseChunk(ps, nil))
|
||||
if !parseSep(pn, ps, '}') {
|
||||
ps.error = shouldBeRBrace
|
||||
ps.error(shouldBeRBrace)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -732,7 +734,7 @@ func (pn *Primary) lbrace(ps *parser) {
|
|||
pn.addToBraced(parseCompound(ps, isBracedSep))
|
||||
}
|
||||
if !parseSep(pn, ps, '}') {
|
||||
ps.error = shouldBeBraceSepOrRBracket
|
||||
ps.error(shouldBeBraceSepOrRBracket)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -775,14 +777,14 @@ func (mpn *MapPair) parse(ps *parser, cut runePred) {
|
|||
parseSep(mpn, ps, '&')
|
||||
parseSpaces(mpn, ps)
|
||||
if !startsCompound(ps.peek(), cut) {
|
||||
ps.error = shouldBeCompound
|
||||
ps.error(shouldBeCompound)
|
||||
return
|
||||
}
|
||||
mpn.setKey(parseCompound(ps, cut))
|
||||
|
||||
parseSpaces(mpn, ps)
|
||||
if !startsCompound(ps.peek(), cut) {
|
||||
ps.error = shouldBeCompound
|
||||
ps.error(shouldBeCompound)
|
||||
return
|
||||
}
|
||||
mpn.setValue(parseCompound(ps, cut))
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"errors"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/elves/elvish/errutil"
|
||||
)
|
||||
|
||||
// parser maintains some mutable states of parsing.
|
||||
|
@ -14,7 +16,7 @@ type parser struct {
|
|||
src string
|
||||
pos int
|
||||
overEOF int
|
||||
error error
|
||||
errors *errutil.Errors
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -43,9 +45,6 @@ func newError(text string, shouldbe ...string) error {
|
|||
}
|
||||
|
||||
func (ps *parser) peek() rune {
|
||||
if ps.error != nil {
|
||||
return ParseError
|
||||
}
|
||||
if ps.pos == len(ps.src) {
|
||||
return EOF
|
||||
}
|
||||
|
@ -58,9 +57,6 @@ func (ps *parser) hasPrefix(prefix string) bool {
|
|||
}
|
||||
|
||||
func (ps *parser) next() rune {
|
||||
if ps.error != nil {
|
||||
return ParseError
|
||||
}
|
||||
if ps.pos == len(ps.src) {
|
||||
ps.overEOF += 1
|
||||
return EOF
|
||||
|
@ -78,3 +74,10 @@ func (ps *parser) backup() {
|
|||
_, s := utf8.DecodeLastRuneInString(ps.src[:ps.pos])
|
||||
ps.pos -= s
|
||||
}
|
||||
|
||||
func (ps *parser) error(e error) {
|
||||
if ps.errors == nil {
|
||||
ps.errors = &errutil.Errors{}
|
||||
}
|
||||
ps.errors.Append(&errutil.PosError{ps.pos, ps.pos, e})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user