pars: bitbucket.org/Ragnara/pars Index | Examples | Files | Directories

package pars

import "bitbucket.org/Ragnara/pars"

Package pars is a simple framework for parser combinators. It is designed to be easy to use, yet powerful enough to allow solving real world problems. Parsers can be arranged into flexible stacks of more elemental parsers. Parser results can be transformed via transformers to easily convert their results into a more fitting format or to implement additional conditions that must be fulfilled for a successful parse. Complex parsers can be debugged by wrapping them with a logger. pars parsers can read from a string or from an io.Reader, so streaming parsing is possible if you need it.

Index

Examples

Package Files

buffer.go combinators.go errors.go fundamental_parsers.go pars.go pkg.go reader.go utilities.go

func ParseFromReader Uses

func ParseFromReader(ior io.Reader, p Parser) (interface{}, error)

ParseFromReader parses from an io.Reader.

func ParseString Uses

func ParseString(s string, p Parser) (interface{}, error)

ParseString is a helper function to directly use a parser on a string.

type Parser Uses

type Parser interface {
    //Parse is used for the actual parsing. It reads from the reader and returns the result or an error value.
    //Each parser must remember enough from the call to this method to undo the reading in case of a parsing error that occurs later.
    //When Parse returns with an error, Parse must make sure that all read bytes are unread so that another parser could try to parse them.
    Parse(*reader) (interface{}, error)
    //Unread puts read bytes back to the reader so that they can be read again by other parsers.
    Unread(*reader)
    //Clone creates a parser that works the same as the receiver. This allows to create a single parser as a blueprint for other parsers.
    //Internal state from reading operations should not be cloned.
    Clone() Parser
}

Parser contains the methods that each parser in this framework has to provide.

var EOF Parser = eof{}

EOF is a parser that never yields a value but that succeeds if and only if the source reached EOF

func NewAnyByte Uses

func NewAnyByte() Parser

NewAnyByte returns a parser that reads exactly one byte from the source.

func NewAnyRune Uses

func NewAnyRune() Parser

NewAnyRune returns a parser that parses a single valid rune. If no such rune can be read, ErrRuneExpected is returned.

func NewBigInt Uses

func NewBigInt() Parser

NewBigInt returns a parser that parses an integer. The parsed integer is returned as a math/big.Int.

func NewByte Uses

func NewByte(b byte) Parser

NewByte returns a parser used to read a single known byte. A different byte is treated as a parsing error.

func NewChar Uses

func NewChar(r rune) Parser

NewChar returns a parser used to read a single known rune. A different rune is treated as a parsing error.

func NewCharPred Uses

func NewCharPred(pred func(rune) bool) Parser

NewCharPred returns a parser that parses a single rune as long as it fulfills the given predicate.

func NewDelimitedString Uses

func NewDelimitedString(beginDelimiter, endDelimiter string) Parser

NewDelimitedString returns a parser that parses a string between two given delimiter strings and returns the value between.

func NewDiscardLeft Uses

func NewDiscardLeft(left, right Parser) Parser

NewDiscardLeft returns a parser that calls two other parsers but only returns the result of the second parser. Both parsers must succeed.

Code:

data := "$123"

dollarParser := NewDiscardLeft(NewChar('$'), NewInt())

result, err := ParseString(data, dollarParser)
if err != nil {
    fmt.Println("Error while parsing:", err)
    return
}

fmt.Printf("%v: %T\n", result, result)

Output:

123: int

func NewDiscardRight Uses

func NewDiscardRight(left, right Parser) Parser

NewDiscardRight returns a parser that calls two other parsers but only returns the result of the first parser. Both parsers must succeed.

func NewError Uses

func NewError(err error) Parser

NewError returns a parser that always fails with the given error

func NewExcept Uses

func NewExcept(parser, except Parser) Parser

NewExcept returns a parser that wraps another parser so that it fails if a third, excepted parser would succeed.

func NewFloat Uses

func NewFloat() Parser

NewFloat returns a parser that parses a floating point number. The supported format is an optional minus sign followed by digits optionally followed by a decimal point and more digits.

func NewInt Uses

func NewInt() Parser

NewInt returns a parser that parses an integer. The parsed integer is converted via strconv.Atoi.

func NewLogger Uses

func NewLogger(parser Parser, logger *log.Logger) Parser

NewLogger wraps a parser so that calls to it are logged to a given logger.

func NewMany Uses

func NewMany(parser Parser) Parser

NewMany returns a parser that matches a given parser one or more times. Not matching at all is an error.

func NewOptional Uses

func NewOptional(parser Parser) Parser

NewOptional returns a parser that reads exactly one result according to a given other parser. If it fails, the error is discarded and nil is returned.

func NewOr Uses

func NewOr(parsers ...Parser) Parser

NewOr returns a parser that matches the first of a given set of parsers. A later parser will not be tried if an earlier match was found. The returned parser uses the error message of the last parser verbatim.

Code:

data := "124"

parser := NewOr(NewString("123"), NewString("124"))

result, err := ParseString(data, parser)
if err != nil {
    fmt.Println("Error while parsing:", err)
    return
}

fmt.Printf("%v: %T\n", result, result)

Output:

124: string

func NewRecursive Uses

func NewRecursive(factory func() Parser) Parser

NewRecursive allows to recursively define a parser in terms of itself.

func NewRunesToString Uses

func NewRunesToString(parser Parser) Parser

NewRunesToString wraps a parser that returns a slice of runes so that it returns a string instead. The returned parser WILL PANIC if the wrapped parser returns something that is not a slice of runes!

func NewRunesUntil Uses

func NewRunesUntil(endCondition Parser) Parser

NewRunesUntil returns a parser that parses runes as long as the given endCondition parser does not match.

func NewSep Uses

func NewSep(item, separator Parser) Parser

NewSep returns a parser that parses a sequence of items according to a first parser that are separated by matches of a second parser.

func NewSeq Uses

func NewSeq(parsers ...Parser) Parser

NewSeq returns a parser that matches all of its given parsers in order or none of them.

Code:

data := "$123"

dollarParser := NewSeq(NewChar('$'), NewInt())

result, err := ParseString(data, dollarParser)
if err != nil {
    fmt.Println("Error while parsing:", err)
    return
}

values := result.([]interface{})
fmt.Printf("%c: %T\n", values[0], values[0])
fmt.Printf("%v: %T\n", values[1], values[1])

Output:

$: int32
123: int

func NewSome Uses

func NewSome(parser Parser) Parser

NewSome returns a parser that matches a given parser zero or more times. Not matching at all is not an error.

func NewSplicingSeq Uses

func NewSplicingSeq(parsers ...Parser) Parser

NewSplicingSeq returns a parser that works like a Seq but joins slices returned by its subparsers into a single slice.

func NewStdLogger Uses

func NewStdLogger(parser Parser, prefix string) Parser

NewStdLogger wraps a parser so that calls to it are logged to a logger logging to StdErr with a given prefix.

func NewString Uses

func NewString(expected string) Parser

NewString returns a parser for a single known string. Different strings are treated as a parsing error.

func NewStringCI Uses

func NewStringCI(expected string) Parser

NewStringCI returns a case-insensitive parser for a single known string. Different strings are treated as a parsing error.

func NewSwallowLeadingWhitespace Uses

func NewSwallowLeadingWhitespace(parser Parser) Parser

NewSwallowLeadingWhitespace wraps a parser so that it removes leading whitespace.

func NewSwallowTrailingWhitespace Uses

func NewSwallowTrailingWhitespace(parser Parser) Parser

NewSwallowTrailingWhitespace wraps a parser so that it removes trailing whitespace.

func NewSwallowWhitespace Uses

func NewSwallowWhitespace(parser Parser) Parser

NewSwallowWhitespace wraps a parser so that it removes leading and trailing whitespace.

func NewTransformer Uses

func NewTransformer(parser Parser, transformer func(interface{}) (interface{}, error)) Parser

NewTransformer wraps a parser so that the result is transformed according to the given function. If the transformer returns an error, the parsing is handled as failed.

Code:

package main

import (
    "bitbucket.org/ragnara/pars"
    "fmt"
)

//Celsius contains a temperature in degree celsius.
type Celsius int

func (c Celsius) String() string {
    return fmt.Sprintf("%v°C", int(c))
}

//TemperatureParser is a parser for temperature strings returning Celsius instances.
type TemperatureParser struct {
    pars.Parser
}

//NewTemperatureParser creates a new TemperatureParser instance.
func NewTemperatureParser() TemperatureParser {
    //Define the format
    simpleParser := pars.NewSeq(pars.NewInt(), pars.NewOr(pars.NewString("°C"), pars.NewString("°F")))
    //Add an conversion
    transformedParser := pars.NewTransformer(simpleParser, transformParsedTemperatureToCelsius)

    return TemperatureParser{Parser: transformedParser}
}

//Parse returns the Celsius instance for a temperature string containing an integer followed by either "°C" or "°F". Fahrenheit strings are converted to celsius.
//For other strings, an error is returned.
func (t TemperatureParser) Parse(s string) (Celsius, error) {
    val, err := pars.ParseString(s, t.Parser)
    if err != nil {
        return Celsius(0), err
    }
    return val.(Celsius), nil
}

//MustParse parses exactly like Parse but panics if an invalid string was found. It should not be used on user input!
func (t TemperatureParser) MustParse(s string) Celsius {
    val, err := t.Parse(s)
    if err != nil {
        panic(err)
    }
    return val
}

func transformParsedTemperatureToCelsius(parserResult interface{}) (interface{}, error) {
    values := parserResult.([]interface{})
    degrees := values[0].(int)
    unit := values[1].(string)

    switch unit {
    case "°C":
        return Celsius(degrees), nil
    case "°F":
        return Celsius((degrees - 32) * 5 / 9), nil
    default:
        panic("Impossible unit: " + unit)
    }
}

func main() {
    sample1 := "32°C"
    sample2 := "104°F"
    sample3 := "128K"

    fmt.Println("Sample1:", NewTemperatureParser().MustParse(sample1))
    fmt.Println("Sample2:", NewTemperatureParser().MustParse(sample2))

    val, err := NewTemperatureParser().Parse(sample3)
    fmt.Println("Sample3:", val)
    fmt.Println("Sample3 error:", err.Error())

}

Directories

PathSynopsis
examples/pars-calcpars-calc is a small cli calculator that takes floats or calculations of floats consisting of additions, substractions, multiplications or divisions on StdIn, parses them via the parser implemented in parser.go into something easily evaluable, and prints the result of the calculation.

Package pars imports 9 packages (graph). Updated 2019-01-11. Refresh now. Tools for package owners.