diff --git a/examples/example_basiccalculator1_test.go b/examples/example_basiccalculator1_test.go index 02f20eb..1809d22 100644 --- a/examples/example_basiccalculator1_test.go +++ b/examples/example_basiccalculator1_test.go @@ -75,7 +75,7 @@ var bareInteger = parsekit.C.Seq(dropBlank, parsekit.A.Integer, dropBlank) var int64Token = parsekit.T.Int64(nil, bareInteger) func (c *simpleCalculator) number(p *parsekit.ParseAPI) { - if p.On(int64Token).Accept() { + if p.Accept(int64Token) { c.Result += c.op * p.Result().Value(0).(int64) p.Handle(c.operatorOrEndOfFile) } else { @@ -86,13 +86,13 @@ func (c *simpleCalculator) number(p *parsekit.ParseAPI) { func (c *simpleCalculator) operatorOrEndOfFile(p *parsekit.ParseAPI) { var A = parsekit.A switch { - case p.On(A.Add).Skip(): + case p.Accept(A.Add): c.op = +1 p.Handle(c.number) - case p.On(A.Subtract).Skip(): + case p.Accept(A.Subtract): c.op = -1 p.Handle(c.number) - case !p.On(A.EndOfFile).Stay(): + case !p.Accept(A.EndOfFile): p.Expected("operator, '+' or '-'") default: p.ExpectEndOfFile() diff --git a/examples/example_basiccalculator2_test.go b/examples/example_basiccalculator2_test.go index ebf08b8..78aa963 100644 --- a/examples/example_basiccalculator2_test.go +++ b/examples/example_basiccalculator2_test.go @@ -96,7 +96,7 @@ func (calc *calculator) expr(p *parsekit.ParseAPI) { var C, A = parsekit.C, parsekit.A if p.Handle(calc.term) { - for p.On(C.Any(A.Add, A.Subtract)).Accept() { + for p.Accept(C.Any(A.Add, A.Subtract)) { op := p.Result().Rune(0) if !p.Handle(calc.term) { return @@ -114,7 +114,7 @@ func (calc *calculator) term(p *parsekit.ParseAPI) { var C, A = parsekit.C, parsekit.A if p.Handle(calc.factor) { - for p.On(C.Any(A.Multiply, A.Divide)).Accept() { + for p.Accept(C.Any(A.Multiply, A.Divide)) { op := p.Result().Rune(0) if !p.Handle(calc.factor) { return @@ -130,16 +130,16 @@ func (calc *calculator) term(p *parsekit.ParseAPI) { // = (FLOAT | LPAREN RPAREN) func (calc *calculator) factor(p *parsekit.ParseAPI) { var A, T = parsekit.A, parsekit.T - p.On(A.Blanks).Skip() + p.Accept(A.Blanks) switch { - case p.On(T.Float64(nil, A.Signed(A.Float))).Accept(): + case p.Accept(T.Float64(nil, A.Signed(A.Float))): value := p.Result().Value(0).(float64) calc.interpreter.pushValue(value) - case p.On(A.LeftParen).Skip(): + case p.Accept(A.LeftParen): if !p.Handle(calc.expr) { return } - if !p.On(A.RightParen).Skip() { + if !p.Accept(A.RightParen) { p.Expected("')'") return } @@ -147,7 +147,7 @@ func (calc *calculator) factor(p *parsekit.ParseAPI) { p.Expected("factor or parenthesized expression") return } - p.On(A.Blanks).Skip() + p.Accept(A.Blanks) } // --------------------------------------------------------------------------- diff --git a/examples/example_helloManyStateParser_test.go b/examples/example_helloManyStateParser_test.go index c7ece89..c019ba6 100644 --- a/examples/example_helloManyStateParser_test.go +++ b/examples/example_helloManyStateParser_test.go @@ -82,7 +82,7 @@ func (h *helloparser1) Parse(input string) (string, *parsekit.Error) { func (h *helloparser1) start(p *parsekit.ParseAPI) { a := parsekit.A - if p.On(a.StrNoCase("hello")).Skip() { + if p.Accept(a.StrNoCase("hello")) { p.Handle(h.comma) } else { p.Expected("hello") @@ -92,9 +92,9 @@ func (h *helloparser1) start(p *parsekit.ParseAPI) { func (h *helloparser1) comma(p *parsekit.ParseAPI) { a := parsekit.A switch { - case p.On(a.Blanks).Skip(): + case p.Accept(a.Blanks): p.Handle(h.comma) - case p.On(a.Comma).Skip(): + case p.Accept(a.Comma): p.Handle(h.startName) default: p.Expected("comma") @@ -103,8 +103,8 @@ func (h *helloparser1) comma(p *parsekit.ParseAPI) { func (h *helloparser1) startName(p *parsekit.ParseAPI) { a := parsekit.A - p.On(a.Blanks).Skip() - if p.On(a.AnyRune).Stay() { + p.Accept(a.Blanks) + if p.Peek(a.AnyRune) { p.Handle(h.name) } else { p.Expected("name") @@ -114,9 +114,9 @@ func (h *helloparser1) startName(p *parsekit.ParseAPI) { func (h *helloparser1) name(p *parsekit.ParseAPI) { a := parsekit.A switch { - case p.On(a.Excl).Stay(): + case p.Peek(a.Excl): p.Handle(h.exclamation) - case p.On(a.AnyRune).Accept(): + case p.Accept(a.AnyRune): h.greetee += p.Result().String() p.Handle(h.name) default: @@ -126,7 +126,7 @@ func (h *helloparser1) name(p *parsekit.ParseAPI) { func (h *helloparser1) exclamation(p *parsekit.ParseAPI) { a := parsekit.A - if p.On(a.Excl).Accept() { + if p.Accept(a.Excl) { p.Handle(h.end) } else { p.Expected("exclamation") @@ -138,7 +138,7 @@ func (h *helloparser1) exclamation(p *parsekit.ParseAPI) { // error message. func (h *helloparser1) end(p *parsekit.ParseAPI) { var a = parsekit.A - if !p.On(a.EndOfFile).Stay() { + if !p.Accept(a.EndOfFile) { p.Expected("end of greeting") return } diff --git a/examples/example_helloSingleStateParser_test.go b/examples/example_helloSingleStateParser_test.go index 691ac75..40c5d4b 100644 --- a/examples/example_helloSingleStateParser_test.go +++ b/examples/example_helloSingleStateParser_test.go @@ -80,15 +80,15 @@ func (h *helloparser2) Parse(input string) (string, *parsekit.Error) { func (h *helloparser2) start(p *parsekit.ParseAPI) { c, a, m := parsekit.C, parsekit.A, parsekit.M - if !p.On(a.StrNoCase("hello")).Skip() { + if !p.Accept(a.StrNoCase("hello")) { p.Error("the greeting is not being friendly") return } - if !p.On(c.Seq(c.Opt(a.Blank), a.Comma, c.Opt(a.Blank))).Skip() { + if !p.Accept(c.Seq(c.Opt(a.Blank), a.Comma, c.Opt(a.Blank))) { p.Error("the greeting is not properly separated") return } - if p.On(m.TrimSpace(c.OneOrMore(c.Except(a.Excl, a.AnyRune)))).Accept() { + if p.Accept(m.TrimSpace(c.OneOrMore(c.Except(a.Excl, a.AnyRune)))) { h.greetee = p.Result().String() if h.greetee == "" { p.Error("the name cannot be empty") @@ -98,9 +98,9 @@ func (h *helloparser2) start(p *parsekit.ParseAPI) { p.Error("the greeting is targeted at thin air") return } - if !p.On(a.Excl).Skip() { + if !p.Accept(a.Excl) { p.Error("the greeting is not loud enough") - } else if !p.On(a.EndOfFile).Stay() { + } else if !p.Accept(a.EndOfFile) { p.Error("too much stuff going on after the closing '!'") } else { p.Stop() diff --git a/examples/examples_state_test.go b/examples/examples_state_test.go index 7dfbe83..c54b5c1 100644 --- a/examples/examples_state_test.go +++ b/examples/examples_state_test.go @@ -20,7 +20,7 @@ func (l *Chunks) AddChopped(s string, chunkSize int) *parsekit.Error { chunkOfRunes := c.MinMax(1, chunkSize, a.AnyRune) parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { - for p.On(chunkOfRunes).Accept() { + for p.Accept(chunkOfRunes) { *l = append(*l, p.Result().String()) } }) diff --git a/parseapi.go b/parseapi.go index 3791e5b..c730d1a 100644 --- a/parseapi.go +++ b/parseapi.go @@ -15,6 +15,59 @@ type ParseAPI struct { stopped bool // a boolean set to true by Stop(), further ParseAPI calls are ignored } +// Peek checks if the upcoming input data matches the provided TokenHandler. +// If it does, then true will be returned, false otherwise. The read cursor +// will be kept at the same position, so the next call to Peek() or Accept() +// will start from the same cursor position. +// +// After calling this method, you can retrieve the produced TokenHandlerResult +// using the ParseAPI.Result() method. +func (p *ParseAPI) Peek(tokenHandler TokenHandler) bool { + p.result = nil + forkedTokenAPI, ok := p.invokeTokenHandler("Peek", tokenHandler) + if ok { + p.result = forkedTokenAPI.Result() + p.tokenAPI.clearResults() + p.tokenAPI.detachChilds() + } + return ok +} + +// Accept checks if the upcoming input data matches the provided TokenHandler. +// If it does, then true will be returned, false otherwise. The read cursor +// will be moved forward to beyond the match that was found. +// +// After calling this method, you can retrieve the produced TokenHandlerResult +// using the ParseAPI.Result() method. +func (p *ParseAPI) Accept(tokenHandler TokenHandler) bool { + p.result = nil + forkedTokenAPI, ok := p.invokeTokenHandler("Accept", tokenHandler) + if ok { + forkedTokenAPI.Merge() + p.result = p.tokenAPI.Result() + p.tokenAPI.detachChilds() + if p.tokenAPI.flushReader() { + p.initLoopCheck() + } + } + return ok +} + +func (p *ParseAPI) invokeTokenHandler(name string, tokenHandler TokenHandler) (*TokenAPI, bool) { + p.panicWhenStoppedOrInError() + p.checkForLoops() + if tokenHandler == nil { + callerPanic(2, "parsekit.ParseAPI.%s(): %s() called with nil tokenHandler argument at {caller}", name, name) + } + + p.result = nil + p.tokenAPI.clearResults() + child := p.tokenAPI.Fork() + ok := tokenHandler(child) + + return child, ok +} + // panicWhenStoppedOrInError will panic when the parser has produced an error // or when it has been stopped. It is used from the ParseAPI methods, to // prevent further calls to the ParseAPI on these occasions. @@ -47,147 +100,23 @@ func (p *ParseAPI) initLoopCheck() { } func (p *ParseAPI) checkForLoops() { - filepos := callerFilepos(2) + filepos := callerFilepos(3) if _, ok := p.loopCheck[filepos]; ok { - callerPanic(2, "parsekit.ParseAPI: Loop detected in parser at {caller}") + callerPanic(3, "parsekit.ParseAPI: Loop detected in parser at {caller}") } p.loopCheck[filepos] = true } -// On checks if the input at the current cursor position matches the provided -// TokenHandler. On must be chained with another method that tells the parser -// what action to perform when a match was found: -// -// 1) On(...).Skip() - Move read cursor forward, ignoring the match results. -// -// 2) On(...).Accept() - Move cursor, making results available through Result() -// -// 3) On(...).Stay() - Do nothing, the cursor stays at the same position. -// -// So an example chain could look like this: -// -// p.On(parsekit.A.Blank).Skip() -// -// The chain as a whole returns a boolean that indicates whether or not at match -// was found. When no match was found, false is returned and Skip() and Accept() -// will have no effect. Because of this, typical use of an On() chain is as -// expression for a conditional statement (if, switch/case, for). E.g.: -// -// // Skip multiple exclamation marks. -// for p.On(parsekit.A.Excl).Skip() { } -// -// // Fork a route based on the input. -// switch { -// case p.On(parsekit.A.Excl).Stay() -// p.RouteTo(stateHandlerA) -// case p.On(parsekit.A.Colon).Stay(): -// p.RouteTo(stateHandlerB) -// default: -// p.RouteTo(stateHandlerC) -// } -// -// // Echo back a sequence of digits on the input. -// if p.On(parsekit.A.Digits).Accept() { -// fmt.Println(p.Result().String()) -// } -func (p *ParseAPI) On(tokenHandler TokenHandler) *ParseAPIOnAction { - p.panicWhenStoppedOrInError() - p.checkForLoops() - if tokenHandler == nil { - callerPanic(1, "parsekit.ParseAPI.On(): On() called with nil tokenHandler argument at {caller}") - } - - p.result = nil - p.tokenAPI.clearResults() - child := p.tokenAPI.Fork() - ok := tokenHandler(child) - - return &ParseAPIOnAction{ - parseAPI: p, - tokenAPI: p.tokenAPI, - forkedTokenAPI: child, - ok: ok, - } -} - -// ParseAPIOnAction is a struct that is used for building the On()-method chain. -// The On() method will return an initialized struct of this type. -type ParseAPIOnAction struct { - parseAPI *ParseAPI - tokenAPI *TokenAPI - forkedTokenAPI *TokenAPI - ok bool -} - -// Accept tells the parser to move the read cursor past a match that was -// found by a TokenHandler, and to make the TokenHandlerResult from the -// TokenAPI available in the ParseAPI through the ParseAPI.Result() method. -// -// Returns true in case a match was found by On(). -// When no match was found, then no action is taken, no results are -// exposed and false is returned. -func (a *ParseAPIOnAction) Accept() bool { - if a.ok { - a.forkedTokenAPI.Merge() - a.parseAPI.result = a.tokenAPI.Result() - a.tokenAPI.detachChilds() - if a.tokenAPI.flushReader() { - a.parseAPI.initLoopCheck() - } - } - return a.ok -} - -// Skip tells the parser to move the cursor past a match that was found, -// without making the results available through the ParseAPI. -// -// Note that functionally, you could call Accept() just as well, simply -// ignoring the results. However, the Skip() call is a bit more efficient -// than the Accept() call and (more important if you ask me) the code -// expresses more clearly that your intent is to skip the match. -// -// Returns true in case a match was found by On(). -// When no match was found, then no action is taken and false is returned. -func (a *ParseAPIOnAction) Skip() bool { - if a.ok { - a.parseAPI.result = nil - a.forkedTokenAPI.clearResults() - a.tokenAPI.detachChilds() - a.forkedTokenAPI.syncCursorTo(a.tokenAPI) - if a.tokenAPI.flushReader() { - a.parseAPI.initLoopCheck() - } - } - return a.ok -} - -// Stay tells the parser to not move the cursor after finding a match. -// -// A typical use of Stay() is to let one ParseHandler detect the start -// of some kind of token, but without moving the read cursor forward. -// When a match is found, it hands off control to another ParseHandler -// to take care of the actual token parsing. -// -// Returns true in case a match was found by On(), false otherwise. -func (a *ParseAPIOnAction) Stay() bool { - if a.ok { - a.parseAPI.result = nil - a.tokenAPI.clearResults() - a.tokenAPI.detachChilds() - } - return a.ok -} - // Result returns a TokenHandlerResult struct, containing results as produced by the -// last ParseAPI.On().Accept() call. +// last Peek() or Accept() call. // -// When Result() is called without first doing a ParsAPI.On().Accept(), then no +// When Result() is called without first doing a Peek() or Accept(), then no // result will be available and the method will panic. func (p *ParseAPI) Result() *TokenHandlerResult { result := p.result if p.result == nil { callerPanic(1, "parsekit.ParseAPI.TokenHandlerResult(): TokenHandlerResult() called "+ - "at {caller} without calling ParseAPI.Accept() on beforehand") + "at {caller} without calling ParseAPI.Peek() or ParseAPI.Accept() on beforehand") } return result } @@ -246,7 +175,7 @@ func (p *ParseAPI) Error(format string, args ...interface{}) { // as the expectation. func (p *ParseAPI) ExpectEndOfFile() { p.panicWhenStoppedOrInError() - if p.On(A.EndOfFile).Stay() { + if p.Peek(A.EndOfFile) { p.Stop() } else { p.Expected("end of file") diff --git a/parser_test.go b/parser_test.go index 5d48b8b..f483f59 100644 --- a/parser_test.go +++ b/parser_test.go @@ -14,7 +14,7 @@ func ExampleParser_usingAcceptedRunes() { matches := []string{} parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { - for p.On(a.AnyRune).Accept() { + for p.Accept(a.AnyRune) { matches = append(matches, p.Result().String()) } p.ExpectEndOfFile() @@ -31,7 +31,7 @@ func ExampleParser_usingTokens() { c, a, tok := parsekit.C, parsekit.A, parsekit.T parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { - if p.On(c.OneOrMore(tok.Rune("RUNE", a.AnyRune))).Accept() { + if p.Accept(c.OneOrMore(tok.Rune("RUNE", a.AnyRune))) { fmt.Printf("Runes accepted: %q\n", p.Result().String()) fmt.Printf("Token values: %s\n", p.Result().Tokens()) } @@ -55,12 +55,12 @@ func ExampleParseAPI_Expected() { // unexpected input (expected a thing) at start of file } -func ExampleParseAPIOnAction_Accept() { +func ExampleParseAPI_Accept_inIfStatement() { parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { // When a case-insensitive match on "Yowza!" is found by the // tokenizer, then Accept() will make the result available // through ParseAPI.Result() - if p.On(parsekit.A.StrNoCase("Yowza!")).Accept() { + if p.Accept(parsekit.A.StrNoCase("Yowza!")) { // Result.String() returns a string containing all // accepted runes that were matched against. fmt.Println(p.Result().String()) @@ -72,14 +72,14 @@ func ExampleParseAPIOnAction_Accept() { // YOWZA! } -func ExampleParseAPIOnAction_Skip() { +func ExampleParseAPI_Accept_inSwitchStatement() { var result string parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { for loop := true; loop; { switch { - case p.On(parsekit.A.Rune('X')).Skip(): + case p.Accept(parsekit.A.Rune('X')): // NOOP, skip this rune - case p.On(parsekit.A.AnyRune).Accept(): + case p.Accept(parsekit.A.AnyRune): result += p.Result().String() default: loop = false @@ -98,7 +98,7 @@ func ExampleParseAPI_Stop() { parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { fmt.Printf("First word: ") - for p.On(C.Not(A.Space)).Accept() { + for p.Accept(C.Not(A.Space)) { fmt.Printf("%s", p.Result()) } p.Stop() @@ -114,7 +114,7 @@ func ExampleParseAPI_Stop_notCalledAndNoInputPending() { parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { fmt.Printf("Word: ") - for p.On(C.Not(A.Space)).Accept() { + for p.Accept(C.Not(A.Space)) { fmt.Printf("%s", p.Result()) } fmt.Printf("\n") @@ -132,7 +132,7 @@ func ExampleParseAPI_Stop_notCalledButInputPending() { parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { fmt.Printf("First word: ") - for p.On(C.Not(A.Space)).Accept() { + for p.Accept(C.Not(A.Space)) { fmt.Printf("%s", p.Result()) } fmt.Printf("\n") @@ -145,14 +145,14 @@ func ExampleParseAPI_Stop_notCalledButInputPending() { // Error: unexpected input (expected end of file) at line 1, column 6 } -func ExampleParseAPIOnAction_Stay() { +func ExampleParseAPI_Peek() { // Definition of a fantasy serial number format. C, A := parsekit.C, parsekit.A serialnr := C.Seq(A.Asterisk, A.ASCIIUpper, A.ASCIIUpper, A.Digits) // This handler is able to handle serial numbers. serialnrHandler := func(p *parsekit.ParseAPI) { - if p.On(serialnr).Accept() { + if p.Accept(serialnr) { fmt.Println(p.Result().String()) } } @@ -160,7 +160,7 @@ func ExampleParseAPIOnAction_Stay() { // Start could function as a sort of dispatcher, handing over // control to the correct ParseHandler function, based on the input. start := func(p *parsekit.ParseAPI) { - if p.On(parsekit.A.Asterisk).Stay() { + if p.Peek(parsekit.A.Asterisk) { p.Handle(serialnrHandler) return } @@ -195,14 +195,25 @@ func TestGivenNullHandler_HandlePanics(t *testing.T) { Expect: `parsekit\.ParseAPI\.Handle\(\): Handle\(\) called with nil input ` + `at /.*/parser_test\.go:\d+`}) } -func TestGivenNilTokenHandler_OnPanics(t *testing.T) { +func TestGivenNilTokenHandler_AcceptPanics(t *testing.T) { p := parsekit.NewParser(func(p *parsekit.ParseAPI) { - p.On(nil) + p.Accept(nil) }) parsekit.AssertPanic(t, parsekit.PanicT{ Function: func() { p.Execute("") }, Regexp: true, - Expect: `parsekit\.ParseAPI\.On\(\): On\(\) called with nil ` + + Expect: `parsekit\.ParseAPI\.Accept\(\): Accept\(\) called with nil ` + + `tokenHandler argument at /.*/parser_test\.go:\d+`}) +} + +func TestGivenNilTokenHandler_PeekPanics(t *testing.T) { + p := parsekit.NewParser(func(p *parsekit.ParseAPI) { + p.Peek(nil) + }) + parsekit.AssertPanic(t, parsekit.PanicT{ + Function: func() { p.Execute("") }, + Regexp: true, + Expect: `parsekit\.ParseAPI\.Peek\(\): Peek\(\) called with nil ` + `tokenHandler argument at /.*/parser_test\.go:\d+`}) } @@ -236,7 +247,7 @@ func TestGivenParserWithErrorSet_HandlePanics(t *testing.T) { `at /.*/parser_test\.go:\d+: no calls allowed after ParseAPI\.Error\(\)`}) } -func TestGivenParserWithoutCallToAccept_ResultPanics(t *testing.T) { +func TestGivenParserWithoutCallToPeekOrAccept_ResultPanics(t *testing.T) { p := parsekit.NewParser(func(p *parsekit.ParseAPI) { p.Result() }) @@ -244,7 +255,7 @@ func TestGivenParserWithoutCallToAccept_ResultPanics(t *testing.T) { Function: func() { p.Execute("") }, Regexp: true, Expect: `parsekit\.ParseAPI\.TokenHandlerResult\(\): TokenHandlerResult\(\) called at ` + - `/.*/parser_test.go:\d+ without calling ParseAPI.Accept\(\) on beforehand`}) + `/.*/parser_test.go:\d+ without calling ParseAPI.Peek\(\) or ParseAPI.Accept\(\) on beforehand`}) } func TestGivenParserWhichIsNotStopped_WithNoMoreInput_FallbackExpectEndOfFileKicksIn(t *testing.T) { @@ -264,12 +275,12 @@ type parserWithLoop struct { } func (l *parserWithLoop) first(p *parsekit.ParseAPI) { - p.On(parsekit.A.ASCII).Accept() + p.Accept(parsekit.A.ASCII) p.Handle(l.second) } func (l *parserWithLoop) second(p *parsekit.ParseAPI) { - p.On(parsekit.A.ASCII).Accept() + p.Accept(parsekit.A.ASCII) p.Handle(l.third) } @@ -278,7 +289,7 @@ func (l *parserWithLoop) third(p *parsekit.ParseAPI) { p.Error("Loop not detected by parsekit") return } - p.On(parsekit.A.ASCII).Accept() + p.Accept(parsekit.A.ASCII) p.Handle(l.first) } @@ -307,7 +318,7 @@ func TestGivenLoopingParserDefinition_ParserPanics(t *testing.T) { func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) { var c, a = parsekit.C, parsekit.A parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { - for p.On(c.Max(5, a.AnyRune)).Accept() { + for p.Accept(c.Max(5, a.AnyRune)) { } p.Stop() }) diff --git a/tokenhandlers_builtin_test.go b/tokenhandlers_builtin_test.go index 07ea93d..2115bf2 100644 --- a/tokenhandlers_builtin_test.go +++ b/tokenhandlers_builtin_test.go @@ -390,7 +390,7 @@ func TestSequenceOfRunes(t *testing.T) { input := "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" output := "" parser := parsekit.NewParser(func(p *parsekit.ParseAPI) { - if p.On(sequence).Accept() { + if p.Accept(sequence) { output = p.Result().String() p.Stop() } else { diff --git a/tokenizer.go b/tokenizer.go index c9530bb..791d2b1 100644 --- a/tokenizer.go +++ b/tokenizer.go @@ -26,7 +26,7 @@ type TokenHandler func(t *TokenAPI) bool func NewTokenizer(tokenHandler TokenHandler) *Tokenizer { tokenizer := &Tokenizer{} tokenizer.parser = NewParser(func(p *ParseAPI) { - if p.On(tokenHandler).Accept() { + if p.Accept(tokenHandler) { tokenizer.result = p.Result() p.Stop() } else {