diff --git a/lexer.go b/lexer.go index 9b92da5..e7095a4 100644 --- a/lexer.go +++ b/lexer.go @@ -27,13 +27,56 @@ const ( item_range_close ) +func (i itemType) String() string { + switch i { + case item_eof: + return "eof" + + case item_error: + return "error" + + case item_text: + return "text" + + case item_any: + return "any" + + case item_single: + return "single" + + case item_range_open: + return "range_open" + + case item_range_not: + return "range_not" + + case item_range_lo: + return "range_lo" + + case item_range_minus: + return "range_minus" + + case item_range_hi: + return "range_hi" + + case item_range_chars: + return "range_chars" + + case item_range_close: + return "range_close" + + default: + return "undef" + } +} + type item struct { t itemType s string } func (i item) String() string { - return fmt.Sprintf("%v[%s]", i.t, i.s) + return fmt.Sprintf("%v<%s>", i.t, i.s) } type lexer struct { @@ -193,7 +236,7 @@ func lexInsideRange(l *lexer) stateFn { switch c { case inside_range_not: // only first char makes sense - if l.pos == l.start { + if l.pos-1 == l.start { l.emit(item_range_not) } @@ -221,6 +264,8 @@ func lexAny(l *lexer) stateFn { } func lexRangeHiLo(l *lexer) stateFn { + start := l.start + for { c := l.read() if c == eof { @@ -228,22 +273,37 @@ func lexRangeHiLo(l *lexer) stateFn { return nil } - if l.pos-l.start != 1 { - l.errorf("unexpected length of char inside range") - return nil - } - switch c { case inside_range_minus: + if l.pos-l.start != 1 { + l.errorf("unexpected length of range: single character expected before minus") + return nil + } + l.emit(item_range_minus) case range_close: l.unread() - l.flush(item_range_hi) + + if l.pos-l.start != 1 { + l.errorf("unexpected length of range: single character expected before close") + return nil + } + + l.emit(item_range_hi) return lexRangeClose default: - l.flush(item_range_lo) + if start != l.start { + continue + } + + if l.pos-l.start != 1 { + l.errorf("unexpected length of range: single character expected at the begining") + return nil + } + + l.emit(item_range_lo) } } } diff --git a/lexer_test.go b/lexer_test.go new file mode 100644 index 0000000..69f3703 --- /dev/null +++ b/lexer_test.go @@ -0,0 +1,100 @@ +package glob + +import ( + "testing" +) + +func TestLexGood(t *testing.T) { + for _, test := range []struct { + pattern string + items []item + }{ + { + pattern: "hello", + items: []item{ + item{item_text, "hello"}, + item{item_eof, ""}, + }, + }, + { + pattern: "hello?", + items: []item{ + item{item_text, "hello"}, + item{item_single, "?"}, + item{item_eof, ""}, + }, + }, + { + pattern: "hello*", + items: []item{ + item{item_text, "hello"}, + item{item_any, "*"}, + item{item_eof, ""}, + }, + }, + { + pattern: "hello**", + items: []item{ + item{item_text, "hello"}, + item{item_any, "*"}, + item{item_any, "*"}, + item{item_eof, ""}, + }, + }, + { + pattern: "[a-b]", + items: []item{ + item{item_range_open, "["}, + item{item_range_lo, "a"}, + item{item_range_minus, "-"}, + item{item_range_hi, "b"}, + item{item_range_close, "]"}, + item{item_eof, ""}, + }, + }, + { + pattern: "[!a-b]", + items: []item{ + item{item_range_open, "["}, + item{item_range_not, "!"}, + item{item_range_lo, "a"}, + item{item_range_minus, "-"}, + item{item_range_hi, "b"}, + item{item_range_close, "]"}, + item{item_eof, ""}, + }, + }, + { + pattern: "[abc]", + items: []item{ + item{item_range_open, "["}, + item{item_range_chars, "abc"}, + item{item_range_close, "]"}, + item{item_eof, ""}, + }, + }, + { + pattern: "[!abc]", + items: []item{ + item{item_range_open, "["}, + item{item_range_not, "!"}, + item{item_range_chars, "abc"}, + item{item_range_close, "]"}, + item{item_eof, ""}, + }, + }, + } { + lexer := newLexer(test.pattern) + for _, exp := range test.items { + act := lexer.nextItem() + if act.t != exp.t { + t.Errorf("wrong item type: exp: %v; act: %v (%s vs %s)", exp.t, act.t, exp, act) + break + } + if act.s != exp.s { + t.Errorf("wrong item contents: exp: %q; act: %q (%s vs %s)", exp.s, act.s, exp, act) + break + } + } + } +} diff --git a/parser.go b/parser.go index 761b8b4..d5614f7 100644 --- a/parser.go +++ b/parser.go @@ -104,6 +104,10 @@ func parserRange(lexer *lexer, separators string) ([]token, parseFn, error) { return nil, nil, fmt.Errorf("unexpected length of hi character") } + if hi < lo { + return nil, nil, fmt.Errorf("hi character should be greater than lo") + } + hi = r[0] case item_range_chars: @@ -120,6 +124,10 @@ func parserRange(lexer *lexer, separators string) ([]token, parseFn, error) { if isRange { return []token{token{match.Between{lo, hi, not}, ""}}, parserMain, nil } else { + if len(chars) == 0 { + return nil, nil, fmt.Errorf("chars range should not be empty") + } + return []token{token{match.RangeList{chars, not}, ""}}, parserMain, nil } } diff --git a/parser_test.go b/parser_test.go index 31525a6..685d003 100644 --- a/parser_test.go +++ b/parser_test.go @@ -1,13 +1,12 @@ package glob import ( - "fmt" "testing" ) func TestParseString(t *testing.T) { - lexer := newLexer("hello") - fmt.Println(lexer.nextItem()) - fmt.Println(lexer.nextItem()) - fmt.Println(lexer.nextItem()) + // lexer := newLexer("hello") + // fmt.Println(lexer.nextItem()) + // fmt.Println(lexer.nextItem()) + // fmt.Println(lexer.nextItem()) }