More documentation and examples.
This commit is contained in:
parent
1a280233b0
commit
cdfc4ce52c
|
@ -57,8 +57,8 @@ func Example_basicCalculator1() {
|
|||
// An error is returned in case the calculation failed.
|
||||
func ComputeSimple(calculation string) (int64, error) {
|
||||
calculator := &simpleCalculator{op: +1}
|
||||
parser := parse.New(calculator.number)
|
||||
err := parser(calculation)
|
||||
parseCalculation := parse.New(calculator.number)
|
||||
err := parseCalculation(calculation)
|
||||
return calculator.Result, err
|
||||
}
|
||||
|
||||
|
|
|
@ -78,8 +78,8 @@ type calculator struct {
|
|||
// calculation fails for some reason.
|
||||
func Compute(input string) (float64, error) {
|
||||
calc := &calculator{}
|
||||
parser := parse.New(calc.calculation)
|
||||
err := parser(input)
|
||||
parseCalculation := parse.New(calc.calculation)
|
||||
err := parseCalculation(input)
|
||||
return calc.result, err
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
//
|
||||
// One big difference between the parser/combinator-based example and this one,
|
||||
// is that this parser reports errors much more fine-grained. This might or
|
||||
// might not be useful for your specific use case. If you need error reporting
|
||||
// might not be useful for your specific use case. If you need error reporting
|
||||
// like this, then also take a look at the helloSingleState example, which does
|
||||
// the same thing as this version, only more concise.
|
||||
|
||||
|
@ -76,8 +76,8 @@ type helloparser1 struct {
|
|||
}
|
||||
|
||||
func (h *helloparser1) Parse(input string) (string, error) {
|
||||
parser := parse.New(h.start)
|
||||
err := parser(input)
|
||||
parseHello := parse.New(h.start)
|
||||
err := parseHello(input)
|
||||
return h.greetee, err
|
||||
}
|
||||
|
||||
|
@ -92,12 +92,10 @@ func (h *helloparser1) start(p *parse.API) {
|
|||
|
||||
func (h *helloparser1) comma(p *parse.API) {
|
||||
a := tokenize.A
|
||||
switch {
|
||||
case p.Accept(a.Blanks):
|
||||
p.Handle(h.comma)
|
||||
case p.Accept(a.Comma):
|
||||
p.Accept(a.Blanks)
|
||||
if p.Accept(a.Comma) {
|
||||
p.Handle(h.startName)
|
||||
default:
|
||||
} else {
|
||||
p.Expected("comma")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ type helloparser2 struct {
|
|||
}
|
||||
|
||||
func (h *helloparser2) Parse(input string) (string, error) {
|
||||
parser := parse.New(h.start)
|
||||
err := parser(input)
|
||||
parseHello := parse.New(h.start)
|
||||
err := parseHello(input)
|
||||
return h.greetee, err
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Here, we create a custom type 'Chunks', which is an alias
|
||||
// for []string. We add a Handler method directly to that type
|
||||
// and let the parsing code fill the slice with strings during parsing.
|
||||
// and let the parsing code append items to the slice during parsing.
|
||||
|
||||
package examples
|
||||
|
||||
|
@ -20,12 +20,12 @@ func (l *Chunks) AddChopped(s string, chunkSize int) error {
|
|||
c, a := tokenize.C, tokenize.A
|
||||
chunkOfRunes := c.MinMax(1, chunkSize, a.AnyRune)
|
||||
|
||||
parser := parse.New(func(p *parse.API) {
|
||||
parseChunks := parse.New(func(p *parse.API) {
|
||||
for p.Accept(chunkOfRunes) {
|
||||
*l = append(*l, p.Result().String())
|
||||
}
|
||||
})
|
||||
return parser(s)
|
||||
return parseChunks(s)
|
||||
}
|
||||
|
||||
func Example_usingSliceAsParserState() {
|
||||
|
|
10
parse/api.go
10
parse/api.go
|
@ -65,7 +65,7 @@ func (p *API) invokeHandler(name string, tokenHandler tokenize.Handler) (*tokeni
|
|||
p.panicWhenStoppedOrInError(name)
|
||||
p.checkForLoops()
|
||||
if tokenHandler == nil {
|
||||
callerPanic(2, "parse.API.%s(): %s() called with nil tokenHandler argument at {caller}", name, name)
|
||||
callerPanic(2, "parsekit.parse.API.%s(): %s() called with nil tokenHandler argument at {caller}", name, name)
|
||||
}
|
||||
|
||||
p.result = nil
|
||||
|
@ -93,7 +93,7 @@ func (p *API) panicWhenStoppedOrInError(name string) {
|
|||
after = "Stop()"
|
||||
}
|
||||
|
||||
callerPanic(2, "parse.API.%s(): Illegal call to %s() at {caller}: "+
|
||||
callerPanic(2, "parsekit.parse.API.%s(): Illegal call to %s() at {caller}: "+
|
||||
"no calls allowed after API.%s", name, name, after)
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ func (p *API) initLoopCheck() {
|
|||
func (p *API) checkForLoops() {
|
||||
filepos := callerFilepos(3)
|
||||
if _, ok := p.loopCheck[filepos]; ok {
|
||||
callerPanic(3, "parse.API: Loop detected in parser at {caller}")
|
||||
callerPanic(3, "parsekit.parse.API: Loop detected in parser at {caller}")
|
||||
}
|
||||
p.loopCheck[filepos] = true
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ func (p *API) checkForLoops() {
|
|||
func (p *API) Result() *tokenize.Result {
|
||||
result := p.result
|
||||
if p.result == nil {
|
||||
callerPanic(1, "parse.API.Result(): Result() called "+
|
||||
callerPanic(1, "parsekit.parse.API.Result(): Result() called "+
|
||||
"at {caller} without calling API.Peek() or API.Accept() on beforehand")
|
||||
}
|
||||
return result
|
||||
|
@ -154,7 +154,7 @@ func (p *API) Handle(parseHandler Handler) bool {
|
|||
|
||||
func (p *API) panicWhenHandlerNil(parseHandler Handler) {
|
||||
if parseHandler == nil {
|
||||
callerPanic(2, "parse.API.Handle(): Handle() called with nil input at {caller}")
|
||||
callerPanic(2, "parsekit.parse.API.Handle(): Handle() called with nil input at {caller}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ func TestGivenNullHandler_HandlePanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { parser("") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API\.Handle\(\): Handle\(\) called with nil input ` +
|
||||
Expect: `parsekit\.parse\.API\.Handle\(\): Handle\(\) called with nil input ` +
|
||||
`at /.*/parse_test\.go:\d+`})
|
||||
}
|
||||
func TestGivenNilHandler_AcceptPanics(t *testing.T) {
|
||||
|
@ -210,7 +210,7 @@ func TestGivenNilHandler_AcceptPanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { p("") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API\.Accept\(\): Accept\(\) called with nil ` +
|
||||
Expect: `parsekit\.parse\.API\.Accept\(\): Accept\(\) called with nil ` +
|
||||
`tokenHandler argument at /.*/parse_test\.go:\d+`})
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ func TestGivenNilHandler_PeekPanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { p("") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API\.Peek\(\): Peek\(\) called with nil ` +
|
||||
Expect: `parsekit\.parse\.API\.Peek\(\): Peek\(\) called with nil ` +
|
||||
`tokenHandler argument at /.*/parse_test\.go:\d+`})
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ func TestGivenStoppedParser_HandlePanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { p("") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API\.Handle\(\): Illegal call to Handle\(\) ` +
|
||||
Expect: `parsekit\.parse\.API\.Handle\(\): Illegal call to Handle\(\) ` +
|
||||
`at /.*/parse_test\.go:\d+: no calls allowed after API\.Stop\(\)`})
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ func TestGivenParserWithErrorSet_HandlePanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { p("") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API\.Handle\(\): Illegal call to Handle\(\) ` +
|
||||
Expect: `parsekit\.parse\.API\.Handle\(\): Illegal call to Handle\(\) ` +
|
||||
`at /.*/parse_test\.go:\d+: no calls allowed after API\.Error\(\)`})
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ func TestGivenParserWithoutCallToPeekOrAccept_ResultPanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { p("") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API\.Result\(\): Result\(\) called at ` +
|
||||
Expect: `parsekit\.parse\.API\.Result\(\): Result\(\) called at ` +
|
||||
`/.*/parse_test.go:\d+ without calling API.Peek\(\) or API.Accept\(\) on beforehand`})
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ func TestGivenLoopingParserDefinition_ParserPanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { parser("Het houdt niet op, niet vanzelf") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API: Loop detected in parser at /.*/parse_test.go:\d+`})
|
||||
Expect: `parsekit\.parse\.API: Loop detected in parser at /.*/parse_test.go:\d+`})
|
||||
}
|
||||
|
||||
// This test incorporates an actual loop bug that I dropped on myself and
|
||||
|
@ -333,5 +333,5 @@ func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) {
|
|||
parse.AssertPanic(t, parse.PanicT{
|
||||
Function: func() { parser("This will end soon") },
|
||||
Regexp: true,
|
||||
Expect: `parse\.API: Loop detected in parser at .*/parse_test.go:\d+`})
|
||||
Expect: `parsekit\.parse\.API: Loop detected in parser at .*/parse_test.go:\d+`})
|
||||
}
|
||||
|
|
|
@ -6,6 +6,102 @@ import (
|
|||
"git.makaay.nl/mauricem/go-parsekit/tokenize"
|
||||
)
|
||||
|
||||
func ExampleNewAPI() {
|
||||
tokenize.NewAPI("The input that the API will handle")
|
||||
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleAPI_NextRune() {
|
||||
api := tokenize.NewAPI("The input that the API will handle")
|
||||
r, err := api.NextRune()
|
||||
|
||||
fmt.Printf("Rune read from input; %c\n", r)
|
||||
fmt.Printf("The error: %v\n", err)
|
||||
fmt.Printf("API results: %q\n", api.Result().String())
|
||||
|
||||
// Output:
|
||||
// Rune read from input; T
|
||||
// The error: <nil>
|
||||
// API results: ""
|
||||
}
|
||||
|
||||
func ExampleAPI_Accept() {
|
||||
api := tokenize.NewAPI("The input that the API will handle")
|
||||
api.NextRune() // reads 'T'
|
||||
api.Accept() // adds 'T' to the API results
|
||||
api.NextRune() // reads 'h'
|
||||
api.Accept() // adds 'h' to the API results
|
||||
api.NextRune() // reads 'e', but it is not added to the API results
|
||||
|
||||
fmt.Printf("API results: %q\n", api.Result().String())
|
||||
|
||||
// Output:
|
||||
// API results: "Th"
|
||||
}
|
||||
|
||||
func ExampleAPI_Result() {
|
||||
api := tokenize.NewAPI("")
|
||||
|
||||
result := api.Result()
|
||||
|
||||
result.AddRunes("Some runes")
|
||||
result.AddRunes([]rune{' ', 'a', 'd', 'd', 'e', 'd'})
|
||||
result.AddRunes(' ', 'i', 'n', ' ', "various ways")
|
||||
fmt.Printf("API result first 10 runes: %q\n", api.Result().Runes()[0:10])
|
||||
fmt.Printf("API result runes as string: %q\n", api.Result().String())
|
||||
|
||||
result.SetRunes("new ", "set ", "of ", 'r', 'u', 'n', 'e', 's')
|
||||
fmt.Printf("API result runes as string: %q\n", api.Result().String())
|
||||
fmt.Printf("API result runes: %q\n", api.Result().Runes())
|
||||
fmt.Printf("API third rune: %q\n", api.Result().Rune(2))
|
||||
|
||||
result.AddTokens(&tokenize.Token{
|
||||
Runes: []rune("demo 1"),
|
||||
Type: 42,
|
||||
Value: "towel"})
|
||||
result.AddTokens(&tokenize.Token{
|
||||
Runes: []rune("demo 2"),
|
||||
Type: 73,
|
||||
Value: "Zaphod"})
|
||||
fmt.Printf("API result tokens: %v\n", api.Result().Tokens())
|
||||
fmt.Printf("API second result token: %v\n", api.Result().Token(1))
|
||||
|
||||
// Output:
|
||||
// API result first 10 runes: ['S' 'o' 'm' 'e' ' ' 'r' 'u' 'n' 'e' 's']
|
||||
// API result runes as string: "Some runes added in various ways"
|
||||
// API result runes as string: "new set of runes"
|
||||
// API result runes: ['n' 'e' 'w' ' ' 's' 'e' 't' ' ' 'o' 'f' ' ' 'r' 'u' 'n' 'e' 's']
|
||||
// API third rune: 'w'
|
||||
// API result tokens: [42("demo 1", value = (string)towel) 73("demo 2", value = (string)Zaphod)]
|
||||
// API second result token: 73("demo 2", value = (string)Zaphod)
|
||||
}
|
||||
|
||||
func ExampleAPI_Reset() {
|
||||
api := tokenize.NewAPI("Very important input!")
|
||||
|
||||
api.NextRune()
|
||||
api.Accept()
|
||||
api.NextRune()
|
||||
api.Accept()
|
||||
fmt.Printf("API results: %q at %s\n", api.Result().String(), api.Result().Cursor())
|
||||
|
||||
// Reset clears the results, but keeps the cursor position.
|
||||
api.Reset()
|
||||
fmt.Printf("API results: %q at %s\n", api.Result().String(), api.Result().Cursor())
|
||||
|
||||
api.NextRune()
|
||||
api.Accept()
|
||||
api.NextRune()
|
||||
api.Accept()
|
||||
fmt.Printf("API results: %q at %s\n", api.Result().String(), api.Result().Cursor())
|
||||
|
||||
// Output:
|
||||
// API results: "Ve" at line 1, column 3
|
||||
// API results: "" at line 1, column 3
|
||||
// API results: "ry" at line 1, column 5
|
||||
}
|
||||
|
||||
func ExampleAPI_Fork() {
|
||||
// This custom Handler checks for input 'a', 'b' or 'c'.
|
||||
abcHandler := func(t *tokenize.API) bool {
|
||||
|
@ -44,6 +140,26 @@ func ExampleAPI_Fork() {
|
|||
// <nil> mismatch at start of file
|
||||
}
|
||||
|
||||
func ExampleAPI_Dispose() {
|
||||
api := tokenize.NewAPI("My uninspired piece of input")
|
||||
|
||||
child := api.Fork()
|
||||
// ... do stuff with child ...
|
||||
child.NextRune()
|
||||
child.Accept()
|
||||
child.NextRune()
|
||||
child.Accept()
|
||||
// ... dispose of the child results ...
|
||||
child.Dispose()
|
||||
|
||||
// The parent still reads from the start of the input.
|
||||
r, _ := api.NextRune()
|
||||
fmt.Printf("Rune read from parent: %c\n", r)
|
||||
|
||||
// Output:
|
||||
// Rune read from parent: M
|
||||
}
|
||||
|
||||
func ExampleAPI_Merge() {
|
||||
tokenHandler := func(t *tokenize.API) bool {
|
||||
child1 := t.Fork()
|
||||
|
|
|
@ -68,9 +68,9 @@ func (r *Result) ClearRunes() {
|
|||
}
|
||||
|
||||
// SetRunes replaces the Runes from the Result with the provided input.
|
||||
func (r *Result) SetRunes(s interface{}) {
|
||||
func (r *Result) SetRunes(s ...interface{}) {
|
||||
r.ClearRunes()
|
||||
r.addRunes(s)
|
||||
r.addRunes(s...)
|
||||
}
|
||||
|
||||
// AddRunes is used to add runes to the Result.
|
||||
|
@ -114,7 +114,7 @@ func (r *Result) ClearTokens() {
|
|||
}
|
||||
|
||||
// SetTokens replaces the Tokens from the Result with the provided tokens.
|
||||
func (r *Result) SetTokens(tokens []*Token) {
|
||||
func (r *Result) SetTokens(tokens ...*Token) {
|
||||
r.ClearTokens()
|
||||
for _, t := range tokens {
|
||||
r.AddTokens(t)
|
||||
|
|
Loading…
Reference in New Issue