// In this example, a parser is created that is able to parse input that looks // like "Hello, !", and that extracts the name from it. // // This implementation uses a state-based Parser for it, and it does not implement // any custom combinator/parser Matcher functions. Note that things are much easier to // implement using custom Matchers (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 application. package parsekit_test import ( "fmt" "strings" "git.makaay.nl/mauricem/go-parsekit" ) const greeteeItem parsekit.ItemType = 1 func stateStartOfGreeting(p *parsekit.P) { c := parsekit.C p.Expects("hello") if p.On(c.StrNoCase("hello")).Skip() { p.RouteTo(stateComma) } } func stateComma(p *parsekit.P) { 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.P) { 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.P) { 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_helloWorldUsingParser() { 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 }