Install

You can install from Hackage, by using cabal-install.

$ cabal update
$ cabal install Peggy

Now, you can use Peggy!

First Example

Here is first example.

{-# Language TemplateHaskell, QuasiQuotes, FlexibleContexts #-}

import Text.Peggy

[peggy|
nums :: [Int]
  = num*
num ::: Int
  = [0-9]+ { read $1 }
|]

main :: IO ()
main = print . parseString nums "<stdin>" =<< getContents

It is a parser which parses a sequence of integers. Let’s try it.

$ cat input 
1 2 3 4 5
$ runhaskell Test.hs < input
Right [1,2,3,4,5]

It seems to run correctly :)

Language Extensions

At first line,

{-# Language TemplateHaskell, QuasiQuotes, FlexibleContexts #-}

add these language extensions for using peggy embeded DSL.

Import Peggy module

To use Peggy, you need simply to import Peggy module.

import Text.Peggy

Define a parser

Now, you can define your parser. Peggy is embeded DSL (eDSL) style parser generator, so you wrote your parser in a Haskell file directly.

Peggy is provided by Quasi-Quoter. In order to define parser, write a syntax in quasi-quoter [peggy| … |].

[peggy|
nums :: [Int]
  = num*
... define syntax here
|]

A parser is a set of definitions. You can use full PEG syntax and Peggy extensions. A full Peggy syntax is described here.

Typical form of syntax

A typical form of syntax definition is

<name> :: <Haskell-Type>
  = <expr> ... { <semantic-by-haskell-code> }
  / <expr> ... { ... }
  ...

Each definition has several alternatives, and each alternative is a sequence of primitive expression with semantic. Semantic is a single haskell expression with place holder. It specify the result value of the nonterminal.

Token

Peggy handles implicit token. You can define a nonterminals as a token by using triple-colon (:::)

num ::: Int
  = [0-9]+ { read $1 }

It allows any leading/trailing spaces. For more detail about token behaviour, please refer to syntax maual.

Generated parser

Peggy quasi-quoter generates a set of parsers. Parser is defined for each nonterminal symbol has same name.

nums :: Parser [Int] -- It is simplified. Actually, it has more complicated type.
nums = ... (Haskell code generated by Peggy)

Invoking parser

At last, you can invoke your parser by using following function.

parseString :: ListLike str Char
               => Parser a
               -> String
               -> str
               -> Either ParseError a
parseString parser inputName input =
  ...

It can parse any String-like sequence by passed parser.

Generate Quasi-Quoter

Peggy can generate user defined quasi-quoter easily.

module Nums (numsqq) where

genParser [("numsqq", "nums")] [peggy|
nums :: [Int]
  = num*
num ::: Int
  = [0-9]+ { read $1 }
|]

First argument of genParser is a list of pair, qqname and top-nonterminal. In above example, a quasi-quoter named “numsqq” are defined. It generates a list of integers. Because of a restriction of Template Haskell, you must split definition and use of quasi-quoters.

{-# Language TemplateHaskell, QuasiQuotes, FlexibleContexts #-}
import Nums

main :: IO ()
main = print [numsqq| 1 2 3 4 5 |]

Then, you can use it.

$ runhaskell Test.hs
[1, 2, 3, 4, 5]

Learn more

  • Some example of more complex parsers are here.
  • A full description of Peggy syntax is avaiable here.
  • A self defined Peggy syntax file is here, it is used for bootstrapping peggy parser.
  • A github repository is here. Any patch / pull requests are welcome!