<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/filter.go51
-rw-r--r--main/lex.go27
-rw-r--r--main/parse.go50
3 files changed, 87 insertions, 41 deletions
diff --git a/main/filter.go b/main/filter.go
index 662fa7b..796f558 100644
--- a/main/filter.go
+++ b/main/filter.go
@@ -32,31 +32,6 @@ func (filter MapTerminalFilter) exec(space WalkItem) bool {
return terminal == MapBegin || terminal == MapEnd
}
-type NonTerminalFilter struct {}
-func (filter NonTerminalFilter) exec(space WalkItem) bool {
- _, isTerminal := space.value.(TerminalValue)
- return !isTerminal
-}
-
-type RangeFilter struct {
- start Filter
- end Filter
- active bool
-}
-func (filter *RangeFilter) exec(space WalkItem) bool {
- if filter.active {
- if filter.end.exec(space) {
- filter.active = false
- }
- return true
- } else {
- if filter.start.exec(space) {
- filter.active = true
- }
- return filter.active
- }
-}
-
type BeginTerminalFilter struct {}
func (filter BeginTerminalFilter) exec(space WalkItem) bool {
terminal, isTerminal := space.value.(TerminalValue)
@@ -75,6 +50,32 @@ func (filter EndTerminalFilter) exec(space WalkItem) bool {
return terminal == ArrayEnd || terminal == MapEnd
}
+type TerminalFilter struct {}
+func (filter TerminalFilter) exec(space WalkItem) bool {
+ _, isTerminal := space.value.(TerminalValue)
+ return isTerminal
+}
+
+type RootFilter struct {}
+func (filter RootFilter) exec(space WalkItem) bool {
+ return len(space.path) == 0
+}
+
+type AndFilter struct {
+ left Filter
+ right Filter
+}
+func (filter AndFilter) exec(space WalkItem) bool {
+ return filter.left.exec(space) && filter.right.exec(space)
+}
+
+type NotFilter struct {
+ content Filter
+}
+func (filter NotFilter) exec(space WalkItem) bool {
+ return !filter.content.exec(space)
+}
+
type Filter interface {
exec(WalkItem) bool
} \ No newline at end of file
diff --git a/main/lex.go b/main/lex.go
index fdb3b59..91231ed 100644
--- a/main/lex.go
+++ b/main/lex.go
@@ -116,7 +116,13 @@ const (
TokenDot // .
TokenAst // *
TokenBar // |
+ TokenAnd // &&
+ TokenHat // ^
+ TokenDollar // $
TokenQuestion // ?
+ TokenHatDollar // ^$
+ TokenExclamation // !
+ TokenTilde // ~
TokenPatternStringIndex // A string index in a pattern
TokenPatternIntegerIndex // An integer index in a pattern
)
@@ -205,6 +211,27 @@ func lexCommand(l *lexer) stateFunc {
case '}':
l.emit(TokenRBrace)
return lexCommandEnd
+ case '&':
+ if l.accept("&") {
+ l.emit(TokenAnd)
+ return lexCommand
+ }
+ case '^':
+ if l.accept("$") {
+ l.emit(TokenHatDollar)
+ } else {
+ l.emit(TokenHat)
+ }
+ return lexCommand
+ case '$':
+ l.emit(TokenDollar)
+ return lexCommand
+ case '!':
+ l.emit(TokenExclamation)
+ return lexCommand
+ case '~':
+ l.emit(TokenTilde)
+ return lexCommand
}
if isAlpha(r) {
l.emit(TokenCommand)
diff --git a/main/parse.go b/main/parse.go
index 492b58f..0767c0d 100644
--- a/main/parse.go
+++ b/main/parse.go
@@ -90,22 +90,36 @@ func (p *parser) parsePathPatternFilter(minPower int) PathFilterAST {
return lhs
}
-// TODO: should only return a single filter
-func (p *parser) parseFilter() []Filter {
- var filters []Filter
+func (p *parser) parseFilter(minPower int) Filter {
+ var lhs Filter
token := p.next()
switch token.typ {
case TokenHash, TokenAt, TokenDot:
p.rewind(token)
filterAst := p.parsePathPatternFilter(0)
- filters = append(filters, compilePathFilterAST(filterAst))
- token = p.next()
+ lhs = compilePathFilterAST(filterAst)
+ case TokenHat:
+ lhs = BeginTerminalFilter{}
+ case TokenDollar:
+ lhs = EndTerminalFilter{}
+ case TokenHatDollar:
+ lhs = TerminalFilter{}
+ case TokenTilde:
+ lhs = RootFilter{}
+ default:
+ panic("Expected filter")
}
- if len(filters) == 0 {
- panic("Missing filter")
+ loop: for {
+ token = p.next()
+ switch {
+ case token.typ == TokenAnd && 2 >= minPower:
+ lhs = AndFilter {lhs, p.parseFilter(3)}
+ default:
+ p.rewind(token)
+ break loop
+ }
}
- p.rewind(token)
- return filters
+ return lhs
}
func (p *parser) parseBasicCommand(commandChar rune) Command {
@@ -122,15 +136,19 @@ func (p *parser) parseBasicCommand(commandChar rune) Command {
func (p *parser) parseCommand() Command {
token := p.next()
switch token.typ {
- case TokenHash, TokenAt, TokenDot:
+ case TokenHash, TokenAt, TokenDot, TokenLParen, TokenHat, TokenDollar, TokenHatDollar, TokenTilde:
p.rewind(token)
- filters := p.parseFilter()
+ filter := p.parseFilter(0)
+ notToken := p.next()
+ if notToken.typ == TokenExclamation {
+ filter = NotFilter {filter}
+ } else {
+ p.rewind(notToken)
+ }
command := p.parseCommand()
- for _, filter := range filters {
- command = FilteredCommand {
- filter: filter,
- command: command,
- }
+ command = FilteredCommand {
+ filter: filter,
+ command: command,
}
return command
case TokenCommand: