parse: Expose Parser.

This commit is contained in:
Qi Xiao 2017-05-31 22:34:10 +01:00
parent 121a7b6a36
commit 35a34f36f1
5 changed files with 69 additions and 64 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

@ -16,7 +16,7 @@ For every node type T, it generates the following:
method that sets this field and adds it to the children list.
* If the type has a parse method that takes a *paser, it genertes a parseT
func that takes a *parser and returns *T. The func creates a new instance of
func that takes a *Parser and returns *T. The func creates a new instance of
*T, sets its begin field, calls its parse method, and set its end and
sourceText fields.
@ -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
@ -140,7 +140,7 @@ def main():
put_get(out, in_type)
continue
m = re.match(
r'^func \(.* \*(.*)\) parse\(ps \*parser(.*?)\) {$', line)
r'^func \(.* \*(.*)\) parse\(ps \*Parser(.*?)\) {$', line)
if m:
typename, extraargs = m.groups()
put_parse(out, typename, extraargs)

View File

@ -64,7 +64,7 @@ type Chunk struct {
Pipelines []*Pipeline
}
func (bn *Chunk) parse(ps *parser) {
func (bn *Chunk) parse(ps *Parser) {
bn.parseSeps(ps)
for startsPipeline(ps.peek()) {
bn.addToPipelines(ParsePipeline(ps))
@ -80,7 +80,7 @@ func isPipelineSep(r rune) bool {
// parseSeps parses pipeline separators along with whitespaces. It returns the
// number of pipeline separators parsed.
func (bn *Chunk) parseSeps(ps *parser) int {
func (bn *Chunk) parseSeps(ps *Parser) int {
nseps := 0
for {
r := ps.peek()
@ -116,7 +116,7 @@ type Pipeline struct {
Background bool
}
func (pn *Pipeline) parse(ps *parser) {
func (pn *Pipeline) parse(ps *Parser) {
pn.addToForms(ParseForm(ps))
for parseSep(pn, ps, '|') {
parseSpacesAndNewlines(pn, ps)
@ -153,7 +153,7 @@ type Form struct {
ExitusRedir *ExitusRedir
}
func (fn *Form) parse(ps *parser) {
func (fn *Form) parse(ps *Parser) {
parseSpaces(fn, ps)
for fn.tryAssignment(ps) {
parseSpaces(fn, ps)
@ -231,7 +231,7 @@ func (fn *Form) parse(ps *parser) {
// tryAssignment tries to parse an assignment. If succeeded, it adds the parsed
// assignment to fn.Assignments and returns true. Otherwise it rewinds the
// parser and returns false.
func (fn *Form) tryAssignment(ps *parser) bool {
func (fn *Form) tryAssignment(ps *Parser) bool {
if !startsIndexing(ps.peek(), false) || ps.peek() == '=' {
return false
}
@ -260,7 +260,7 @@ type Assignment struct {
Right *Compound
}
func (an *Assignment) parse(ps *parser) {
func (an *Assignment) parse(ps *Parser) {
ps.cut('=')
an.setLeft(ParseIndexing(ps, false))
head := an.Left.Head
@ -275,7 +275,7 @@ func (an *Assignment) parse(ps *parser) {
an.setRight(ParseCompound(ps, false))
}
func checkVariableInAssignment(p *Primary, ps *parser) bool {
func checkVariableInAssignment(p *Primary, ps *Parser) bool {
if p.Type == Braced {
// XXX don't check further inside braced expression
return true
@ -301,7 +301,7 @@ type ExitusRedir struct {
Dest *Compound
}
func (ern *ExitusRedir) parse(ps *parser) {
func (ern *ExitusRedir) parse(ps *Parser) {
ps.next()
ps.next()
addSep(ern, ps)
@ -318,7 +318,7 @@ type Redir struct {
Right *Compound
}
func (rn *Redir) parse(ps *parser, dest *Compound) {
func (rn *Redir) parse(ps *Parser, dest *Compound) {
// The parsing of the Left part is done in Form.parse.
if dest != nil {
rn.setLeft(dest)
@ -380,7 +380,7 @@ type Compound struct {
Indexings []*Indexing
}
func (cn *Compound) parse(ps *parser, head bool) {
func (cn *Compound) parse(ps *Parser, head bool) {
cn.tilde(ps)
for startsIndexing(ps.peek(), head) {
cn.addToIndexings(ParseIndexing(ps, head))
@ -390,7 +390,7 @@ func (cn *Compound) parse(ps *parser, head bool) {
// tilde parses a tilde if there is one. It is implemented here instead of
// within Primary since a tilde can only appear as the first part of a
// Compound. Elsewhere tildes are barewords.
func (cn *Compound) tilde(ps *parser) {
func (cn *Compound) tilde(ps *Parser) {
if ps.peek() == '~' {
ps.next()
base := node{nil, ps.pos - 1, ps.pos, "~", nil}
@ -412,7 +412,7 @@ type Indexing struct {
Indicies []*Array
}
func (in *Indexing) parse(ps *parser, head bool) {
func (in *Indexing) parse(ps *Parser, head bool) {
in.setHead(ParsePrimary(ps, head))
for parseSep(in, ps, '[') {
if !startsArray(ps.peek()) {
@ -444,7 +444,7 @@ type Array struct {
Semicolons []int
}
func (sn *Array) parse(ps *parser, allowSemicolon bool) {
func (sn *Array) parse(ps *Parser, allowSemicolon bool) {
parseSep := func() {
parseSpacesAndNewlines(sn, ps)
if allowSemicolon {
@ -504,7 +504,7 @@ const (
Braced
)
func (pn *Primary) parse(ps *parser, head bool) {
func (pn *Primary) parse(ps *Parser, head bool) {
r := ps.peek()
if !startsPrimary(r, head) {
ps.error(errShouldBePrimary)
@ -545,7 +545,7 @@ func (pn *Primary) parse(ps *parser, head bool) {
}
}
func (pn *Primary) singleQuoted(ps *parser) {
func (pn *Primary) singleQuoted(ps *Parser) {
pn.Type = SingleQuoted
ps.next()
var buf bytes.Buffer
@ -570,7 +570,7 @@ func (pn *Primary) singleQuoted(ps *parser) {
}
}
func (pn *Primary) doubleQuoted(ps *parser) {
func (pn *Primary) doubleQuoted(ps *Parser) {
pn.Type = DoubleQuoted
ps.next()
var buf bytes.Buffer
@ -672,7 +672,7 @@ func hexToDigit(r rune) (rune, bool) {
}
}
func (pn *Primary) variable(ps *parser) {
func (pn *Primary) variable(ps *Parser) {
pn.Type = Variable
defer func() { pn.Value = ps.src[pn.begin+1 : ps.pos] }()
ps.next()
@ -699,7 +699,7 @@ func allowedInVariableName(r rune) bool {
r == '-' || r == '_' || r == ':' || r == '&'
}
func (pn *Primary) wildcard(ps *parser) {
func (pn *Primary) wildcard(ps *Parser) {
pn.Type = Wildcard
for isWildcard(ps.peek()) {
ps.next()
@ -711,7 +711,7 @@ func isWildcard(r rune) bool {
return r == '*' || r == '?'
}
func (pn *Primary) exitusCapture(ps *parser) {
func (pn *Primary) exitusCapture(ps *Parser) {
ps.next()
ps.next()
addSep(pn, ps)
@ -727,7 +727,7 @@ func (pn *Primary) exitusCapture(ps *parser) {
}
}
func (pn *Primary) outputCapture(ps *parser) {
func (pn *Primary) outputCapture(ps *Parser) {
pn.Type = OutputCapture
var closer rune
@ -766,7 +766,7 @@ func (pn *Primary) outputCapture(ps *parser) {
// Map = '[' { Space } '&' { Space } ']'
// = '[' { Space } { MapPair { Space } } ']'
func (pn *Primary) lbracket(ps *parser) {
func (pn *Primary) lbracket(ps *Parser) {
parseSep(pn, ps, '[')
parseSpacesAndNewlines(pn, ps)
@ -816,7 +816,7 @@ func (pn *Primary) lbracket(ps *parser) {
}
// lambda parses a lambda expression. The opening brace has been seen.
func (pn *Primary) lambda(ps *parser) {
func (pn *Primary) lambda(ps *Parser) {
pn.Type = Lambda
ps.pushCutset()
pn.setChunk(ParseChunk(ps))
@ -828,7 +828,7 @@ func (pn *Primary) lambda(ps *parser) {
// Braced = '{' Compound { BracedSep Compounds } '}'
// BracedSep = { Space | '\n' } [ ',' ] { Space | '\n' }
func (pn *Primary) lbrace(ps *parser) {
func (pn *Primary) lbrace(ps *Parser) {
parseSep(pn, ps, '{')
if r := ps.peek(); r == ';' || r == '\n' || IsSpace(r) {
@ -866,7 +866,7 @@ func isBracedSep(r rune) bool {
return r == ',' || IsSpaceOrNewline(r)
}
func (pn *Primary) bareword(ps *parser, head bool) {
func (pn *Primary) bareword(ps *Parser, head bool) {
pn.Type = Bareword
defer func() { pn.Value = ps.src[pn.begin:ps.pos] }()
for allowedInBareword(ps.peek(), head) {
@ -899,7 +899,7 @@ type MapPair struct {
Key, Value *Compound
}
func (mpn *MapPair) parse(ps *parser) {
func (mpn *MapPair) parse(ps *Parser) {
parseSep(mpn, ps, '&')
// Parse key part, cutting on '='.
@ -930,7 +930,7 @@ func NewSep(src string, begin, end int) *Sep {
return &Sep{node{nil, begin, end, src[begin:end], nil}}
}
func addSep(n Node, ps *parser) {
func addSep(n Node, ps *Parser) {
var begin int
ch := n.Children()
if len(ch) > 0 {
@ -941,7 +941,7 @@ func addSep(n Node, ps *parser) {
addChild(n, NewSep(ps.src, begin, ps.pos))
}
func parseSep(n Node, ps *parser, sep rune) bool {
func parseSep(n Node, ps *Parser, sep rune) bool {
if ps.peek() == sep {
ps.next()
addSep(n, ps)
@ -950,7 +950,7 @@ func parseSep(n Node, ps *parser, sep rune) bool {
return false
}
func parseSpaces(n Node, ps *parser) {
func parseSpaces(n Node, ps *Parser) {
if !IsSpace(ps.peek()) {
return
}
@ -961,7 +961,7 @@ func parseSpaces(n Node, ps *parser) {
addSep(n, ps)
}
func parseSpacesAndNewlines(n Node, ps *parser) {
func parseSpacesAndNewlines(n Node, ps *Parser) {
// TODO parse comments here.
if !IsSpaceOrNewline(ps.peek()) {
return

View File

@ -9,10 +9,10 @@ import (
"github.com/elves/elvish/util"
)
// parser maintains some mutable states of parsing.
// Parser maintains some mutable states of parsing.
//
// NOTE: The str member is assumed to be valid UF-8.
type parser struct {
type Parser struct {
srcName string
src string
pos int
@ -22,12 +22,12 @@ type parser struct {
}
// 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{}}
func NewParser(srcname, src string) *Parser {
return &Parser{srcname, src, 0, 0, []map[rune]int{{}}, Error{}}
}
// Done tells the parser that parsing has completed.
func (ps *parser) Done() {
func (ps *Parser) Done() {
if ps.pos != len(ps.src) {
ps.error(errUnexpectedRune)
}
@ -35,16 +35,21 @@ func (ps *parser) Done() {
// Errors gets the parsing errors after calling one of the parse* functions. If
// the return value is not nil, it is always of type Error.
func (ps *parser) Errors() error {
func (ps *Parser) Errors() error {
if len(ps.errors.Entries) > 0 {
return &ps.errors
}
return nil
}
// Source returns the source code that is being parsed.
func (ps *Parser) Source() string {
return ps.src
}
const eof rune = -1
func (ps *parser) peek() rune {
func (ps *Parser) peek() rune {
if ps.pos == len(ps.src) {
return eof
}
@ -55,14 +60,14 @@ func (ps *parser) peek() rune {
return r
}
func (ps *parser) hasPrefix(prefix string) bool {
func (ps *Parser) hasPrefix(prefix string) bool {
return strings.HasPrefix(ps.src[ps.pos:], prefix)
}
// findWord looks ahead for [a-z]* that is also a valid compound. If the
// lookahead fails, it returns an empty string. It is useful for looking for
// command leaders.
func (ps *parser) findPossibleLeader() string {
func (ps *Parser) findPossibleLeader() string {
rest := ps.src[ps.pos:]
i := strings.IndexFunc(rest, func(r rune) bool {
return r < 'a' || r > 'z'
@ -78,7 +83,7 @@ func (ps *parser) findPossibleLeader() string {
return rest[:i]
}
func (ps *parser) next() rune {
func (ps *Parser) next() rune {
if ps.pos == len(ps.src) {
ps.overEOF++
return eof
@ -91,7 +96,7 @@ func (ps *parser) next() rune {
return r
}
func (ps *parser) backup() {
func (ps *Parser) backup() {
if ps.overEOF > 0 {
ps.overEOF--
return
@ -100,7 +105,7 @@ func (ps *parser) backup() {
ps.pos -= s
}
func (ps *parser) advance(c int) {
func (ps *Parser) advance(c int) {
ps.pos += c
if ps.pos > len(ps.src) {
ps.overEOF = ps.pos - len(ps.src)
@ -108,11 +113,11 @@ func (ps *parser) advance(c int) {
}
}
func (ps *parser) errorp(begin, end int, e error) {
func (ps *Parser) errorp(begin, end int, e error) {
ps.errors.Add(e.Error(), util.SourceContext{ps.srcName, ps.src, begin, end, nil})
}
func (ps *parser) error(e error) {
func (ps *Parser) error(e error) {
end := ps.pos
if end < len(ps.src) {
end++
@ -120,29 +125,29 @@ func (ps *parser) error(e error) {
ps.errorp(ps.pos, end, e)
}
func (ps *parser) pushCutset(rs ...rune) {
func (ps *Parser) pushCutset(rs ...rune) {
ps.cutsets = append(ps.cutsets, map[rune]int{})
ps.cut(rs...)
}
func (ps *parser) popCutset() {
func (ps *Parser) popCutset() {
n := len(ps.cutsets)
ps.cutsets[n-1] = nil
ps.cutsets = ps.cutsets[:n-1]
}
func (ps *parser) currentCutset() map[rune]int {
func (ps *Parser) currentCutset() map[rune]int {
return ps.cutsets[len(ps.cutsets)-1]
}
func (ps *parser) cut(rs ...rune) {
func (ps *Parser) cut(rs ...rune) {
cutset := ps.currentCutset()
for _, r := range rs {
cutset[r]++
}
}
func (ps *parser) uncut(rs ...rune) {
func (ps *Parser) uncut(rs ...rune) {
cutset := ps.currentCutset()
for _, r := range rs {
cutset[r]--

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=PrimaryType,RedirMode -output=string.go"; DO NOT EDIT
// Code generated by "stringer -type=PrimaryType,RedirMode -output=string.go"; DO NOT EDIT.
package parse