diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/filter.go | 51 | ||||
-rw-r--r-- | main/lex.go | 27 | ||||
-rw-r--r-- | main/parse.go | 50 |
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: |