parse: Expose more of the parser.

This commit is contained in:
Qi Xiao 2017-05-30 00:42:38 +01:00
parent 65579834de
commit 7a4d7b1e54
4 changed files with 62 additions and 54 deletions

View File

@ -17,7 +17,7 @@ func (n *Chunk) addToPipelines(ch *Pipeline) {
addChild(n, ch)
}
func parseChunk(ps *parser) *Chunk {
func ParseChunk(ps *parser) *Chunk {
n := &Chunk{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos
@ -42,7 +42,7 @@ func (n *Pipeline) addToForms(ch *Form) {
addChild(n, ch)
}
func parsePipeline(ps *parser) *Pipeline {
func ParsePipeline(ps *parser) *Pipeline {
n := &Pipeline{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos
@ -97,7 +97,7 @@ func (n *Form) setExitusRedir(ch *ExitusRedir) {
addChild(n, ch)
}
func parseForm(ps *parser) *Form {
func ParseForm(ps *parser) *Form {
n := &Form{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos
@ -127,7 +127,7 @@ func (n *Assignment) setRight(ch *Compound) {
addChild(n, ch)
}
func parseAssignment(ps *parser) *Assignment {
func ParseAssignment(ps *parser) *Assignment {
n := &Assignment{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos
@ -152,7 +152,7 @@ func (n *ExitusRedir) setDest(ch *Compound) {
addChild(n, ch)
}
func parseExitusRedir(ps *parser) *ExitusRedir {
func ParseExitusRedir(ps *parser) *ExitusRedir {
n := &ExitusRedir{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos
@ -182,7 +182,7 @@ func (n *Redir) setRight(ch *Compound) {
addChild(n, ch)
}
func parseRedir(ps *parser, dest *Compound) *Redir {
func ParseRedir(ps *parser, dest *Compound) *Redir {
n := &Redir{node: node{begin: ps.pos}}
n.parse(ps, dest)
n.end = ps.pos
@ -207,7 +207,7 @@ func (n *Compound) addToIndexings(ch *Indexing) {
addChild(n, ch)
}
func parseCompound(ps *parser, head bool) *Compound {
func ParseCompound(ps *parser, head bool) *Compound {
n := &Compound{node: node{begin: ps.pos}}
n.parse(ps, head)
n.end = ps.pos
@ -237,7 +237,7 @@ func (n *Indexing) addToIndicies(ch *Array) {
addChild(n, ch)
}
func parseIndexing(ps *parser, head bool) *Indexing {
func ParseIndexing(ps *parser, head bool) *Indexing {
n := &Indexing{node: node{begin: ps.pos}}
n.parse(ps, head)
n.end = ps.pos
@ -262,7 +262,7 @@ func (n *Array) addToCompounds(ch *Compound) {
addChild(n, ch)
}
func parseArray(ps *parser, allowSemicolon bool) *Array {
func ParseArray(ps *parser, allowSemicolon bool) *Array {
n := &Array{node: node{begin: ps.pos}}
n.parse(ps, allowSemicolon)
n.end = ps.pos
@ -302,7 +302,7 @@ func (n *Primary) addToBraced(ch *Compound) {
addChild(n, ch)
}
func parsePrimary(ps *parser, head bool) *Primary {
func ParsePrimary(ps *parser, head bool) *Primary {
n := &Primary{node: node{begin: ps.pos}}
n.parse(ps, head)
n.end = ps.pos
@ -332,7 +332,7 @@ func (n *MapPair) setValue(ch *Compound) {
addChild(n, ch)
}
func parseMapPair(ps *parser) *MapPair {
func ParseMapPair(ps *parser) *MapPair {
n := &MapPair{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos

View File

@ -52,7 +52,7 @@ func (n *X) addToG(ch *Z) {
addChild(n, ch)
}
func parseX(ps *parser) *X {
func ParseX(ps *parser) *X {
n := &X{node: node{begin: ps.pos}}
n.parse(ps)
n.end = ps.pos
@ -103,7 +103,7 @@ func (n *{parent}) addTo{field}(ch *{child}) {{
def put_parse(out, typename, extraargs):
extranames = ', '.join(a.split(' ')[0] for a in extraargs.split(', ')) if extraargs else ''
print >>out, '''
func parse{typename}(ps *parser{extraargs}) *{typename} {{
func Parse{typename}(ps *parser{extraargs}) *{typename} {{
n := &{typename}{{node: node{{begin: ps.pos}}}}
n.parse(ps{extranames})
n.end = ps.pos

View File

@ -11,19 +11,28 @@ import (
"unicode"
)
// Parse parses elvish source. If the error is not nil, it always has type
// Parse parses Elvish source. If the error is not nil, it always has type
// ParseError.
func Parse(srcname, src string) (*Chunk, error) {
ps := &parser{srcname, src, 0, 0, []map[rune]int{{}}, 0, Error{}}
bn := parseChunk(ps)
ps := NewParser(srcname, src)
n := ParseChunk(ps)
return n, GetError(ps, src, n)
}
// NewParser creates a new parser from a piece of source text and its name.
func NewParser(srcname, src string) *parser {
return &parser{srcname, src, 0, 0, []map[rune]int{{}}, Error{}}
}
// GetError gets the parsing error after calling one of the parse* functions.
func GetError(ps *parser, src string, n Node) error {
if ps.pos != len(src) {
ps.error(errUnexpectedRune)
}
var err error
if len(ps.errors.Entries) > 0 {
err = &ps.errors
return &ps.errors
}
return bn, err
return nil
}
// Errors.
@ -73,7 +82,7 @@ type Chunk struct {
func (bn *Chunk) parse(ps *parser) {
bn.parseSeps(ps)
for startsPipeline(ps.peek()) {
bn.addToPipelines(parsePipeline(ps))
bn.addToPipelines(ParsePipeline(ps))
if bn.parseSeps(ps) == 0 {
break
}
@ -123,14 +132,14 @@ type Pipeline struct {
}
func (pn *Pipeline) parse(ps *parser) {
pn.addToForms(parseForm(ps))
pn.addToForms(ParseForm(ps))
for parseSep(pn, ps, '|') {
parseSpacesAndNewlines(pn, ps)
if !startsForm(ps.peek()) {
ps.error(errShouldBeForm)
return
}
pn.addToForms(parseForm(ps))
pn.addToForms(ParseForm(ps))
}
parseSpaces(pn, ps)
if ps.peek() == '&' {
@ -174,7 +183,7 @@ func (fn *Form) parse(ps *parser) {
// Bad form.
ps.error(fmt.Errorf("bad rune at form head: %q", ps.peek()))
}
fn.setHead(parseCompound(ps, true))
fn.setHead(ParseCompound(ps, true))
parseSpaces(fn, ps)
for {
@ -188,22 +197,22 @@ func (fn *Form) parse(ps *parser) {
// background indicator
return
}
fn.addToOpts(parseMapPair(ps))
fn.addToOpts(ParseMapPair(ps))
case startsCompound(r, false):
if ps.hasPrefix("?>") {
if fn.ExitusRedir != nil {
ps.error(errDuplicateExitusRedir)
// Parse the duplicate redir anyway.
addChild(fn, parseExitusRedir(ps))
addChild(fn, ParseExitusRedir(ps))
} else {
fn.setExitusRedir(parseExitusRedir(ps))
fn.setExitusRedir(ParseExitusRedir(ps))
}
continue
}
cn := parseCompound(ps, false)
cn := ParseCompound(ps, false)
if isRedirSign(ps.peek()) {
// Redir
fn.addToRedirs(parseRedir(ps, cn))
fn.addToRedirs(ParseRedir(ps, cn))
} else if cn.sourceText == "=" {
// Spacey assignment.
// Turn the equal sign into a Sep.
@ -226,7 +235,7 @@ func (fn *Form) parse(ps *parser) {
fn.addToArgs(cn)
}
case isRedirSign(r):
fn.addToRedirs(parseRedir(ps, nil))
fn.addToRedirs(ParseRedir(ps, nil))
default:
return
}
@ -244,7 +253,7 @@ func (fn *Form) tryAssignment(ps *parser) bool {
pos := ps.pos
errorEntries := ps.errors.Entries
an := parseAssignment(ps)
an := ParseAssignment(ps)
// If errors were added, revert
if len(ps.errors.Entries) > len(errorEntries) {
ps.errors.Entries = errorEntries
@ -268,7 +277,7 @@ type Assignment struct {
func (an *Assignment) parse(ps *parser) {
ps.cut('=')
an.setLeft(parseIndexing(ps, false))
an.setLeft(ParseIndexing(ps, false))
head := an.Left.Head
if !checkVariableInAssignment(head, ps) {
ps.errorp(head.Begin(), head.End(), errShouldBeVariableName)
@ -278,7 +287,7 @@ func (an *Assignment) parse(ps *parser) {
if !parseSep(an, ps, '=') {
ps.error(errShouldBeEqual)
}
an.setRight(parseCompound(ps, false))
an.setRight(ParseCompound(ps, false))
}
func checkVariableInAssignment(p *Primary, ps *parser) bool {
@ -312,7 +321,7 @@ func (ern *ExitusRedir) parse(ps *parser) {
ps.next()
addSep(ern, ps)
parseSpaces(ern, ps)
ern.setDest(parseCompound(ps, false))
ern.setDest(ParseCompound(ps, false))
}
// Redir = { Compound } { '<'|'>'|'<>'|'>>' } { Space } ( '&'? Compound )
@ -353,7 +362,7 @@ func (rn *Redir) parse(ps *parser, dest *Compound) {
if parseSep(rn, ps, '&') {
rn.RightIsFd = true
}
rn.setRight(parseCompound(ps, false))
rn.setRight(ParseCompound(ps, false))
if len(rn.Right.Indexings) == 0 {
if rn.RightIsFd {
ps.error(errShouldBeFD)
@ -389,7 +398,7 @@ type Compound struct {
func (cn *Compound) parse(ps *parser, head bool) {
cn.tilde(ps)
for startsIndexing(ps.peek(), head) {
cn.addToIndexings(parseIndexing(ps, head))
cn.addToIndexings(ParseIndexing(ps, head))
}
}
@ -419,14 +428,14 @@ type Indexing struct {
}
func (in *Indexing) parse(ps *parser, head bool) {
in.setHead(parsePrimary(ps, head))
in.setHead(ParsePrimary(ps, head))
for parseSep(in, ps, '[') {
if !startsArray(ps.peek()) {
ps.error(errShouldBeArray)
}
ps.pushCutset()
in.addToIndicies(parseArray(ps, false))
in.addToIndicies(ParseArray(ps, false))
ps.popCutset()
if !parseSep(in, ps, ']') {
@ -463,7 +472,7 @@ func (sn *Array) parse(ps *parser, allowSemicolon bool) {
parseSep()
for startsCompound(ps.peek(), false) {
sn.addToCompounds(parseCompound(ps, false))
sn.addToCompounds(ParseCompound(ps, false))
parseSep()
}
}
@ -725,7 +734,7 @@ func (pn *Primary) exitusCapture(ps *parser) {
pn.Type = ExceptionCapture
ps.pushCutset()
pn.setChunk(parseChunk(ps))
pn.setChunk(ParseChunk(ps))
ps.popCutset()
if !parseSep(pn, ps, ')') {
@ -759,7 +768,7 @@ func (pn *Primary) outputCapture(ps *parser) {
} else {
ps.pushCutset()
}
pn.setChunk(parseChunk(ps))
pn.setChunk(ParseChunk(ps))
ps.popCutset()
if !parseSep(pn, ps, closer) {
@ -795,7 +804,7 @@ func (pn *Primary) lbracket(ps *parser) {
// { MapPair { Space } } ']': Wind back
ps.pos = amp
for ps.peek() == '&' {
pn.addToMapPairs(parseMapPair(ps))
pn.addToMapPairs(ParseMapPair(ps))
parseSpacesAndNewlines(pn, ps)
}
}
@ -804,7 +813,7 @@ func (pn *Primary) lbracket(ps *parser) {
ps.error(errShouldBeRBracket)
}
default:
pn.setList(parseArray(ps, true))
pn.setList(ParseArray(ps, true))
ps.popCutset()
if !parseSep(pn, ps, ']') {
@ -825,7 +834,7 @@ func (pn *Primary) lbracket(ps *parser) {
func (pn *Primary) lambda(ps *parser) {
pn.Type = Lambda
ps.pushCutset()
pn.setChunk(parseChunk(ps))
pn.setChunk(ParseChunk(ps))
ps.popCutset()
if !parseSep(pn, ps, '}') {
ps.error(errShouldBeRBrace)
@ -850,7 +859,7 @@ func (pn *Primary) lbrace(ps *parser) {
// XXX: The compound can be empty, which allows us to parse {,foo}.
// Allowing compounds to be empty can be fragile in other cases.
ps.cut(',')
pn.addToBraced(parseCompound(ps, false))
pn.addToBraced(ParseCompound(ps, false))
ps.uncut(',')
for isBracedSep(ps.peek()) {
@ -860,7 +869,7 @@ func (pn *Primary) lbrace(ps *parser) {
parseSpacesAndNewlines(pn, ps)
ps.cut(',')
pn.addToBraced(parseCompound(ps, false))
pn.addToBraced(ParseCompound(ps, false))
ps.uncut(',')
}
if !parseSep(pn, ps, '}') {
@ -910,7 +919,7 @@ func (mpn *MapPair) parse(ps *parser) {
// Parse key part, cutting on '='.
ps.cut('=')
mpn.setKey(parseCompound(ps, false))
mpn.setKey(ParseCompound(ps, false))
if len(mpn.Key.Indexings) == 0 {
ps.error(errShouldBeCompound)
}
@ -919,7 +928,7 @@ func (mpn *MapPair) parse(ps *parser) {
if parseSep(mpn, ps, '=') {
parseSpacesAndNewlines(mpn, ps)
// Parse value part.
mpn.setValue(parseCompound(ps, false))
mpn.setValue(ParseCompound(ps, false))
// The value part can be empty.
}
}

View File

@ -13,13 +13,12 @@ import (
//
// NOTE: The str member is assumed to be valid UF-8.
type parser struct {
srcName string
src string
pos int
overEOF int
cutsets []map[rune]int
controls int
errors Error
srcName string
src string
pos int
overEOF int
cutsets []map[rune]int
errors Error
}
const eof rune = -1