Skip to content

Go

Go is the default target. The generator runs goimports on its output, and the initializer must contain a valid package declaration.

Minimal working example

Create the following two files in an empty directory. parser.go is generated by pegtool and does not need to be created manually.

identifier.peg

peg
{
package main

type ParserCustomData struct{}

func ParseIdentifier(input []byte) (string, error) {
    value, err := parse("input.txt", input)
    if err != nil {
        return "", err
    }
    return value.(string), nil
}
}

Start = value:<Identifier> !. { return value }
Identifier = [\pL_] [\pL\p{Nd}_]*

main.go

go
package main

import "fmt"

func main() {
    value, err := ParseIdentifier([]byte("name_世界"))
    if err != nil {
        panic(err)
    }
    fmt.Println(value)
}

Generate and run it:

powershell
go mod init example.com/identifier
pegtool -t go -optimize-parser -o parser.go identifier.peg
go run .

Output:

text
name_世界

Public API and custom data

The generated runtime's base symbols are the package-private parse, newParser, option, and memoized. The example wraps the internal parse in the project-specific ParseIdentifier function inside the initializer. You can similarly wrap it in an initializer or regular Go file when you need ParseFile, ParseReader, or another signature.

An empty ParserCustomData must be defined even when no state is needed. To inject data, provide a project-level wrapper:

go
func ParseWithData(filename string, input []byte, data *ParserCustomData) (any, error) {
    p := newParser(filename, input)
    p.setCustomData(data)
    return p.parse(g)
}

Actions and predicates access it through c.data. This data is not automatically restored during PEG backtracking.

Actions and errors

peg
Integer = [0-9]+ {
    value, err := strconv.Atoi(string(c.text))
    if err != nil {
        p.addErr(err)
        return nil
    }
    return value
}

A Go action returns one value rather than the old (value, error) pair. Customize user-facing no-match messages with the formatter described in Error Handling.

Memoization

Go output generated with -optimize-parser still retains named-rule memoization, so the two can be combined:

go
type Option = option

func Memoize(enabled bool) Option {
    return memoized(enabled)
}

Memoization is suitable only when a rule's result is determined consistently by its input position during one parse. Use it carefully when predicates depend on mutable ParserCustomData. See Choosing Performance Options for the complete decision process.

To share one runtime across several grammars, use the same-package Go workflow in Multiple Grammars and Entry Points.

Released under the BSD 3-Clause License