<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/main/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'main/parse.go')
-rw-r--r--main/parse.go93
1 files changed, 59 insertions, 34 deletions
diff --git a/main/parse.go b/main/parse.go
index e876010..492b58f 100644
--- a/main/parse.go
+++ b/main/parse.go
@@ -11,11 +11,17 @@ type parser struct {
rewinds []Token
}
func (p *parser) next() Token {
+ var token Token
if len(p.rewinds) == 0 {
- return <- p.tokenStream
+ token = <- p.tokenStream
+ } else {
+ token = p.rewinds[len(p.rewinds)-1]
+ p.rewinds = p.rewinds[:len(p.rewinds)-1]
+ }
+ if token.typ == TokenErr {
+ fmt.Println(token)
+ panic("Lexing error")
}
- token := p.rewinds[len(p.rewinds)-1]
- p.rewinds = p.rewinds[:len(p.rewinds)-1]
return token
}
func (p *parser) rewind(token Token) {
@@ -27,41 +33,61 @@ func (p *parser) peek() Token {
return token
}
-// TODO: make a pratt parser
-func (p *parser) parsePathPatternFilter() PathFilterAST {
- var segments []PathFilterAST
+var segmentTokens map[TokenType]bool = map[TokenType]bool {
+ TokenHash: true,
+ TokenAt: true,
+ TokenDot: true,
+ TokenLParen: true,
+}
+
+func (p *parser) parsePathPatternFilter(minPower int) PathFilterAST {
+ var lhs PathFilterAST
+ token := p.next()
+ switch token.typ {
+ case TokenHash:
+ stringIndex := p.next()
+ if stringIndex.typ != TokenPatternStringIndex {
+ panic("Expected string index after # in pattern")
+ }
+ lhs = StringSegmentPathFilterAST{stringIndex.val}
+ case TokenAt:
+ intIndex := p.next()
+ if intIndex.typ != TokenPatternIntegerIndex {
+ panic("Expected integer index after @ in pattern")
+ }
+ index, err := strconv.Atoi(intIndex.val)
+ if err != nil {
+ panic("Expected integer index after @ in pattern")
+ }
+ lhs = IntegerSegmentPathFilterAST{index}
+ case TokenDot:
+ lhs = AnySegmentPathFilterAST{}
+ case TokenLParen:
+ lhs = p.parsePathPatternFilter(0)
+ if p.next().typ != TokenRParen {
+ panic("Expected )")
+ }
+ default:
+ panic("Expected path pattern filter segment")
+ }
loop: for {
- token := p.next()
- switch token.typ {
- case TokenHash:
- stringIndex := p.next()
- if stringIndex.typ != TokenPatternStringIndex {
- panic("Expected string index after # in pattern")
- }
- segments = append(segments, StringSegmentPathFilterAST{stringIndex.val})
- case TokenAt:
- intIndex := p.next()
- if intIndex.typ != TokenPatternIntegerIndex {
- panic("Expected integer index after @ in pattern")
- }
- index, err := strconv.Atoi(intIndex.val)
- if err != nil {
- panic("Expected integer index after @ in pattern")
- }
- segments = append(segments, IntegerSegmentPathFilterAST{index})
- case TokenDot:
- segments = append(segments, AnySegmentPathFilterAST{})
- case TokenAst:
- if len(segments) == 0 {
- panic("Invalid * in pattern, * must go after something")
- }
- segments[len(segments) - 1] = RepeatPathFilterAST {segments[len(segments)-1]}
+ token = p.next()
+ switch {
+ case token.typ == TokenAst && 10 >= minPower:
+ lhs = RepeatPathFilterAST {lhs}
+ case token.typ == TokenQuestion && 10 >= minPower:
+ lhs = OrPathFilterAST{lhs, NonePathFilterAST{}}
+ case token.typ == TokenBar && 0 >= minPower:
+ lhs = OrPathFilterAST{lhs, p.parsePathPatternFilter(1)}
+ case segmentTokens[token.typ] && 2 >= minPower:
+ p.rewind(token)
+ lhs = SequencePathFilterAST {lhs, p.parsePathPatternFilter(3)}
default:
p.rewind(token)
break loop
}
}
- return SequencePathFilterAST {segments}
+ return lhs
}
// TODO: should only return a single filter
@@ -71,7 +97,7 @@ func (p *parser) parseFilter() []Filter {
switch token.typ {
case TokenHash, TokenAt, TokenDot:
p.rewind(token)
- filterAst := p.parsePathPatternFilter()
+ filterAst := p.parsePathPatternFilter(0)
filters = append(filters, compilePathFilterAST(filterAst))
token = p.next()
}
@@ -114,7 +140,6 @@ func (p *parser) parseCommand() Command {
}
return p.parseBasicCommand(commandChar)
default:
- fmt.Println(token)
panic("Invalid token, expected command")
}
}