This commit is contained in:
s.kamardin 2015-12-25 21:08:54 +03:00
parent d400ac872c
commit f313fe3570
4 changed files with 181 additions and 14 deletions

View File

@ -27,13 +27,56 @@ const (
item_range_close 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 { type item struct {
t itemType t itemType
s string s string
} }
func (i item) String() 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 { type lexer struct {
@ -193,7 +236,7 @@ func lexInsideRange(l *lexer) stateFn {
switch c { switch c {
case inside_range_not: case inside_range_not:
// only first char makes sense // only first char makes sense
if l.pos == l.start { if l.pos-1 == l.start {
l.emit(item_range_not) l.emit(item_range_not)
} }
@ -221,6 +264,8 @@ func lexAny(l *lexer) stateFn {
} }
func lexRangeHiLo(l *lexer) stateFn { func lexRangeHiLo(l *lexer) stateFn {
start := l.start
for { for {
c := l.read() c := l.read()
if c == eof { if c == eof {
@ -228,22 +273,37 @@ func lexRangeHiLo(l *lexer) stateFn {
return nil return nil
} }
switch c {
case inside_range_minus:
if l.pos-l.start != 1 { if l.pos-l.start != 1 {
l.errorf("unexpected length of char inside range") l.errorf("unexpected length of range: single character expected before minus")
return nil return nil
} }
switch c {
case inside_range_minus:
l.emit(item_range_minus) l.emit(item_range_minus)
case range_close: case range_close:
l.unread() 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 return lexRangeClose
default: 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)
} }
} }
} }

100
lexer_test.go Normal file
View File

@ -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
}
}
}
}

View File

@ -104,6 +104,10 @@ func parserRange(lexer *lexer, separators string) ([]token, parseFn, error) {
return nil, nil, fmt.Errorf("unexpected length of hi character") 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] hi = r[0]
case item_range_chars: case item_range_chars:
@ -120,6 +124,10 @@ func parserRange(lexer *lexer, separators string) ([]token, parseFn, error) {
if isRange { if isRange {
return []token{token{match.Between{lo, hi, not}, ""}}, parserMain, nil return []token{token{match.Between{lo, hi, not}, ""}}, parserMain, nil
} else { } 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 return []token{token{match.RangeList{chars, not}, ""}}, parserMain, nil
} }
} }

View File

@ -1,13 +1,12 @@
package glob package glob
import ( import (
"fmt"
"testing" "testing"
) )
func TestParseString(t *testing.T) { func TestParseString(t *testing.T) {
lexer := newLexer("hello") // lexer := newLexer("hello")
fmt.Println(lexer.nextItem()) // fmt.Println(lexer.nextItem())
fmt.Println(lexer.nextItem()) // fmt.Println(lexer.nextItem())
fmt.Println(lexer.nextItem()) // fmt.Println(lexer.nextItem())
} }