ptera-th: A parser generator

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Ptera is haskell libraries and toolchains for generating parser.


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.2.0.0, 0.3.0.0, 0.4.0.0, 0.5.0.0, 0.6.0.0, 0.6.0.0, 0.6.1.0, 0.7.0.0
Change log CHANGELOG.md
Dependencies array (>=0.5.4 && <0.6), base (>=4.14.0 && <5), containers (>=0.6.0 && <0.7), enummapset-th (>=0.6.0 && <0.7), ghc-prim (>=0.6.1 && <0.7), membership (>=0.0.1 && <0.1), ptera (>=0.3.0 && <0.4), ptera-core (>=0.1.0 && <0.2), template-haskell (>=2.16.0 && <2.17), unordered-containers (>=0.2.0 && <0.3) [details]
License (Apache-2.0 OR MPL-2.0)
Copyright (c) 2021 Mizunashi Mana
Author Mizunashi Mana
Maintainer mizunashi-mana@noreply.git
Category Parsing
Home page https://github.com/mizunashi-mana/ptera
Bug tracker https://github.com/mizunashi-mana/ptera/issues
Source repo head: git clone https://github.com/mizunashi-mana/ptera.git
Uploaded by mizunashi_mana at 2022-05-14T15:49:40Z

Modules

[Index] [Quick Jump]

Flags

Manual Flags

NameDescriptionDefault
develop

Turn on some options for development

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for ptera-th-0.6.0.0

[back to package description]

Ptera: A Parser Generator for PEGs

Hackage

Installation

Add dependencies on package.cabal:

build-depends:
    base,
    ptera,          -- main
    ptera-th,       -- for outputing parser with Template Haskell
    template-haskell,

Usage

Write parser rules:

module Parser.Rules where

import Language.Haskell.TH
import Language.Parser.Ptera.TH

data Token
    = TokDigit
    | TokSymPlus
    | TokSymMulti
    | TokEndOfInput
    deriving (Eq, Show, Enum)

data Ast
    = Value
    | Sum Ast Ast
    | Product Ast Ast

$(genGrammarToken (mkName "Tokens") [t|Token|]
    [ ("+", [p|TokSymPlus|])
    , ("*", [p|TokSymMulti|])
    , ("n", [p|TokDigit|])
    , ("^Z", [p|TokEndOfInput{}|])
    ])

$(Ptera.genRules
    do TH.mkName "RuleDefs"
    do GenRulesTypes
        { genRulesCtxTy = [t|()|]
        , genRulesTokensTy = [t|Tokens|]
        , genRulesTokenTy = [t|Token|]
        }
    [ (TH.mkName "ruleExprEos", "expr ^Z", [t|Ast|])
    , (TH.mkName "ruleExpr", "expr", [t|Ast|])
    , (TH.mkName "ruleSum", "sum", [t|Ast|])
    , (TH.mkName "ruleProduct", "product", [t|Ast|])
    , (TH.mkName "ruleValue", "value", [t|Ast|])
    ]
    )

$(Ptera.genParsePoints
    do TH.mkName "ParsePoints"
    do TH.mkName "RuleDefs"
    [ "expr ^Z"
    ]
    )

grammar :: Grammar RuleDefs Tokens Token ParsePoints
grammar = fixGrammar $ RuleDefs
    { ruleExprEos = rExprEos
    , ruleExpr = rExpr
    , ruleSum = rSum
    , ruleProduct = rProduct
    , ruleValue = rValue
    }

type Rule = RuleExpr RuleDefs Tokens Token


rExprEos :: Rule Ast
rExprEos = ruleExpr
    [ varA @"expr" <^> tokA @"^Z"
        <:> \(e :* _ :* HNil) -> e
    ]

rExpr :: Rule Ast
rExpr = ruleExpr
    [ varA @"sum"
        <:> \(e :* HNil) -> e
    ]

rSum :: Rule Ast
rSum = ruleExpr
    [ varA @"product" <^> tokA @"+" <^> varA @"sum"
        <:> \(e1 :* _ :* e2 :* HNil) -> [|| Sum $$(e1) $$(e2) ||]
    , varA @"product"
        <:> \(e :* HNil) -> e
    ]

rProduct :: Rule Ast
rProduct = ruleExpr
    [ varA @"value" <^> tokA @"*" <^> varA @"product"
        <:> \(e1 :* _ :* e2 :* HNil) -> [|| Product $$(e1) $$(e2) ||]
    , varA @"value"
        <:> \(e :* HNil) -> e
    ]

rValue :: Rule Ast
rValue = ruleExpr
    [ tokA @"n" <:> \(n :* HNil) ->
        [|| case $$(n) of
            TokDigit -> Value
            _        -> error "unreachable: expected digit token"
        ||]
    ]

And, generate parser:

module Parser where

import Parser.Rules
import Language.Parser.Ptera.TH
import Data.Proxy

$(genRunner
    (GenParam
        { startsTy = [t|ParsePoints|]
        , rulesTy  = [t|RuleDefs|]
        , tokensTy = [t|Tokens|]
        , tokenTy  = [t|Token|]
        , customCtxTy = defaultCustomCtxTy
        })
    grammar
    )

exprParser :: Scanner posMark Token m => m (Result posMark Ast)
exprParser = runParser (Proxy :: Proxy "expr EOS") pteraTHRunner

Examples