pars

package module
v1.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 13, 2019 License: BSD-2-Clause Imports: 9 Imported by: 0

README

GoDoc Go Report Card

pars - Simple parser combinators for Go

For documentation please read the godoc.

Documentation

Overview

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseFromReader

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

ParseFromReader parses from an io.Reader.

func ParseString

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

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

Types

type Clause added in v1.3.0

type Clause []Parser

Clause is the most simple DispatchClause. It is just a slice of parsers without any transformations.

func (Clause) Parsers added in v1.3.0

func (c Clause) Parsers() []Parser

Parsers returns the parser slice for this clause.

func (Clause) TransformError added in v1.3.0

func (c Clause) TransformError(err error) error

TransformError returns the given error unchanged.

func (Clause) TransformResult added in v1.3.0

func (c Clause) TransformResult(val []interface{}) interface{}

TransformResult returns the only value if the slice of values has only one element. Otherwise it returns the slice of values unchanged.

type DescribeClause added in v1.3.0

type DescribeClause struct {
	DispatchClause
	Description string
}

DescribeClause extends the error message of a clause so that a custom description is part of the message.

func (DescribeClause) TransformError added in v1.3.0

func (d DescribeClause) TransformError(err error) error

TransformError extends the error message of a clause so that a custom description is part of the message.

type DispatchClause added in v1.3.0

type DispatchClause interface {
	//Parsers returns the parsers of the clause.
	Parsers() []Parser
	//TransformResult allows the DispatchClause to combine the results of its parsers to a single result.
	TransformResult([]interface{}) interface{}
	//TransformError allows the DispatchClause to replace or extend the error returned on a failed match.
	TransformError(error) error
}

DispatchClause is the interface of a clause used by Dispatch.

type Logger added in v1.1.0

type Logger interface {
	Println(...interface{})
}

Logger is anything that lines can be printed to.

type Parser

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 AnyByte added in v1.1.0

func AnyByte() Parser

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

func AnyRune added in v1.1.0

func AnyRune() Parser

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

func BigInt added in v1.1.0

func BigInt() Parser

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

func Byte added in v1.1.0

func Byte(b byte) Parser

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

func Char added in v1.1.0

func Char(r rune) Parser

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

func CharPred added in v1.1.0

func CharPred(pred func(rune) bool) Parser

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

func DelimitedString added in v1.1.0

func DelimitedString(beginDelimiter, endDelimiter string) Parser

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

func DiscardLeft added in v1.1.0

func DiscardLeft(left, right Parser) Parser

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

Example
data := "$123"

dollarParser := DiscardLeft(Char('$'), Int())

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 DiscardRight added in v1.1.0

func DiscardRight(left, right Parser) Parser

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

func Dispatch added in v1.3.0

func Dispatch(clauses ...DispatchClause) Parser

Dispatch returns a parser that is like a combination of Seq and Or with limited backtracking.

A Dispatch contains multiple clauses consisting of parsers. Dispatch parses by trying the clauses one by one. The first matching clause is used, later clauses are not tried. Each clause can contain multiple parsers. Clauses are special because they limit the backtracking: If the first parser of a clause matches, that clause is selected even if a later parser of that clause fails. If no clause matches, the error from the last clause is returned.

The motivation for limited backtracking is in better error reporting. When an Or parser fails, all you know is that not a single parser succeeded. When a Dispatch parser fails after a clause was selected, you know which subclause was supposed to be parsed and can return a fitting error message.

func Error added in v1.1.0

func Error(err error) Parser

Error returns a parser that always fails with the given error

func ErrorTransformer added in v1.2.0

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

ErrorTransformer wraps a parser so that an error result is transformed according to the given function. If the wrapped parser was successful, the result is not changed.

func Except added in v1.1.0

func Except(parser, except Parser) Parser

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

func Float added in v1.1.0

func Float() Parser

Float 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 Int added in v1.1.0

func Int() Parser

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

func JoinString added in v1.3.0

func JoinString(parser Parser) Parser

JoinString wraps a parser that returns a slice of runes or strings so that it returns a single string instead. Runes and strings can be mixed in the same slice. The slice also can contain other slices of runes and strings, recursively. The returned parser WILL PANIC if the wrapped parser returns something that is not a slice of runes or strings!

func Many added in v1.1.0

func Many(parser Parser) Parser

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

func NewAnyByte deprecated

func NewAnyByte() Parser

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

Deprecated: Use AnyByte instead.

func NewAnyRune deprecated

func NewAnyRune() Parser

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

Deprecated: Use AnyRune instead.

func NewBigInt deprecated

func NewBigInt() Parser

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

Deprecated: Use BigInt instead.

func NewByte deprecated

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.

Deprecated: Use Byte instead.

func NewChar deprecated

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.

Deprecated: Use Char instead.

func NewCharPred deprecated

func NewCharPred(pred func(rune) bool) Parser

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

Deprecated: Use CharPred instead.

func NewDelimitedString deprecated

func NewDelimitedString(beginDelimiter, endDelimiter string) Parser

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

Deprecated: Use DelimitedString instead.

func NewDiscardLeft deprecated

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.

Deprecated: Use DiscardLeft instead.

func NewDiscardRight deprecated

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.

Deprecated: Use DiscardRight instead.

func NewError deprecated

func NewError(err error) Parser

NewError returns a parser that always fails with the given error

Deprecated: Use Error instead.

func NewExcept deprecated

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.

Deprecated: Use Except instead.

func NewFloat deprecated

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.

Deprecated: Use Float instead.

func NewInt deprecated

func NewInt() Parser

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

Deprecated: Use Int instead.

func NewLogger deprecated

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

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

Deprecated: Use WithLogging instead.

func NewMany deprecated

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.

Deprecated: Use Many instead.

func NewOptional deprecated

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.

Deprecated: Use Optional instead.

func NewOr deprecated

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.

Deprecated: Use Or instead.

func NewRecursive deprecated

func NewRecursive(factory func() Parser) Parser

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

Deprecated: Use Recursive instead.

func NewRunesToString deprecated

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!

Deprecated: Use JoinString instead.

func NewRunesUntil deprecated

func NewRunesUntil(endCondition Parser) Parser

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

Deprecated: Use RunesUntil instead.

func NewSep deprecated

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.

Deprecated: Use Sep instead.

func NewSeq deprecated

func NewSeq(parsers ...Parser) Parser

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

Deprecated: Use Seq instead.

func NewSome deprecated

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.

Deprecated: Use Some instead.

func NewSplicingSeq deprecated

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.

Deprecated: Use SplicingSeq instead.

func NewStdLogger deprecated

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.

Deprecated: Use WithStdLogging instead.

func NewString deprecated

func NewString(expected string) Parser

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

Deprecated: Use String instead.

func NewStringCI deprecated

func NewStringCI(expected string) Parser

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

Deprecated: Use StringCI instead.

func NewSwallowLeadingWhitespace deprecated

func NewSwallowLeadingWhitespace(parser Parser) Parser

NewSwallowLeadingWhitespace wraps a parser so that it removes leading whitespace.

Deprecated: Use SwallowLeadingWhitespace instead.

func NewSwallowTrailingWhitespace deprecated

func NewSwallowTrailingWhitespace(parser Parser) Parser

NewSwallowTrailingWhitespace wraps a parser so that it removes trailing whitespace.

Deprecated: Use SwallowTrailingWhitespace instead.

func NewSwallowWhitespace deprecated

func NewSwallowWhitespace(parser Parser) Parser

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

Deprecated: Use SwallowWhitespace instead.

func NewTransformer deprecated

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.

Deprecated: Use Transformer instead.

func Optional added in v1.1.0

func Optional(parser Parser) Parser

Optional 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 Or added in v1.1.0

func Or(parsers ...Parser) Parser

Or 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.

Example
data := "124"

parser := Or(String("123"), String("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 Recursive added in v1.1.0

func Recursive(factory func() Parser) Parser

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

func RunesToString deprecated added in v1.1.0

func RunesToString(parser Parser) Parser

RunesToString wraps a parser that returns a slice of runes or strings so that it returns a single string instead. Runes and strings can be mixed in the same slice. The returned parser WILL PANIC if the wrapped parser returns something that is not a slice of runes or strings!

Deprecated: Use JoinString instead.

func RunesUntil added in v1.1.0

func RunesUntil(endCondition Parser) Parser

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

func Sep added in v1.1.0

func Sep(item, separator Parser) Parser

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

func Seq added in v1.1.0

func Seq(parsers ...Parser) Parser

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

Example
data := "$123"

dollarParser := Seq(Char('$'), Int())

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 Some added in v1.1.0

func Some(parser Parser) Parser

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

func SplicingSeq added in v1.1.0

func SplicingSeq(parsers ...Parser) Parser

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

func String added in v1.1.0

func String(expected string) Parser

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

func StringCI added in v1.1.0

func StringCI(expected string) Parser

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

func SwallowLeadingWhitespace added in v1.1.0

func SwallowLeadingWhitespace(parser Parser) Parser

SwallowLeadingWhitespace wraps a parser so that it removes leading whitespace.

func SwallowTrailingWhitespace added in v1.1.0

func SwallowTrailingWhitespace(parser Parser) Parser

SwallowTrailingWhitespace wraps a parser so that it removes trailing whitespace.

func SwallowWhitespace added in v1.1.0

func SwallowWhitespace(parser Parser) Parser

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

func Transformer added in v1.1.0

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

Transformer 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.

Example
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.Seq(pars.Int(), pars.Or(pars.String("°C"), pars.String("°F")))
	//Add an conversion
	transformedParser := pars.Transformer(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())

}
Output:

Sample1: 32°C
Sample2: 40°C
Sample3: 0°C
Sample3 error: Could not find expected sequence item 1: Could not parse expected string "°F": EOF

func WithLogging added in v1.1.0

func WithLogging(parser Parser, logger Logger) Parser

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

func WithStdLogging added in v1.1.0

func WithStdLogging(parser Parser, prefix string) Parser

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

type Reader added in v1.2.0

type Reader struct {
	// contains filtered or unexported fields
}

Reader is an io.Reader that can Unread as many bytes as necessary.

func NewReader added in v1.2.0

func NewReader(r io.Reader) *Reader

NewReader creates a new Reader from an io.Reader.

func (*Reader) Read added in v1.2.0

func (br *Reader) Read(p []byte) (n int, err error)

Read reads a slice of bytes.

func (*Reader) Unread added in v1.2.0

func (br *Reader) Unread(p []byte)

Unread unreads a slice of bytes so that they will be read again by Read.

type Scanner added in v1.2.0

type Scanner struct {
	// contains filtered or unexported fields
}

Scanner provides a convenient interface to use a single parser multiple times on the same reader. Successive calls to Scan will parse the input and allow the results to be accessed one at a time. Scanner stops at the first error.

Example
data := "this is a text of words"
reader := NewReader(strings.NewReader(data))

wordParser := SwallowTrailingWhitespace(JoinString(RunesUntil(CharPred(unicode.IsSpace))))

scanner := NewScanner(reader, wordParser)

for scanner.Scan() {
	fmt.Println(scanner.ResultString())
}
fmt.Println(scanner.Err())
Output:

this
is
a
text
of
words
<nil>

func NewScanner added in v1.2.0

func NewScanner(r *Reader, p Parser) Scanner

NewScanner returns a new scanner using a given Reader and Parser.

func (Scanner) Err added in v1.2.0

func (s Scanner) Err() error

Err returns the last encountered error that is not io.EOF. It returns nil otherwise.

func (Scanner) Result added in v1.2.0

func (s Scanner) Result() interface{}

Result returns the most recently parsed value from a call to Scan.

func (Scanner) ResultString added in v1.2.0

func (s Scanner) ResultString() string

ResultString returns the most recently parsed value from a call to Scan, cast to a String. This will panic if the last result is not a string!

func (*Scanner) Scan added in v1.2.0

func (s *Scanner) Scan() bool

Scan invokes the parser on the reader and makes the results available via Result and Err. Scan returns true if the parsing succeeded and returns false otherwise.

type StringJoiningClause added in v1.3.0

type StringJoiningClause struct {
	DispatchClause
}

StringJoiningClause extends a clause that consists of parsers that return runes or strings so that it returnes a single string instead. Slices are handled recursively. StringJoiningClause WILL PANIC if any of the parsers return something other than a rune or a string or a slice of these types.

func (StringJoiningClause) TransformResult added in v1.3.0

func (s StringJoiningClause) TransformResult(vals []interface{}) interface{}

TransformResult joins runes and strings together like JoinString.

Directories

Path Synopsis
examples
pars-calc
pars-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.
pars-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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL