gigaparsec-0.3.0.0: Refreshed parsec-style library for compatibility with Scala parsley
LicenseBSD-3-Clause
MaintainerJamie Willis, Gigaparsec Maintainers
Stabilityexperimental
Safe HaskellSafe
LanguageHaskell2010

Text.Gigaparsec.Expr

Description

This module contains various functionality relating to the parsing of expressions.

It also includes functionality for constructing larger precedence tables, which may even vary the type of each layer in the table, allowing for strongly-typed expression parsing.

Synopsis

Infix combinators

These are standalone Infix combinators. They are useful for parsing the application of operators to values in many different configurations, including: prefix, postfix, infix (left and right associated), and mixed fixity.

Although these combinators do have their uses, they are overshadowed by the precedence combinator, which allows for the combining of multiple levels of infix-chaining in a clean and concise way.

See Text.Gigaparsec.Expr.Infix and Text.Gigaparsec.Expr.Chain for more information on chaining combinators.

Binary Operator Chains

These combinators allow for the chaining together of values and binary operators in either left-, right- or non-associative application.

infixl1 Source #

Arguments

:: (a -> b)

a function converting the value type a into the result type b.

-> Parsec a

p, the value to be parsed

-> Parsec (b -> a -> b)

op, the operator between each value.

-> Parsec b

a parser that parses alternating p and op, ending in a p, and applies their results left-associatively.

This combinator handles left-associative parsing, and the application of, zero or more binary operators between one or more values.

First parse p, then parse op followed by a p repeatedly. The results of the ps, x₁ through xₙ, are combined with the results of the ops, f₁ through fₙ₋₁, with left-associative application: fₙ₋₁ (fₙ₋₂ (..(f₁ x₁ x₂)..) xₙ₋₁) xₙ. This application is then returned as the result of the combinator. If p or op fails having consumed input at any point, the whole combinator fails.

Compared with chainl1, this combinator allows the types of the operators to more accurately encode their associativity in their types. However, chainl1, in which a and b must match, allows for more flexibility to change the associativity.

infixr1 Source #

Arguments

:: (a -> b)

a function converting the value type a into the result type b.

-> Parsec a

p, the value to be parsed

-> Parsec (a -> b -> b)

op, the operator between each value.

-> Parsec b

a parser that parses alternating p and op, ending in a p, and applies their results right-associatively.

This combinator handles right-associative parsing, and the application of, zero or more binary operators between one or more values.

First parse p, then parse op followed by a p repeatedly. The results of the ps, x₁ through xₙ, are combined with the results of the ops, f₁ through fₙ, with right-associative application: f₁ x₁ (f₂ x₂ (...(fₙ₋₁ xₙ₋₁ xₙ)...)). This application is then returned as the result of the combinator. If p or op fails having consumed input at any point, the whole combinator fails.

Compared with chainr1, this combinator allows the types of the operators to more accurately encode their associativity in their types. However, chainr1, in which a and b must match, allows for more flexibility to change the associativity.

infixn1 Source #

Arguments

:: (a -> b)

a function converting the value type a into the result type b.

-> Parsec a

p, the value to be parsed

-> Parsec (a -> a -> b)

op, the operator between each value.

-> Parsec b

a parser that parses p, op and then p, and applies the result of op to those of p in the same order.

This combinator handles non-associative parsing, and the application of, zero or one binary operators between one or two values.

First parse p. Then:

  • If this not is followed by an op, simply return p.
  • Otherwise, parse this op followed by a single p. Then ensure that this is not followed by a further op, to enforce non-associativity. The results of the ps, x and y, are combined with the result of op, f with the application f x y. This application is then returned as the result of the combinator.

If p or op fails having consumed input at any point, the whole combinator fails. This combinator also fails if the second p is followed by another op.

Unary Operator Chains

These combinators allow for the chaining together, and application, of multiple prefix or postfix unary operators to a single value.

prefix Source #

Arguments

:: (a -> b)

wrap a function converting the value type a into the result type b

-> Parsec (b -> b)

op, the prefix operator to repeatedly parse before p.

-> Parsec a

p, the single value to be parsed

-> Parsec b

a parser that parses many ops, and a final p, and applies all of the results right-associatively.

This combinator handles right-assocative parsing, and application of, zero or more prefix unary operators to a single value.

First parse many repeated ops. When there are no more ops left to parse, parse a single p. The result of p, x, is applied first to wrap, and then to each of the results of the ops, f₁ through fₙ, such that fₙ is applied first and f₁ last: f₁ (f₂ (..(fₙ (wrap x))..)). This application is then returned as the result of the combinator.

If p or op fails having consumed input at any point, the whole combinator fails.

postfix Source #

Arguments

:: (a -> b)

a function converting the value type a into the result type b

-> Parsec a

p, the single value to be parsed

-> Parsec (b -> b)

op, the postfix operator to repeatedly parse after p.

-> Parsec b

a parser that parses many ops, and a final p, and applies all of the results left-associatively.

This combinator handles left-assocative parsing, and application of, zero or more postfix unary operators to a single value.

First parse a single p. Then, parse many repeated ops. The result of p, x, is applied first to wrap, and then to each of the results of the ops, f₁ through fₙ, such that f₁ is applied first and fₙ last: fₙ( fₙ₋₁(..f₁ (wrap x)..)). This application is then returned as the result of the combinator.

If p or op fails having consumed input at any point, the whole combinator fails.

Precedence Combinators

These combinators represent each of the different "shapes" of precedence combinator, which takes a description of the precedence relations between various operators and constructs a parser for them.

precedence Source #

Arguments

:: Prec a

the description of the heterogeneous table, where each level can vary in output and input types.

-> Parsec a

an expression parser for the described precedence table.

Constructs a precedence parser.

This combinator builds an expression parser given a heterogeneous precedence table.

An expression parser will be formed by collapsing the given precedence table layer-by-layer. Since this table is heterogeneous, each level of the table produces a difference type, which is then consumed by the next level above.

precedence' Source #

Arguments

:: Parsec a

The atom at the base of the table.

-> [Op a a]

The levels of operators, oredered tightest-to-weakest.

-> Parsec a

An expression parser for the constructed precedence table.

This combinator builds an expression parser given a collection of homogeneous atoms and operators.

An expression parser will be formed by treating the given parser as the base Atom, then each successive layer in the given list as another Level in a tightest-to-weakest binding. This means the last element of the given list will be at the top of the precedence table.

Each level must consume and produce the same type.

Precedence Layer Builders

These are used to construct an individual layer of a precedence table. They all allow for the tying of a Fixity to the parsers that inhabit the level, which will have type Op a b for some a (the type of the layer below) and b (the type of this layer). Op uses existential types, so that the types of the parsers are only known when fixity itself is known.

The different objects represent different inter-layer relationships:

  • are they the same type? Use ops;
  • is the layer below a subtype of this layer? use sops;
  • or none of the above? Use gops!

ops Source #

Arguments

:: Fixity a a sig

The fixity of the layer to add.

-> [Parsec sig]

The parsers that can be run in this layer.

-> Op a a

A layer in the precedence table, containing the given parsers.

Constructs a single layer of operators in the precedence tree.

sops Source #

Arguments

:: Subtype a b 
=> Fixity a b sig

The fixity of the layer to add.

-> [Parsec sig]

The parsers that can be run in this layer.

-> Op a b

A layer in the precedence table, containing the given parsers.

Constructs a single layer of operators in the precedence tree for values of Op a b, where a is a Subtype of b. This provides support for subtyped heterogeneous precedence parsing.

gops Source #

Arguments

:: Fixity a b sig

the fixity of the operators described.

-> (a -> b)

the function that will convert as to bs. this will be at right of a left-assoc chain, left of a right-assoc chain, or the root of a prefix/postfix chain.

-> [Parsec sig]

The operators themselves, provided variadically.

-> Op a b

A layer in the precedence table, containing the given parsers.

Constructs a single layer of operators Op a b, supporting fully heterogeneous precedence parsing.

This function builds an Ops object representing many operators found at the same precedence level, with a given fixity.

The operators found on the level constructed by this function are heterogeneous: the type of the level below may vary from the types of the values produced at this level. To make this work, a function must be provided that can transform the values from the layer below into the types generated by this layer.

The fixity describes the shape of the operators expected.

Fixity Description

These all describe the fixities and associativities of operators at a given level of the precedence table. They are special because they each encode an Op type, which directs the type of the operators that are legal at the level (using existential types).

data Fixity a b sig where Source #

Denotes the fixity and associativity of an operator.

Importantly, it also specifies the types of the operations themselves.

Constructors

InfixL :: forall a b. Fixity a b (b -> a -> b)

A left-associative binary Operator.

InfixR :: forall a b. Fixity a b (a -> b -> b)

A right-associative binary Operator.

InfixN :: forall a b. Fixity a b (a -> a -> b)

A non-associative binary Operators.

Prefix :: forall a b. Fixity a b (b -> b)

A Unary prefix operator.

Postfix :: forall a b. Fixity a b (b -> b)

A Unary postfix operator.

Precedence Table Datatypes

These are the parts that make up a precedence table (in particular, they are used for heterogeneous expression parsing, with the types of each layer of the table vary from one another).

These are (mostly) not constructed directly, but are instead constructed via the use of the Ops builders or the :+ and +: methods.

data Op a b Source #

Describes a single layer of operators in the precedence tree.

The parameters are:

  • a: the base tyep consumed by the operators.
  • b: the type produced/consumed by the operators.

Constructors

Op (Fixity a b sig) (a -> b) (Parsec sig)

Describes the operators at a specific level in the precedence tree, such that these ops consume bs, possibly as and produce bs: this depends on the Fixity of the operators.

data Prec a where Source #

The base type for precedence tables.

The parameter a is the type of structure produced by the list of levels.

For more complex expression parser types, Prec describes the precedence table whilst preserving the intermediate structure between each level.

The base of the table will always be an Atom, and each layer built on top of the last using the Level constructor.

Constructors

Level :: forall a1 a. Prec a1 -> Op a1 a -> Prec a

Adds a new layer to this precedence table on the left, in a weakest-to-tightest ordering.

This method associates to the left, so left-most applications are tighter binding (closer to the atoms) than those to the right.

It should not be mixed with (+<), as this can be create a confusing and less predictable precedence table.

Atom :: forall a. Parsec a -> Prec a

The base of a precedence table.

Forms the base of a precedence table, requiring at least one atom to be provided. This first atom will be parsed first.

(>+) infixl 5 Source #

Arguments

:: Prec a

the lower precedence table.

-> Op a b

the operators that make up the new level on the table.

-> Prec b

a new table that incorporates the operators and atoms in the given table, along with extra ops.

Adds a new layer to this precedence table on the left, in a weakest-to-tightest ordering. This is an alias for Level.

This method associates to the left, so left-most applications are tighter binding (closer to the atoms) than those to the right.

It should not be mixed with (+<), as this can be create a confusing and less predictable precedence table.

(+<) infixr 5 Source #

Arguments

:: Op a b

the lower precedence table.

-> Prec a

the operators that make up the new level on the table.

-> Prec b

a new table that incorporates the operators and atoms in the given table, along with extra ops.

Adds a new layer to this precedence table on the right, in a tightest-to-weakest ordering.

This method associates to the right (with this table on the right!), so right-most applications are tighter binding (closer to the atoms) than those to the left.

It should not be mixed with (>+), as this can be create a confusing and less predictable precedence table.

Module Re-export

This should be removed at some point.

data Prec a where Source #

The base type for precedence tables.

The parameter a is the type of structure produced by the list of levels.

For more complex expression parser types, Prec describes the precedence table whilst preserving the intermediate structure between each level.

The base of the table will always be an Atom, and each layer built on top of the last using the Level constructor.

Constructors

Level :: forall a1 a. Prec a1 -> Op a1 a -> Prec a

Adds a new layer to this precedence table on the left, in a weakest-to-tightest ordering.

This method associates to the left, so left-most applications are tighter binding (closer to the atoms) than those to the right.

It should not be mixed with (+<), as this can be create a confusing and less predictable precedence table.

Atom :: forall a. Parsec a -> Prec a

The base of a precedence table.

Forms the base of a precedence table, requiring at least one atom to be provided. This first atom will be parsed first.

data Fixity a b sig where Source #

Denotes the fixity and associativity of an operator.

Importantly, it also specifies the types of the operations themselves.

Constructors

InfixL :: forall a b. Fixity a b (b -> a -> b)

A left-associative binary Operator.

InfixR :: forall a b. Fixity a b (a -> b -> b)

A right-associative binary Operator.

InfixN :: forall a b. Fixity a b (a -> a -> b)

A non-associative binary Operators.

Prefix :: forall a b. Fixity a b (b -> b)

A Unary prefix operator.

Postfix :: forall a b. Fixity a b (b -> b)

A Unary postfix operator.

data Op a b Source #

Describes a single layer of operators in the precedence tree.

The parameters are:

  • a: the base tyep consumed by the operators.
  • b: the type produced/consumed by the operators.

Constructors

Op (Fixity a b sig) (a -> b) (Parsec sig)

Describes the operators at a specific level in the precedence tree, such that these ops consume bs, possibly as and produce bs: this depends on the Fixity of the operators.

precedence Source #

Arguments

:: Prec a

the description of the heterogeneous table, where each level can vary in output and input types.

-> Parsec a

an expression parser for the described precedence table.

Constructs a precedence parser.

This combinator builds an expression parser given a heterogeneous precedence table.

An expression parser will be formed by collapsing the given precedence table layer-by-layer. Since this table is heterogeneous, each level of the table produces a difference type, which is then consumed by the next level above.

precedence' Source #

Arguments

:: Parsec a

The atom at the base of the table.

-> [Op a a]

The levels of operators, oredered tightest-to-weakest.

-> Parsec a

An expression parser for the constructed precedence table.

This combinator builds an expression parser given a collection of homogeneous atoms and operators.

An expression parser will be formed by treating the given parser as the base Atom, then each successive layer in the given list as another Level in a tightest-to-weakest binding. This means the last element of the given list will be at the top of the precedence table.

Each level must consume and produce the same type.

ops Source #

Arguments

:: Fixity a a sig

The fixity of the layer to add.

-> [Parsec sig]

The parsers that can be run in this layer.

-> Op a a

A layer in the precedence table, containing the given parsers.

Constructs a single layer of operators in the precedence tree.

sops Source #

Arguments

:: Subtype a b 
=> Fixity a b sig

The fixity of the layer to add.

-> [Parsec sig]

The parsers that can be run in this layer.

-> Op a b

A layer in the precedence table, containing the given parsers.

Constructs a single layer of operators in the precedence tree for values of Op a b, where a is a Subtype of b. This provides support for subtyped heterogeneous precedence parsing.

gops Source #

Arguments

:: Fixity a b sig

the fixity of the operators described.

-> (a -> b)

the function that will convert as to bs. this will be at right of a left-assoc chain, left of a right-assoc chain, or the root of a prefix/postfix chain.

-> [Parsec sig]

The operators themselves, provided variadically.

-> Op a b

A layer in the precedence table, containing the given parsers.

Constructs a single layer of operators Op a b, supporting fully heterogeneous precedence parsing.

This function builds an Ops object representing many operators found at the same precedence level, with a given fixity.

The operators found on the level constructed by this function are heterogeneous: the type of the level below may vary from the types of the values produced at this level. To make this work, a function must be provided that can transform the values from the layer below into the types generated by this layer.

The fixity describes the shape of the operators expected.

(>+) infixl 5 Source #

Arguments

:: Prec a

the lower precedence table.

-> Op a b

the operators that make up the new level on the table.

-> Prec b

a new table that incorporates the operators and atoms in the given table, along with extra ops.

Adds a new layer to this precedence table on the left, in a weakest-to-tightest ordering. This is an alias for Level.

This method associates to the left, so left-most applications are tighter binding (closer to the atoms) than those to the right.

It should not be mixed with (+<), as this can be create a confusing and less predictable precedence table.

(+<) infixr 5 Source #

Arguments

:: Op a b

the lower precedence table.

-> Prec a

the operators that make up the new level on the table.

-> Prec b

a new table that incorporates the operators and atoms in the given table, along with extra ops.

Adds a new layer to this precedence table on the right, in a tightest-to-weakest ordering.

This method associates to the right (with this table on the right!), so right-most applications are tighter binding (closer to the atoms) than those to the left.

It should not be mixed with (>+), as this can be create a confusing and less predictable precedence table.