Add is.To and is.Inc

This commit is contained in:
rwxrob 2022-03-03 04:24:30 -05:00
parent b86c1e15fb
commit 36c83cab0b
No known key found for this signature in database
GPG Key ID: 2B9111F33082AE77
3 changed files with 77 additions and 13 deletions

View File

@ -75,8 +75,30 @@ type Any []any
// found the scan is advanced (unlike Lk, which does not advance).
type Opt []any
// To is a set of advancing expressions that mark an exclusive boundary
// at which the scan should stop. The matching expression itself will
// not be advanced.
//
// In order to work with escaped boundaries use a negative
// look-ahead sequence combined with the boundary:
//
// is.To{s.Seq{is.Not{`\\`,`"`}}}
//
type To []any
// Inc is a set of advancing expressions that mark an inclusive boundary
// after which the scan should stop. The matching expression will be
// included in the advance (unlike is.To).
type Inc []any
// --------------------------- parameterized --------------------------
// EscTo is identical to is.To{s.Seq{is.Not{E,To}}}.
type EscTo struct {
E any
To any
}
// MMx is a parameterized advancing expression that matches an inclusive
// minimum and maximum count of the given expression (This). Use within
// is.Lk to disable advancement.
@ -113,12 +135,3 @@ type Rng struct {
First rune
Last rune
}
// Esc is a parameterized advancing expression that matches everything
// in the given expression (This) except for an expression (Not) that
// requires being immediately preceded by the escape expression (Esc).
type Esc struct {
Not any
Esc any
This any
}

View File

@ -279,6 +279,40 @@ func (s *R) Expect(scannables ...any) (*Cur, error) {
end = s.Mark()
s.Scan()
case is.Inc: // -----------------------------------------------------
var m *Cur
for m == nil && s.Cur.Rune != tk.EOD {
for _, i := range v {
m, _ = s.check(i)
}
s.Scan()
}
if m == nil {
err := s.ErrorExpected(v)
s.Jump(beg)
return nil, err
}
end = m
case is.To: // -----------------------------------------------------
var m *Cur
OUT:
for s.Cur.Rune != tk.EOD {
for _, i := range v {
m, _ = s.check(i)
if m != nil {
break OUT
}
}
s.Scan()
}
if m == nil {
err := s.ErrorExpected(v)
s.Jump(beg)
return nil, err
}
end = m
case is.Lk: // ----------------------------------------------------
var m *Cur
for _, i := range v {
@ -407,9 +441,6 @@ func (s *R) Expect(scannables ...any) (*Cur, error) {
end = s.Mark()
s.Scan()
case is.Esc: // ----------------------------------------------------
// TODO
case Hook: // ------------------------------------------------------
if !v(s) {
return nil, fmt.Errorf(
@ -480,6 +511,9 @@ func (s *R) ErrorExpected(this any, args ...any) error {
case is.Rng:
str := `expected range [%v-%v]`
msg = fmt.Sprintf(str, string(v.First), string(v.Last))
case is.To, is.Inc:
str := `%q not found`
msg = fmt.Sprintf(str, v)
default:
msg = fmt.Sprintf(`expected %T %q`, v, v)
}

View File

@ -383,7 +383,24 @@ func ExampleExpect_hook() {
}
// TODO Esc
func ExampleExpect_inc() {
s, _ := scan.New("some thing")
s.Expect(is.Inc{`i`})
s.Print()
// Output:
// U+006E 'n' 1,9-9 (9-9)
}
func ExampleExpect_to() {
s, _ := scan.New("some thing")
s.Expect(is.To{`i`})
s.Print()
_, err := s.Expect(is.To{`z`})
fmt.Println(err)
// Output:
// U+0069 'i' 1,8-8 (8-8)
// ["z"] not found at <EOD>
}
func ExampleSnap() {
s, _ := scan.New("some thing")