112 lines
3.1 KiB
Go
112 lines
3.1 KiB
Go
// In this example, a parser is created that is able to parse input that looks
|
|
// like "Hello, <name>!", and that extracts the name from it.
|
|
//
|
|
// This implementation uses a state-based Parser for it, and it does not implement
|
|
// any custom parser/combinator TokenHandler functions. Note that things are much
|
|
// easier to implement using custom TokenHandlers (see the other HelloWorldUsingMatcher
|
|
// example for this). Doing this fully parser-based implementation is mainly for your
|
|
// learning pleasure.
|
|
//
|
|
// One big difference between the Matcher-based example and this one, is that the
|
|
// state-based parser reports errors much more fine-grained. This might or might
|
|
// not be useful for your specific use case.
|
|
package parsekit_test
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.makaay.nl/mauricem/go-parsekit"
|
|
)
|
|
|
|
const greeteeItem parsekit.ItemType = 1
|
|
|
|
func stateStartOfGreeting(p *parsekit.ParseAPI) {
|
|
c := parsekit.C
|
|
p.Expects("hello")
|
|
if p.On(c.StrNoCase("hello")).Skip() {
|
|
p.RouteTo(stateComma)
|
|
}
|
|
}
|
|
|
|
func stateComma(p *parsekit.ParseAPI) {
|
|
a := parsekit.A
|
|
p.Expects("comma")
|
|
switch {
|
|
case p.On(a.Whitespace).Skip():
|
|
p.RouteRepeat()
|
|
case p.On(a.Comma).Skip():
|
|
p.RouteTo(stateName)
|
|
}
|
|
}
|
|
|
|
func stateName(p *parsekit.ParseAPI) {
|
|
a := parsekit.A
|
|
p.Expects("name")
|
|
switch {
|
|
case p.On(a.Excl).Skip():
|
|
p.RouteTo(stateEndOfGreeting)
|
|
case p.On(a.AnyRune).Accept():
|
|
p.RouteRepeat()
|
|
}
|
|
}
|
|
|
|
func stateEndOfGreeting(p *parsekit.ParseAPI) {
|
|
p.Expects("end of greeting")
|
|
if p.On(a.EndOfFile).Stay() {
|
|
name := strings.TrimSpace(p.BufLiteral())
|
|
if name == "" {
|
|
p.EmitError("The name cannot be empty")
|
|
} else {
|
|
p.Emit(greeteeItem, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createHelloParser() *parsekit.Parser {
|
|
return parsekit.NewParser(stateStartOfGreeting)
|
|
}
|
|
|
|
func Example_helloWorldUsingParser1() {
|
|
parser := createHelloParser()
|
|
|
|
for i, input := range []string{
|
|
"Hello, world!",
|
|
"HELLO ,Johnny!",
|
|
"hello , Bob123!",
|
|
"hello Pizza!",
|
|
"",
|
|
" ",
|
|
"hello",
|
|
"hello,",
|
|
"hello , ",
|
|
"hello , Droopy",
|
|
"hello , Droopy!",
|
|
"hello , \t \t Droopy \t !",
|
|
"Oh no!",
|
|
"hello,!",
|
|
} {
|
|
item, err, ok := parser.Parse(input).Next()
|
|
if !ok {
|
|
fmt.Printf("[%d] Input: %q Error: %s\n", i, input, err)
|
|
} else {
|
|
fmt.Printf("[%d] Input: %q Output: %s\n", i, input, item.Value)
|
|
}
|
|
}
|
|
// Output:
|
|
// [0] Input: "Hello, world!" Output: world
|
|
// [1] Input: "HELLO ,Johnny!" Output: Johnny
|
|
// [2] Input: "hello , Bob123!" Output: Bob123
|
|
// [3] Input: "hello Pizza!" Error: unexpected character 'P' (expected comma)
|
|
// [4] Input: "" Error: unexpected end of file (expected hello)
|
|
// [5] Input: " " Error: unexpected character ' ' (expected hello)
|
|
// [6] Input: "hello" Error: unexpected end of file (expected comma)
|
|
// [7] Input: "hello," Error: unexpected end of file (expected name)
|
|
// [8] Input: "hello , " Error: unexpected end of file (expected name)
|
|
// [9] Input: "hello , Droopy" Error: unexpected end of file (expected name)
|
|
// [10] Input: "hello , Droopy!" Output: Droopy
|
|
// [11] Input: "hello , \t \t Droopy \t !" Output: Droopy
|
|
// [12] Input: "Oh no!" Error: unexpected character 'O' (expected hello)
|
|
// [13] Input: "hello,!" Error: The name cannot be empty
|
|
}
|