Merged functionality of p.Expects(string) and p.UnexpectedInput().
It is now simply p.UnexpectedInput(string). This makes the naming of unexpected input not as magical, but explicit (which is a GoodThing). With one of the earlier incarnations of parsekit it did make sense, but it went in a way in which explicit is more idiomatic for the package.
This commit is contained in:
parent
3094b09284
commit
6d92e1dc68
|
@ -75,7 +75,7 @@ func AssertTokenHandlers(t *testing.T, testSet []TokenHandlerT) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func AssertTokenHandler(t *testing.T, test TokenHandlerT) {
|
func AssertTokenHandler(t *testing.T, test TokenHandlerT) {
|
||||||
result, err := NewTokenizer(test.TokenHandler, "a match").Execute(test.Input)
|
result, err := NewTokenizer(test.TokenHandler).Execute(test.Input)
|
||||||
if test.MustMatch {
|
if test.MustMatch {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test %q failed with error: %s", test.Input, err)
|
t.Errorf("Test %q failed with error: %s", test.Input, err)
|
||||||
|
@ -102,7 +102,7 @@ func AssertTokenMakers(t *testing.T, testSet []TokenMakerT) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func AssertTokenMaker(t *testing.T, test TokenMakerT) {
|
func AssertTokenMaker(t *testing.T, test TokenMakerT) {
|
||||||
result, err := NewTokenizer(test.TokenHandler, "a match").Execute(test.Input)
|
result, err := NewTokenizer(test.TokenHandler).Execute(test.Input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test %q failed with error: %s", test.Input, err)
|
t.Errorf("Test %q failed with error: %s", test.Input, err)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -75,10 +75,11 @@ var bareInteger = parsekit.C.Seq(dropWhitespace, parsekit.A.Integer, dropWhitesp
|
||||||
var int64Token = parsekit.T.Int64(nil, bareInteger)
|
var int64Token = parsekit.T.Int64(nil, bareInteger)
|
||||||
|
|
||||||
func (c *simpleCalculator) number(p *parsekit.ParseAPI) {
|
func (c *simpleCalculator) number(p *parsekit.ParseAPI) {
|
||||||
p.Expects("integer number")
|
|
||||||
if p.On(int64Token).Accept() {
|
if p.On(int64Token).Accept() {
|
||||||
c.Result += c.op * p.Result().Value(0).(int64)
|
c.Result += c.op * p.Result().Value(0).(int64)
|
||||||
p.Handle(c.operatorOrEndOfFile)
|
p.Handle(c.operatorOrEndOfFile)
|
||||||
|
} else {
|
||||||
|
p.UnexpectedInput("integer number")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +93,7 @@ func (c *simpleCalculator) operatorOrEndOfFile(p *parsekit.ParseAPI) {
|
||||||
c.op = -1
|
c.op = -1
|
||||||
p.Handle(c.number)
|
p.Handle(c.number)
|
||||||
case !p.On(A.EndOfFile).Stay():
|
case !p.On(A.EndOfFile).Stay():
|
||||||
p.Expects("operator, '+' or '-'")
|
p.UnexpectedInput("operator, '+' or '-'")
|
||||||
p.UnexpectedInput()
|
|
||||||
default:
|
default:
|
||||||
p.ExpectEndOfFile()
|
p.ExpectEndOfFile()
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,12 +140,11 @@ func (c *calculator) factor(p *parsekit.ParseAPI) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !p.On(A.RightParen).Skip() {
|
if !p.On(A.RightParen).Skip() {
|
||||||
p.Expects("')'")
|
p.UnexpectedInput("')'")
|
||||||
p.UnexpectedInput()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
p.UnexpectedInput()
|
p.UnexpectedInput("factor or (expression)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.On(A.Whitespace).Skip()
|
p.On(A.Whitespace).Skip()
|
||||||
|
|
|
@ -70,5 +70,5 @@ func createPostcodeTokenizer() *parsekit.Tokenizer {
|
||||||
|
|
||||||
// Create a Tokenizer that wraps the 'postcode' TokenHandler and allows
|
// Create a Tokenizer that wraps the 'postcode' TokenHandler and allows
|
||||||
// us to match some input against that handler.
|
// us to match some input against that handler.
|
||||||
return parsekit.NewTokenizer(postcode, "a Dutch postcode")
|
return parsekit.NewTokenizer(postcode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,51 +80,56 @@ func (h *helloparser1) Parse(input string) (string, *parsekit.Error) {
|
||||||
|
|
||||||
func (h *helloparser1) start(p *parsekit.ParseAPI) {
|
func (h *helloparser1) start(p *parsekit.ParseAPI) {
|
||||||
a := parsekit.A
|
a := parsekit.A
|
||||||
p.Expects("hello")
|
|
||||||
if p.On(a.StrNoCase("hello")).Skip() {
|
if p.On(a.StrNoCase("hello")).Skip() {
|
||||||
p.Handle(h.comma)
|
p.Handle(h.comma)
|
||||||
|
} else {
|
||||||
|
p.UnexpectedInput("hello")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *helloparser1) comma(p *parsekit.ParseAPI) {
|
func (h *helloparser1) comma(p *parsekit.ParseAPI) {
|
||||||
a := parsekit.A
|
a := parsekit.A
|
||||||
p.Expects("comma")
|
|
||||||
switch {
|
switch {
|
||||||
case p.On(a.Whitespace).Skip():
|
case p.On(a.Whitespace).Skip():
|
||||||
p.Handle(h.comma)
|
p.Handle(h.comma)
|
||||||
case p.On(a.Comma).Skip():
|
case p.On(a.Comma).Skip():
|
||||||
p.Handle(h.startName)
|
p.Handle(h.startName)
|
||||||
|
default:
|
||||||
|
p.UnexpectedInput("comma")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *helloparser1) startName(p *parsekit.ParseAPI) {
|
func (h *helloparser1) startName(p *parsekit.ParseAPI) {
|
||||||
c, a := parsekit.C, parsekit.A
|
c, a := parsekit.C, parsekit.A
|
||||||
p.Expects("name")
|
|
||||||
switch {
|
switch {
|
||||||
case p.On(a.Whitespace).Skip():
|
case p.On(a.Whitespace).Skip():
|
||||||
p.Handle(h.startName)
|
p.Handle(h.startName)
|
||||||
case p.On(c.Not(a.Excl)).Stay():
|
case p.On(c.Not(a.Excl)).Stay():
|
||||||
p.Handle(h.name)
|
p.Handle(h.name)
|
||||||
|
default:
|
||||||
|
p.UnexpectedInput("name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *helloparser1) name(p *parsekit.ParseAPI) {
|
func (h *helloparser1) name(p *parsekit.ParseAPI) {
|
||||||
c, a := parsekit.C, parsekit.A
|
a := parsekit.A
|
||||||
p.Expects("name")
|
|
||||||
switch {
|
switch {
|
||||||
case p.On(c.Not(a.Excl)).Accept():
|
case p.On(a.Excl).Skip():
|
||||||
|
p.Handle(h.exclamation)
|
||||||
|
case p.On(a.AnyRune).Accept():
|
||||||
h.greetee += p.Result().String()
|
h.greetee += p.Result().String()
|
||||||
p.Handle(h.name)
|
p.Handle(h.name)
|
||||||
default:
|
default:
|
||||||
p.Handle(h.exclamation)
|
p.UnexpectedInput("name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *helloparser1) exclamation(p *parsekit.ParseAPI) {
|
func (h *helloparser1) exclamation(p *parsekit.ParseAPI) {
|
||||||
a := parsekit.A
|
a := parsekit.A
|
||||||
p.Expects("exclamation")
|
|
||||||
if p.On(a.Excl).Accept() {
|
if p.On(a.Excl).Accept() {
|
||||||
p.Handle(h.end)
|
p.Handle(h.end)
|
||||||
|
} else {
|
||||||
|
p.UnexpectedInput("exclamation")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +139,7 @@ func (h *helloparser1) exclamation(p *parsekit.ParseAPI) {
|
||||||
func (h *helloparser1) end(p *parsekit.ParseAPI) {
|
func (h *helloparser1) end(p *parsekit.ParseAPI) {
|
||||||
var a = parsekit.A
|
var a = parsekit.A
|
||||||
if !p.On(a.EndOfFile).Stay() {
|
if !p.On(a.EndOfFile).Stay() {
|
||||||
p.Expects("end of greeting")
|
p.UnexpectedInput("end of greeting")
|
||||||
p.UnexpectedInput()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,5 +61,5 @@ func createHelloTokenizer() *parsekit.Tokenizer {
|
||||||
|
|
||||||
// Create a Tokenizer that wraps the 'greeting' TokenHandler and allows
|
// Create a Tokenizer that wraps the 'greeting' TokenHandler and allows
|
||||||
// us to match some input against that handler.
|
// us to match some input against that handler.
|
||||||
return parsekit.NewTokenizer(greeting, "a friendly greeting")
|
return parsekit.NewTokenizer(greeting)
|
||||||
}
|
}
|
||||||
|
|
40
parseapi.go
40
parseapi.go
|
@ -10,7 +10,6 @@ import (
|
||||||
type ParseAPI struct {
|
type ParseAPI struct {
|
||||||
tokenAPI *TokenAPI // the input reader
|
tokenAPI *TokenAPI // the input reader
|
||||||
loopCheck map[string]bool // used for parser loop detection
|
loopCheck map[string]bool // used for parser loop detection
|
||||||
expecting string // a description of what the current state expects to find (see Expects())
|
|
||||||
result *TokenHandlerResult // Last TokenHandler result as produced by On(...).Accept()
|
result *TokenHandlerResult // Last TokenHandler result as produced by On(...).Accept()
|
||||||
err *Error // error during parsing, retrieved by Error(), further ParseAPI calls are ignored
|
err *Error // error during parsing, retrieved by Error(), further ParseAPI calls are ignored
|
||||||
stopped bool // a boolean set to true by Stop(), further ParseAPI calls are ignored
|
stopped bool // a boolean set to true by Stop(), further ParseAPI calls are ignored
|
||||||
|
@ -145,8 +144,9 @@ func (a *ParseAPIOnAction) Accept() bool {
|
||||||
// When no match was found, then no action is taken and false is returned.
|
// When no match was found, then no action is taken and false is returned.
|
||||||
func (a *ParseAPIOnAction) Skip() bool {
|
func (a *ParseAPIOnAction) Skip() bool {
|
||||||
if a.ok {
|
if a.ok {
|
||||||
a.tokenAPI.syncCursor(a.tokenAPI.root)
|
a.parseAPI.result = nil
|
||||||
a.tokenAPI.clearResults()
|
a.tokenAPI.clearResults()
|
||||||
|
a.tokenAPI.syncCursorTo(a.tokenAPI.root)
|
||||||
a.tokenAPI.detachChilds()
|
a.tokenAPI.detachChilds()
|
||||||
a.flushReader()
|
a.flushReader()
|
||||||
}
|
}
|
||||||
|
@ -208,19 +208,6 @@ func (p *ParseAPI) panicWhenParseHandlerNil(parseHandler ParseHandler) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expects is used to let a ParseHandler function describe what input it is
|
|
||||||
// expecting. This expectation is used in error messages to provide some
|
|
||||||
// context to them.
|
|
||||||
//
|
|
||||||
// When defining an expectation inside a ParseHandler, you do not need to
|
|
||||||
// handle unexpected input yourself. When the end of the parser is reached
|
|
||||||
// without stopping it using ParseAPI.Stop() or ParseAPI.ExpectEndOfFile(),
|
|
||||||
// an automatic error will be emitted using ParseAPI.UnexpectedInput().
|
|
||||||
func (p *ParseAPI) Expects(description string) {
|
|
||||||
p.panicWhenStoppedOrInError()
|
|
||||||
p.expecting = description
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop is used by the parser impementation to tell the ParseAPI that it has
|
// Stop is used by the parser impementation to tell the ParseAPI that it has
|
||||||
// completed the parsing process successfully.
|
// completed the parsing process successfully.
|
||||||
//
|
//
|
||||||
|
@ -259,38 +246,33 @@ func (p *ParseAPI) ExpectEndOfFile() {
|
||||||
if p.On(A.EndOfFile).Stay() {
|
if p.On(A.EndOfFile).Stay() {
|
||||||
p.Stop()
|
p.Stop()
|
||||||
} else {
|
} else {
|
||||||
p.Expects("end of file")
|
p.UnexpectedInput("end of file")
|
||||||
p.UnexpectedInput()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnexpectedInput is used to set an error that tells the user that some
|
// UnexpectedInput is used to set an error that tells the user that some
|
||||||
// unexpected input was encountered.
|
// unexpected input was encountered.
|
||||||
//
|
//
|
||||||
// It can automatically produce an error message for a couple of situations:
|
// It automatically produces an error message for a couple of situations:
|
||||||
// 1) the input simply didn't match the expectation
|
// 1) the input simply didn't match the expectation
|
||||||
// 2) the end of the input was reached
|
// 2) the end of the input was reached
|
||||||
// 3) there was an error while reading the input.
|
// 3) there was an error while reading the input.
|
||||||
//
|
func (p *ParseAPI) UnexpectedInput(expected string) {
|
||||||
// The parser implementation can provide some feedback for this error by
|
|
||||||
// calling ParseAPI.Expects() to set the expectation. When set, the
|
|
||||||
// expectation is included in the error message.
|
|
||||||
func (p *ParseAPI) UnexpectedInput() {
|
|
||||||
p.panicWhenStoppedOrInError()
|
p.panicWhenStoppedOrInError()
|
||||||
_, err := p.tokenAPI.NextRune()
|
_, err := p.tokenAPI.NextRune()
|
||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
p.Error("unexpected input%s", fmtExpects(p))
|
p.Error("unexpected input%s", fmtExpects(expected))
|
||||||
case err == io.EOF:
|
case err == io.EOF:
|
||||||
p.Error("unexpected end of file%s", fmtExpects(p))
|
p.Error("unexpected end of file%s", fmtExpects(expected))
|
||||||
default:
|
default:
|
||||||
p.Error("unexpected error '%s'%s", err, fmtExpects(p))
|
p.Error("unexpected error '%s'%s", err, fmtExpects(expected))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fmtExpects(p *ParseAPI) string {
|
func fmtExpects(expected string) string {
|
||||||
if p.expecting == "" {
|
if expected == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(" (expected %s)", p.expecting)
|
return fmt.Sprintf(" (expected %s)", expected)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,9 @@ func (p *Parser) Execute(input string) *Error {
|
||||||
if api.Handle(p.startHandler) {
|
if api.Handle(p.startHandler) {
|
||||||
// Handle returned true, indicating that parsing could still continue.
|
// Handle returned true, indicating that parsing could still continue.
|
||||||
// There was no error and that the parsing has not actively been Stop()-ed.
|
// There was no error and that the parsing has not actively been Stop()-ed.
|
||||||
// Let's try to make the best of it.
|
// Let's assume that we actually reached the end of the parsing successfully
|
||||||
if api.expecting != "" {
|
// and try to make the best of it.
|
||||||
api.UnexpectedInput()
|
api.ExpectEndOfFile()
|
||||||
} else {
|
|
||||||
api.ExpectEndOfFile()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return api.err
|
return api.err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,7 @@ func ExampleParser_usingTokens() {
|
||||||
|
|
||||||
func ExampleParseAPI_UnexpectedInput() {
|
func ExampleParseAPI_UnexpectedInput() {
|
||||||
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
|
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
|
||||||
p.Expects("a thing")
|
p.UnexpectedInput("a thing")
|
||||||
p.UnexpectedInput()
|
|
||||||
})
|
})
|
||||||
err := parser.Execute("Whatever, this parser will never be happy...")
|
err := parser.Execute("Whatever, this parser will never be happy...")
|
||||||
fmt.Println(err.Full())
|
fmt.Println(err.Full())
|
||||||
|
|
|
@ -141,7 +141,7 @@ func (i *TokenAPI) Fork() *TokenAPI {
|
||||||
parent: i,
|
parent: i,
|
||||||
}
|
}
|
||||||
child.result = newTokenHandlerResult()
|
child.result = newTokenHandlerResult()
|
||||||
i.syncCursor(child)
|
i.syncCursorTo(child)
|
||||||
i.child = child
|
i.child = child
|
||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ func (i *TokenAPI) Merge() {
|
||||||
callerPanic(1, "parsekit.TokenAPI.Merge(): Merge() called at {caller} on a non-forked TokenAPI")
|
callerPanic(1, "parsekit.TokenAPI.Merge(): Merge() called at {caller} on a non-forked TokenAPI")
|
||||||
}
|
}
|
||||||
i.addResultsToParent()
|
i.addResultsToParent()
|
||||||
i.syncCursor(i.parent)
|
i.syncCursorTo(i.parent)
|
||||||
i.clearResults()
|
i.clearResults()
|
||||||
i.detachChilds()
|
i.detachChilds()
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ func (i *TokenAPI) addResultsToParent() {
|
||||||
i.parent.result.tokens = append(i.parent.result.tokens, i.result.tokens...)
|
i.parent.result.tokens = append(i.parent.result.tokens, i.result.tokens...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *TokenAPI) syncCursor(to *TokenAPI) {
|
func (i *TokenAPI) syncCursorTo(to *TokenAPI) {
|
||||||
to.result.offset = i.result.offset
|
to.result.offset = i.result.offset
|
||||||
*to.result.cursor = *i.result.cursor
|
*to.result.cursor = *i.result.cursor
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,20 +28,20 @@ func ExampleTokenAPI_Fork() {
|
||||||
// a lot simpler. The handler from above can be replaced with:
|
// a lot simpler. The handler from above can be replaced with:
|
||||||
simpler := parsekit.A.Str("abcd")
|
simpler := parsekit.A.Str("abcd")
|
||||||
|
|
||||||
result, err := parsekit.NewTokenizer(abcdSequence, "abcd").Execute("abcdefgh")
|
result, err := parsekit.NewTokenizer(abcdSequence).Execute("abcdefgh")
|
||||||
fmt.Println(result, err)
|
fmt.Println(result, err)
|
||||||
result, err = parsekit.NewTokenizer(simpler, "abcd").Execute("abcdefgh")
|
result, err = parsekit.NewTokenizer(simpler).Execute("abcdefgh")
|
||||||
fmt.Println(result, err)
|
fmt.Println(result, err)
|
||||||
result, err = parsekit.NewTokenizer(abcdSequence, "abcd").Execute("abcx")
|
result, err = parsekit.NewTokenizer(abcdSequence).Execute("abcx")
|
||||||
fmt.Println(result, err)
|
fmt.Println(result, err)
|
||||||
result, err = parsekit.NewTokenizer(abcdSequence, "abcd").Execute("xyz")
|
result, err = parsekit.NewTokenizer(abcdSequence).Execute("xyz")
|
||||||
fmt.Println(result, err)
|
fmt.Println(result, err)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// abcd <nil>
|
// abcd <nil>
|
||||||
// abcd <nil>
|
// abcd <nil>
|
||||||
// <nil> unexpected input (expected abcd)
|
// <nil> unexpected input
|
||||||
// <nil> unexpected input (expected abcd)
|
// <nil> unexpected input
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleTokenAPI_Merge() {
|
func ExampleTokenAPI_Merge() {
|
||||||
|
@ -62,7 +62,7 @@ func ExampleTokenAPI_Merge() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
result, _ := parsekit.NewTokenizer(tokenHandler, "a match").Execute("Hi mister X!")
|
result, _ := parsekit.NewTokenizer(tokenHandler).Execute("Hi mister X!")
|
||||||
fmt.Println(result)
|
fmt.Println(result)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
|
|
|
@ -13,7 +13,7 @@ func TestWithinTokenHandler_AcceptIncludesRuneInOutput(t *testing.T) {
|
||||||
t.Accept()
|
t.Accept()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}, "test")
|
})
|
||||||
result, _ := parser.Execute("This is some random data to parse")
|
result, _ := parser.Execute("This is some random data to parse")
|
||||||
if result.String() != "This is some random " {
|
if result.String() != "This is some random " {
|
||||||
t.Fatalf("Got unexpected output from TokenHandler: %s", result.String())
|
t.Fatalf("Got unexpected output from TokenHandler: %s", result.String())
|
||||||
|
@ -33,7 +33,7 @@ func TestWithinTokenHandler_TokensCanBeEmitted(t *testing.T) {
|
||||||
Value: true,
|
Value: true,
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
}, "test")
|
})
|
||||||
result, _ := parser.Execute("doesn't matter")
|
result, _ := parser.Execute("doesn't matter")
|
||||||
if len(result.Tokens()) != 2 {
|
if len(result.Tokens()) != 2 {
|
||||||
t.Fatalf("Wrong number of tokens in result, expected 2, got %d", len(result.Tokens()))
|
t.Fatalf("Wrong number of tokens in result, expected 2, got %d", len(result.Tokens()))
|
||||||
|
@ -61,7 +61,7 @@ func TestWithinTokenHandler_TokensCanBeEmitted(t *testing.T) {
|
||||||
func TestUsingTokenParserCombinators_TokensCanBeEmitted(t *testing.T) {
|
func TestUsingTokenParserCombinators_TokensCanBeEmitted(t *testing.T) {
|
||||||
var tok, c, a = parsekit.T, parsekit.C, parsekit.A
|
var tok, c, a = parsekit.T, parsekit.C, parsekit.A
|
||||||
fooToken := tok.Str("ASCII", c.OneOrMore(a.ASCII))
|
fooToken := tok.Str("ASCII", c.OneOrMore(a.ASCII))
|
||||||
parser := parsekit.NewTokenizer(fooToken, "something")
|
parser := parsekit.NewTokenizer(fooToken)
|
||||||
input := "This is fine ASCII Åltho hère öt endĩt!"
|
input := "This is fine ASCII Åltho hère öt endĩt!"
|
||||||
result, err := parser.Execute(input)
|
result, err := parser.Execute(input)
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ func TestUsingTokenParserCombinators_TokensCanBeNested(t *testing.T) {
|
||||||
)),
|
)),
|
||||||
m.Drop(c.ZeroOrMore(a.Asterisk)),
|
m.Drop(c.ZeroOrMore(a.Asterisk)),
|
||||||
)
|
)
|
||||||
parser := parsekit.NewTokenizer(fooToken, "something")
|
parser := parsekit.NewTokenizer(fooToken)
|
||||||
input := "*** This is fine ASCII Åltho hère öt endĩt! ***"
|
input := "*** This is fine ASCII Åltho hère öt endĩt! ***"
|
||||||
output := "This is fine ASCIIÅltho hère öt endĩt!"
|
output := "This is fine ASCIIÅltho hère öt endĩt!"
|
||||||
result, err := parser.Execute(input)
|
result, err := parser.Execute(input)
|
||||||
|
@ -112,7 +112,7 @@ func TestGivenNextRuneNotCalled_CallToAcceptPanics(t *testing.T) {
|
||||||
parser := parsekit.NewTokenizer(func(t *parsekit.TokenAPI) bool {
|
parser := parsekit.NewTokenizer(func(t *parsekit.TokenAPI) bool {
|
||||||
t.Accept()
|
t.Accept()
|
||||||
return false
|
return false
|
||||||
}, "test")
|
})
|
||||||
parsekit.AssertPanic(t, parsekit.PanicT{
|
parsekit.AssertPanic(t, parsekit.PanicT{
|
||||||
Function: func() { parser.Execute("input string") },
|
Function: func() { parser.Execute("input string") },
|
||||||
Regexp: true,
|
Regexp: true,
|
||||||
|
@ -125,7 +125,7 @@ func TestGivenAcceptNotCalled_CallToNextRunePanics(t *testing.T) {
|
||||||
t.NextRune()
|
t.NextRune()
|
||||||
t.NextRune()
|
t.NextRune()
|
||||||
return false
|
return false
|
||||||
}, "test")
|
})
|
||||||
parsekit.AssertPanic(t, parsekit.PanicT{
|
parsekit.AssertPanic(t, parsekit.PanicT{
|
||||||
Function: func() { parser.Execute("input string") },
|
Function: func() { parser.Execute("input string") },
|
||||||
Regexp: true,
|
Regexp: true,
|
||||||
|
@ -138,7 +138,7 @@ func TestGivenNextRuneReturningNotOk_CallToAcceptPanics(t *testing.T) {
|
||||||
t.NextRune()
|
t.NextRune()
|
||||||
t.Accept()
|
t.Accept()
|
||||||
return false
|
return false
|
||||||
}, "test")
|
})
|
||||||
parsekit.AssertPanic(t, parsekit.PanicT{
|
parsekit.AssertPanic(t, parsekit.PanicT{
|
||||||
Function: func() { parser.Execute("") },
|
Function: func() { parser.Execute("") },
|
||||||
Regexp: true,
|
Regexp: true,
|
||||||
|
|
|
@ -164,6 +164,8 @@ func (r *TokenHandlerResult) Value(idx int) interface{} {
|
||||||
return r.tokens[idx].Value
|
return r.tokens[idx].Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cursor retrieves the read cursor from the TokenHandlerResult. This is the
|
||||||
|
// first cursor position after the runes that were read by the TokenHandler.
|
||||||
func (r *TokenHandlerResult) Cursor() *Cursor {
|
func (r *TokenHandlerResult) Cursor() *Cursor {
|
||||||
return r.cursor
|
return r.cursor
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,7 +298,7 @@ func TestModifiers(t *testing.T) {
|
||||||
func TestTokenMakerErrorHandling(t *testing.T) {
|
func TestTokenMakerErrorHandling(t *testing.T) {
|
||||||
var a, tok = parsekit.A, parsekit.T
|
var a, tok = parsekit.A, parsekit.T
|
||||||
invalid := tok.Boolean("BOOL", a.Str("no")) // not valid for strconv.ParseBool()
|
invalid := tok.Boolean("BOOL", a.Str("no")) // not valid for strconv.ParseBool()
|
||||||
parser := parsekit.NewTokenizer(invalid, "boolean")
|
parser := parsekit.NewTokenizer(invalid)
|
||||||
parsekit.AssertPanic(t, parsekit.PanicT{
|
parsekit.AssertPanic(t, parsekit.PanicT{
|
||||||
func() { parser.Execute("no") }, false,
|
func() { parser.Execute("no") }, false,
|
||||||
`TokenHandler error: MakeBooleanToken cannot handle input "no": strconv.ParseBool: parsing "no": ` +
|
`TokenHandler error: MakeBooleanToken cannot handle input "no": strconv.ParseBool: parsing "no": ` +
|
||||||
|
@ -380,10 +380,11 @@ func TestSequenceOfRunes(t *testing.T) {
|
||||||
input := "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
input := "#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||||
output := ""
|
output := ""
|
||||||
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
|
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
|
||||||
p.Expects("Sequence of runes")
|
|
||||||
if p.On(sequence).Accept() {
|
if p.On(sequence).Accept() {
|
||||||
output = p.Result().String()
|
output = p.Result().String()
|
||||||
p.Stop()
|
p.Stop()
|
||||||
|
} else {
|
||||||
|
p.UnexpectedInput("sequence of runes")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
err := parser.Execute(input)
|
err := parser.Execute(input)
|
||||||
|
|
|
@ -23,18 +23,14 @@ type TokenHandler func(t *TokenAPI) bool
|
||||||
// This is a simple wrapper around a TokenHandler function. It can be used to
|
// This is a simple wrapper around a TokenHandler function. It can be used to
|
||||||
// match an input string against that TokenHandler function and retrieve the
|
// match an input string against that TokenHandler function and retrieve the
|
||||||
// results in a straight forward way.
|
// results in a straight forward way.
|
||||||
//
|
func NewTokenizer(tokenHandler TokenHandler) *Tokenizer {
|
||||||
// The 'expects' parameter is used for creating an error message in case parsed
|
|
||||||
// input does not match the TokenHandler.
|
|
||||||
func NewTokenizer(tokenHandler TokenHandler, expects string) *Tokenizer {
|
|
||||||
tokenizer := &Tokenizer{}
|
tokenizer := &Tokenizer{}
|
||||||
tokenizer.parser = NewParser(func(p *ParseAPI) {
|
tokenizer.parser = NewParser(func(p *ParseAPI) {
|
||||||
if p.On(tokenHandler).Accept() {
|
if p.On(tokenHandler).Accept() {
|
||||||
tokenizer.result = p.Result()
|
tokenizer.result = p.Result()
|
||||||
p.Stop()
|
p.Stop()
|
||||||
} else {
|
} else {
|
||||||
p.Expects(expects)
|
p.UnexpectedInput("")
|
||||||
p.UnexpectedInput()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return tokenizer
|
return tokenizer
|
||||||
|
|
|
@ -24,7 +24,7 @@ func ExampleTokenizer_Execute() {
|
||||||
ip := T.Str("ip", A.IPv4)
|
ip := T.Str("ip", A.IPv4)
|
||||||
mask := T.Int8("mask", A.IPv4CIDRMask)
|
mask := T.Int8("mask", A.IPv4CIDRMask)
|
||||||
cidr := C.Seq(ip, A.Slash, mask)
|
cidr := C.Seq(ip, A.Slash, mask)
|
||||||
tokenizer := NewTokenizer(cidr, "cidr")
|
tokenizer := NewTokenizer(cidr)
|
||||||
|
|
||||||
for _, input := range []string{
|
for _, input := range []string{
|
||||||
"000.000.000.000/000",
|
"000.000.000.000/000",
|
||||||
|
@ -46,8 +46,8 @@ func ExampleTokenizer_Execute() {
|
||||||
// Result: ip("0.0.0.0", value = (string)0.0.0.0) mask("0", value = (int8)0)
|
// Result: ip("0.0.0.0", value = (string)0.0.0.0) mask("0", value = (int8)0)
|
||||||
// Result: ip("192.168.0.1", value = (string)192.168.0.1) mask("24", value = (int8)24)
|
// Result: ip("192.168.0.1", value = (string)192.168.0.1) mask("24", value = (int8)24)
|
||||||
// Result: ip("255.255.255.255", value = (string)255.255.255.255) mask("32", value = (int8)32)
|
// Result: ip("255.255.255.255", value = (string)255.255.255.255) mask("32", value = (int8)32)
|
||||||
// Error: unexpected input (expected cidr)
|
// Error: unexpected input
|
||||||
// Error: unexpected input (expected cidr)
|
// Error: unexpected input
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCallingNextRune_ReturnsNextRune(t *testing.T) {
|
func TestCallingNextRune_ReturnsNextRune(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue