Small code cleanup things, mainly backing up the changes.
This commit is contained in:
parent
99654c2f9e
commit
2293627232
|
@ -71,7 +71,7 @@ type simpleCalculator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A definition of an int64, which conveniently drops surrounding blanks.
|
// A definition of an int64, which conveniently drops surrounding blanks.
|
||||||
var dropBlank = tokenize.M.Drop(tokenize.C.Opt(tokenize.A.Blanks))
|
var dropBlank = tokenize.M.Drop(tokenize.C.Optional(tokenize.A.Blanks))
|
||||||
var bareInteger = tokenize.C.Seq(dropBlank, tokenize.A.Integer, dropBlank)
|
var bareInteger = tokenize.C.Seq(dropBlank, tokenize.A.Integer, dropBlank)
|
||||||
var int64Token = tokenize.T.Int64(nil, bareInteger)
|
var int64Token = tokenize.T.Int64(nil, bareInteger)
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ func createHelloTokenizer() tokenize.Func {
|
||||||
// that does all the work. The 'greeting' Handler matches the whole input and
|
// that does all the work. The 'greeting' Handler matches the whole input and
|
||||||
// drops all but the name from it.
|
// drops all but the name from it.
|
||||||
hello := a.StrNoCase("hello")
|
hello := a.StrNoCase("hello")
|
||||||
comma := c.Seq(c.Opt(a.Blanks), a.Comma, c.Opt(a.Blanks))
|
comma := c.Seq(c.Optional(a.Blanks), a.Comma, c.Optional(a.Blanks))
|
||||||
separator := c.Any(comma, a.Blanks)
|
separator := c.Any(comma, a.Blanks)
|
||||||
name := c.OneOrMore(c.Not(a.Excl))
|
name := c.OneOrMore(c.Not(a.Excl))
|
||||||
greeting := m.Drop(hello).
|
greeting := m.Drop(hello).
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (h *helloparser2) start(p *parse.API) {
|
||||||
p.Error("the greeting is not being friendly")
|
p.Error("the greeting is not being friendly")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !p.Accept(c.Seq(c.Opt(a.Blanks), a.Comma, c.Opt(a.Blanks))) {
|
if !p.Accept(c.Seq(c.Optional(a.Blanks), a.Comma, c.Optional(a.Blanks))) {
|
||||||
p.Error("the greeting is not properly separated")
|
p.Error("the greeting is not properly separated")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,9 +41,9 @@ func (handler Handler) SeparatedBy(separatorHandler Handler) Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional is syntactic sugar that allows you to write a construction like
|
// Optional is syntactic sugar that allows you to write a construction like
|
||||||
// MatchOpt(handler) as handler.Optional().
|
// MatchOptional(handler) as handler.Optional().
|
||||||
func (handler Handler) Optional() Handler {
|
func (handler Handler) Optional() Handler {
|
||||||
return MatchOpt(handler)
|
return MatchOptional(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Except is syntactic sugar that allows you to write a construction like
|
// Except is syntactic sugar that allows you to write a construction like
|
||||||
|
|
|
@ -31,7 +31,7 @@ func ExampleHandler_Times() {
|
||||||
|
|
||||||
func ExampleHandler_Then() {
|
func ExampleHandler_Then() {
|
||||||
c, a := tokenize.C, tokenize.A
|
c, a := tokenize.C, tokenize.A
|
||||||
phoneNumber := a.Rune('0').Then(c.Rep(9, a.Digit))
|
phoneNumber := a.Rune('0').Then(c.Repeated(9, a.Digit))
|
||||||
|
|
||||||
fmt.Println(phoneNumber.Match("0208888888"))
|
fmt.Println(phoneNumber.Match("0208888888"))
|
||||||
// Output:
|
// Output:
|
||||||
|
@ -40,7 +40,7 @@ func ExampleHandler_Then() {
|
||||||
|
|
||||||
func ExampleHandler_Or() {
|
func ExampleHandler_Or() {
|
||||||
c, a := tokenize.C, tokenize.A
|
c, a := tokenize.C, tokenize.A
|
||||||
phoneNumber := c.Seq(a.Str("00").Or(a.Plus), a.Str("31"), a.DigitNotZero, c.Rep(8, a.Digit))
|
phoneNumber := c.Seq(a.Str("00").Or(a.Plus), a.Str("31"), a.DigitNotZero, c.Repeated(8, a.Digit))
|
||||||
|
|
||||||
fmt.Println(phoneNumber.Match("+31209876543"))
|
fmt.Println(phoneNumber.Match("+31209876543"))
|
||||||
fmt.Println(phoneNumber.Match("0031209876543"))
|
fmt.Println(phoneNumber.Match("0031209876543"))
|
||||||
|
|
|
@ -28,29 +28,33 @@ import (
|
||||||
var C = struct {
|
var C = struct {
|
||||||
Any func(...Handler) Handler
|
Any func(...Handler) Handler
|
||||||
Not func(Handler) Handler
|
Not func(Handler) Handler
|
||||||
Opt func(Handler) Handler
|
|
||||||
Seq func(...Handler) Handler
|
Seq func(...Handler) Handler
|
||||||
Rep func(times int, handler Handler) Handler
|
|
||||||
Min func(min int, handler Handler) Handler
|
Min func(min int, handler Handler) Handler
|
||||||
Max func(max int, handler Handler) Handler
|
Max func(max int, handler Handler) Handler
|
||||||
|
Repeated func(times int, handler Handler) Handler
|
||||||
|
Optional func(Handler) Handler
|
||||||
ZeroOrMore func(Handler) Handler
|
ZeroOrMore func(Handler) Handler
|
||||||
OneOrMore func(Handler) Handler
|
OneOrMore func(Handler) Handler
|
||||||
MinMax func(min int, max int, handler Handler) Handler
|
MinMax func(min int, max int, handler Handler) Handler
|
||||||
Separated func(separated Handler, separator Handler) Handler
|
Separated func(separated Handler, separator Handler) Handler
|
||||||
Except func(except Handler, handler Handler) Handler
|
Except func(except Handler, handler Handler) Handler
|
||||||
|
FollowedBy func(lookAhead Handler, handler Handler) Handler
|
||||||
|
WhileFollowedBy func(lookahead Handler, handler Handler) Handler
|
||||||
}{
|
}{
|
||||||
Opt: MatchOpt,
|
|
||||||
Any: MatchAny,
|
Any: MatchAny,
|
||||||
Not: MatchNot,
|
Not: MatchNot,
|
||||||
Seq: MatchSeq,
|
Seq: MatchSeq,
|
||||||
Rep: MatchRep,
|
|
||||||
Min: MatchMin,
|
Min: MatchMin,
|
||||||
Max: MatchMax,
|
Max: MatchMax,
|
||||||
|
Repeated: MatchRep,
|
||||||
|
Optional: MatchOptional,
|
||||||
ZeroOrMore: MatchZeroOrMore,
|
ZeroOrMore: MatchZeroOrMore,
|
||||||
OneOrMore: MatchOneOrMore,
|
OneOrMore: MatchOneOrMore,
|
||||||
MinMax: MatchMinMax,
|
MinMax: MatchMinMax,
|
||||||
Separated: MatchSeparated,
|
Separated: MatchSeparated,
|
||||||
Except: MatchExcept,
|
Except: MatchExcept,
|
||||||
|
FollowedBy: MatchFollowedBy,
|
||||||
|
WhileFollowedBy: MatchWhileFollowedBy,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A provides convenient access to a range of atoms or functions to build atoms.
|
// A provides convenient access to a range of atoms or functions to build atoms.
|
||||||
|
@ -199,6 +203,7 @@ var A = struct {
|
||||||
Pipe: MatchRune('|'),
|
Pipe: MatchRune('|'),
|
||||||
CurlyClose: MatchRune('}'),
|
CurlyClose: MatchRune('}'),
|
||||||
Tilde: MatchRune('~'),
|
Tilde: MatchRune('~'),
|
||||||
|
Newline: MatchNewline(),
|
||||||
Blank: MatchBlank(),
|
Blank: MatchBlank(),
|
||||||
Blanks: MatchBlanks(),
|
Blanks: MatchBlanks(),
|
||||||
Whitespace: MatchWhitespace(),
|
Whitespace: MatchWhitespace(),
|
||||||
|
@ -339,6 +344,12 @@ func MatchRuneRange(start rune, end rune) Handler {
|
||||||
return MatchRuneByCallback(func(r rune) bool { return r >= start && r <= end })
|
return MatchRuneByCallback(func(r rune) bool { return r >= start && r <= end })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MatchNewline creates a handler that matches a newline, which is either
|
||||||
|
// a DOS-style newline (CRLF, \r\n) or a UNIX-style newline (just a LF, \n).
|
||||||
|
func MatchNewline() Handler {
|
||||||
|
return MatchAny(MatchStr("\r\n"), MatchRune('\n'))
|
||||||
|
}
|
||||||
|
|
||||||
// MatchBlank creates a Handler that matches one rune from the input
|
// MatchBlank creates a Handler that matches one rune from the input
|
||||||
// against blank characters, meaning tabs and spaces.
|
// against blank characters, meaning tabs and spaces.
|
||||||
//
|
//
|
||||||
|
@ -382,7 +393,7 @@ func MatchRuneByCallback(callback func(rune) bool) Handler {
|
||||||
|
|
||||||
// MatchEndOfLine creates a Handler that matches a newline ("\r\n" or "\n") or EOF.
|
// MatchEndOfLine creates a Handler that matches a newline ("\r\n" or "\n") or EOF.
|
||||||
func MatchEndOfLine() Handler {
|
func MatchEndOfLine() Handler {
|
||||||
return MatchAny(MatchStr("\r\n"), MatchRune('\n'), MatchEndOfFile())
|
return MatchAny(MatchNewline(), MatchEndOfFile())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatchStr creates a Handler that matches the input against the provided string.
|
// MatchStr creates a Handler that matches the input against the provided string.
|
||||||
|
@ -406,11 +417,11 @@ func MatchStrNoCase(expected string) Handler {
|
||||||
return MatchSeq(handlers...)
|
return MatchSeq(handlers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatchOpt creates a Handler that makes the provided Handler optional.
|
// MatchOptional creates a Handler that makes the provided Handler optional.
|
||||||
// When the provided Handler applies, then its output is used, otherwise
|
// When the provided Handler applies, then its output is used, otherwise
|
||||||
// no output is generated but still a successful match is reported (but the
|
// no output is generated but still a successful match is reported (but the
|
||||||
// result will be empty).
|
// result will be empty).
|
||||||
func MatchOpt(handler Handler) Handler {
|
func MatchOptional(handler Handler) Handler {
|
||||||
return MatchMinMax(0, 1, handler)
|
return MatchMinMax(0, 1, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,13 +591,38 @@ func MatchExcept(handler Handler, except Handler) Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO keep this?
|
||||||
|
func MatchFollowedBy(lookAhead Handler, handler Handler) Handler {
|
||||||
|
return func(t *API) bool {
|
||||||
|
child := t.Fork()
|
||||||
|
if handler(child) && lookAhead(child.Fork()) {
|
||||||
|
child.Merge()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO keep this? Make some useful tests first.
|
||||||
|
func MatchWhileFollowedBy(lookAhead Handler, handler Handler) Handler {
|
||||||
|
followedBy := MatchFollowedBy(lookAhead, handler)
|
||||||
|
return func(t *API) bool {
|
||||||
|
matches := 0
|
||||||
|
for followedBy(t) {
|
||||||
|
fmt.Printf("Matches so far: %q\n", t.Result().String())
|
||||||
|
matches++
|
||||||
|
}
|
||||||
|
return matches > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MatchSigned creates a Handler that checks if the provided Handler is
|
// MatchSigned creates a Handler that checks if the provided Handler is
|
||||||
// prefixed by an optional '+' or '-' sign. This can be used to turn numeric
|
// prefixed by an optional '+' or '-' sign. This can be used to turn numeric
|
||||||
// atoms into a signed version, e.g.
|
// atoms into a signed version, e.g.
|
||||||
//
|
//
|
||||||
// C.Signed(A.Integer)
|
// C.Signed(A.Integer)
|
||||||
func MatchSigned(handler Handler) Handler {
|
func MatchSigned(handler Handler) Handler {
|
||||||
sign := MatchOpt(MatchAny(MatchRune('+'), MatchRune('-')))
|
sign := MatchOptional(MatchAny(MatchRune('+'), MatchRune('-')))
|
||||||
return MatchSeq(sign, handler)
|
return MatchSeq(sign, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,7 +731,7 @@ func MatchInteger() Handler {
|
||||||
// Handler will report a match, so both "123" and "123.123" will match.
|
// Handler will report a match, so both "123" and "123.123" will match.
|
||||||
func MatchFloat() Handler {
|
func MatchFloat() Handler {
|
||||||
digits := MatchDigits()
|
digits := MatchDigits()
|
||||||
return MatchSeq(digits, MatchOpt(MatchSeq(MatchRune('.'), digits)))
|
return MatchSeq(digits, MatchOptional(MatchSeq(MatchRune('.'), digits)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatchBoolean creates a Handler function that checks if a boolean
|
// MatchBoolean creates a Handler function that checks if a boolean
|
||||||
|
@ -950,7 +986,7 @@ func MatchIPv6Net(normalize bool) Handler {
|
||||||
// even though we would have dropped the output anyway. So if you would like
|
// even though we would have dropped the output anyway. So if you would like
|
||||||
// to drop optional blanks (spaces and tabs), then use something like:
|
// to drop optional blanks (spaces and tabs), then use something like:
|
||||||
//
|
//
|
||||||
// M.Drop(C.Opt(A.Blanks))
|
// M.Drop(C.Optional(A.Blanks))
|
||||||
//
|
//
|
||||||
// instead of:
|
// instead of:
|
||||||
//
|
//
|
||||||
|
|
|
@ -18,8 +18,8 @@ func TestCombinators(t *testing.T) {
|
||||||
{"abc", c.Any(a.Rune('a'), a.Rune('b')), true, "a"},
|
{"abc", c.Any(a.Rune('a'), a.Rune('b')), true, "a"},
|
||||||
{"bcd", c.Any(a.Rune('a'), a.Rune('b')), true, "b"},
|
{"bcd", c.Any(a.Rune('a'), a.Rune('b')), true, "b"},
|
||||||
{"cde", c.Any(a.Rune('a'), a.Rune('b')), false, ""},
|
{"cde", c.Any(a.Rune('a'), a.Rune('b')), false, ""},
|
||||||
{"ababc", c.Rep(4, a.Runes('a', 'b')), true, "abab"},
|
{"ababc", c.Repeated(4, a.Runes('a', 'b')), true, "abab"},
|
||||||
{"ababc", c.Rep(5, a.Runes('a', 'b')), false, ""},
|
{"ababc", c.Repeated(5, a.Runes('a', 'b')), false, ""},
|
||||||
{"", c.Min(0, a.Rune('a')), true, ""},
|
{"", c.Min(0, a.Rune('a')), true, ""},
|
||||||
{"a", c.Min(0, a.Rune('a')), true, "a"},
|
{"a", c.Min(0, a.Rune('a')), true, "a"},
|
||||||
{"aaaaa", c.Min(4, a.Rune('a')), true, "aaaaa"},
|
{"aaaaa", c.Min(4, a.Rune('a')), true, "aaaaa"},
|
||||||
|
@ -55,12 +55,12 @@ func TestCombinators(t *testing.T) {
|
||||||
{"eeeeeX", c.ZeroOrMore(a.Rune('e')), true, "eeeee"},
|
{"eeeeeX", c.ZeroOrMore(a.Rune('e')), true, "eeeee"},
|
||||||
{"Hello, world!X", c.Seq(a.Str("Hello"), a.Comma, a.Space, a.Str("world"), a.Excl), true, "Hello, world!"},
|
{"Hello, world!X", c.Seq(a.Str("Hello"), a.Comma, a.Space, a.Str("world"), a.Excl), true, "Hello, world!"},
|
||||||
{"101010123", c.OneOrMore(c.Seq(a.Rune('1'), a.Rune('0'))), true, "101010"},
|
{"101010123", c.OneOrMore(c.Seq(a.Rune('1'), a.Rune('0'))), true, "101010"},
|
||||||
{"", c.Opt(c.OneOrMore(a.Rune('f'))), true, ""},
|
{"", c.Optional(c.OneOrMore(a.Rune('f'))), true, ""},
|
||||||
{"ghijkl", c.Opt(a.Rune('h')), true, ""},
|
{"ghijkl", c.Optional(a.Rune('h')), true, ""},
|
||||||
{"ghijkl", c.Opt(a.Rune('g')), true, "g"},
|
{"ghijkl", c.Optional(a.Rune('g')), true, "g"},
|
||||||
{"fffffX", c.Opt(c.OneOrMore(a.Rune('f'))), true, "fffff"},
|
{"fffffX", c.Optional(c.OneOrMore(a.Rune('f'))), true, "fffff"},
|
||||||
{"1,2,3,b,c", c.Separated(a.Comma, a.Digit), true, "1,2,3"},
|
{"1,2,3,b,c", c.Separated(a.Comma, a.Digit), true, "1,2,3"},
|
||||||
{`\x9a\x01\xF0\xfCAndSomeMoreStuff`, c.OneOrMore(c.Seq(a.Backslash, a.Rune('x'), c.Rep(2, a.HexDigit))), true, `\x9a\x01\xF0\xfC`},
|
{`\x9a\x01\xF0\xfCAndSomeMoreStuff`, c.OneOrMore(c.Seq(a.Backslash, a.Rune('x'), c.Repeated(2, a.HexDigit))), true, `\x9a\x01\xF0\xfC`},
|
||||||
{" ", m.Trim(c.OneOrMore(a.AnyRune), " "), true, ""},
|
{" ", m.Trim(c.OneOrMore(a.AnyRune), " "), true, ""},
|
||||||
{" ", m.TrimLeft(c.OneOrMore(a.AnyRune), " "), true, ""},
|
{" ", m.TrimLeft(c.OneOrMore(a.AnyRune), " "), true, ""},
|
||||||
{" ", m.TrimRight(c.OneOrMore(a.AnyRune), " "), true, ""},
|
{" ", m.TrimRight(c.OneOrMore(a.AnyRune), " "), true, ""},
|
||||||
|
@ -382,23 +382,23 @@ func TestTokenMakers(t *testing.T) {
|
||||||
func TestCombination(t *testing.T) {
|
func TestCombination(t *testing.T) {
|
||||||
var c, a, m = tokenize.C, tokenize.A, tokenize.M
|
var c, a, m = tokenize.C, tokenize.A, tokenize.M
|
||||||
demonic := c.Seq(
|
demonic := c.Seq(
|
||||||
c.Opt(a.SquareOpen),
|
c.Optional(a.SquareOpen),
|
||||||
m.Trim(
|
m.Trim(
|
||||||
c.Seq(
|
c.Seq(
|
||||||
c.Opt(a.Blanks),
|
c.Optional(a.Blanks),
|
||||||
c.Rep(3, a.AngleClose),
|
c.Repeated(3, a.AngleClose),
|
||||||
m.ByCallback(c.OneOrMore(a.StrNoCase("hello")), func(s string) string {
|
m.ByCallback(c.OneOrMore(a.StrNoCase("hello")), func(s string) string {
|
||||||
return fmt.Sprintf("%d", len(s))
|
return fmt.Sprintf("%d", len(s))
|
||||||
}),
|
}),
|
||||||
m.Replace(c.Separated(a.Comma, c.Opt(a.Blanks)), ", "),
|
m.Replace(c.Separated(a.Comma, c.Optional(a.Blanks)), ", "),
|
||||||
m.ToUpper(c.Min(1, a.ASCIILower)),
|
m.ToUpper(c.Min(1, a.ASCIILower)),
|
||||||
m.Drop(a.Excl),
|
m.Drop(a.Excl),
|
||||||
c.Rep(3, a.AngleOpen),
|
c.Repeated(3, a.AngleOpen),
|
||||||
c.Opt(a.Blanks),
|
c.Optional(a.Blanks),
|
||||||
),
|
),
|
||||||
" \t",
|
" \t",
|
||||||
),
|
),
|
||||||
c.Opt(a.SquareClose),
|
c.Optional(a.SquareClose),
|
||||||
)
|
)
|
||||||
|
|
||||||
AssertHandlers(t, []HandlerT{
|
AssertHandlers(t, []HandlerT{
|
||||||
|
|
Loading…
Reference in New Issue