ptera-0.1.0.0: src/Language/Parser/Ptera/Syntax/SafeGrammar.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
module Language.Parser.Ptera.Syntax.SafeGrammar (
T,
Grammar (..),
TokensTag,
RulesTag,
RuleExprType,
GrammarToken (..),
fixGrammar,
StartPoint,
Terminal,
NonTerminal,
HasRuleExprField (..),
MemberInitials (..),
Rules (..),
genStartPoint,
RuleExpr (..),
Alt (..),
Expr (..),
ruleExpr,
(<^>),
(<:>),
eps,
var,
varA,
tok,
TokensMember (..),
tokA,
) where
import Language.Parser.Ptera.Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Language.Parser.Ptera.Data.HEnum as HEnum
import qualified Language.Parser.Ptera.Data.HFList as HFList
import qualified Language.Parser.Ptera.Syntax.Grammar as SyntaxGrammar
import Prelude (String)
import qualified Type.Membership as Membership
type T = Grammar
type Grammar
:: ([Type] -> Type -> Type) -> Type -> Type -> Type -> [Symbol]
-> Type
newtype Grammar action rules tokens elem initials = UnsafeGrammar
{
unsafeGrammar :: SyntaxGrammar.FixedGrammar
StartPoint
NonTerminal
Terminal
elem
StringLit
(Maybe ())
action
}
type family TokensTag (tokens :: Type) :: [Symbol]
type family RulesTag (rules :: Type) :: [Symbol]
type family RuleExprType (rules :: Type) :: Type -> Type
class GrammarToken tokens elem where
tokenToTerminal :: Proxy tokens -> elem -> HEnum.T (TokensTag tokens)
class
( KnownSymbol v
, HasField v rules ((RuleExprType rules) (RuleExprReturnType rules v))
) => HasRuleExprField rules v where
type RuleExprReturnType rules v :: Type
nonTerminalName :: rules -> proxy v -> String
nonTerminalName _ p = symbolVal p
type GrammarMForFixGrammar elem action = SyntaxGrammar.GrammarT
StartPoint
NonTerminal
Terminal
elem
StringLit
(Maybe ())
action
Identity
fixGrammar
:: forall initials action rules tokens elem
. MemberInitials rules initials
=> Rules rules => RuleExprType rules ~ RuleExpr action rules tokens elem
=> rules -> Grammar action rules tokens elem initials
fixGrammar ruleDefs = UnsafeGrammar do
runIdentity do
SyntaxGrammar.fixGrammarT do
HFList.hforMWithIndex
memberInitials
fixInitial
HFList.hforMWithIndex
generateRules
fixRule
where
fixInitial
:: Membership.Membership initials v
-> HFList.DictF (HasRuleExprField rules) v
-> GrammarMForFixGrammar elem action ()
fixInitial m HFList.DictF = do
let sn = genStartPoint m
let vn = getNewV do symbolVal m
SyntaxGrammar.initialT sn vn
fixRule
:: forall v
. Membership.Membership (RulesTag rules) v
-> HFList.DictF (HasRuleExprField rules) v
-> GrammarMForFixGrammar elem action ()
fixRule m HFList.DictF = do
let vn = getNewV do symbolVal m
let d = nonTerminalName ruleDefs m
SyntaxGrammar.ruleT vn d do
fixRuleExpr do getField @v ruleDefs
fixRuleExpr :: RuleExpr action rules tokens elem a
-> SyntaxGrammar.RuleExpr NonTerminal Terminal elem (Maybe ()) action
fixRuleExpr = \case
RuleExpr alts -> SyntaxGrammar.RuleExpr
[ fixAlt origAlt | origAlt <- alts ]
fixAlt :: Alt action rules tokens elem a
-> SyntaxGrammar.Alt NonTerminal Terminal elem (Maybe ()) action a
fixAlt (UnsafeAlt origAlt) = case origAlt of
SyntaxGrammar.Alt e h act -> SyntaxGrammar.Alt
do fixExpr e
do h
do act
fixExpr :: SyntaxGrammar.Expr IntermNonTerminal Terminal elem us
-> SyntaxGrammar.Expr NonTerminal Terminal elem us
fixExpr = HFList.hmapWithIndex
do \_ u1 -> fixUnit u1
fixUnit :: SyntaxGrammar.Unit IntermNonTerminal Terminal elem u
-> SyntaxGrammar.Unit NonTerminal Terminal elem u
fixUnit u = case u of
SyntaxGrammar.UnitToken t ->
SyntaxGrammar.UnitToken t
SyntaxGrammar.UnitVar v ->
SyntaxGrammar.UnitVar do getNewV v
rulesTag = genRulesTagMap do proxy# @rules
getNewV v = case HashMap.lookup v rulesTag of
Just newV ->
newV
Nothing ->
error "unreachable: rulesTag must include v."
type StartPoint = Int
type Terminal = Int
type NonTerminal = Int
type IntermNonTerminal = String
class MemberInitials rules initials where
memberInitials :: HFList.T (HFList.DictF (HasRuleExprField rules)) initials
class Rules rules where
generateRules :: HFList.T (HFList.DictF (HasRuleExprField rules)) (RulesTag rules)
genStartPoint :: forall initials v. Membership.Membership initials v -> StartPoint
genStartPoint m = Membership.getMemberId m
genRulesTagMap :: forall rules.
Rules rules => Proxy# rules -> HashMap.HashMap IntermNonTerminal NonTerminal
genRulesTagMap _ = HFList.hfoldlWithIndex HashMap.empty go generateRules where
go :: forall v
. HashMap.HashMap IntermNonTerminal NonTerminal
-> Membership.Membership (RulesTag rules) v
-> HFList.DictF (HasRuleExprField rules) v
-> HashMap.HashMap IntermNonTerminal NonTerminal
go vMap m HFList.DictF = HashMap.insert
do symbolVal' do proxy# @v
do Membership.getMemberId m
do vMap
type RuleExpr :: ([Type] -> Type -> Type) -> Type -> Type -> Type -> Type -> Type
newtype RuleExpr action rules tokens elem a = RuleExpr
{ unRuleExpr :: [Alt action rules tokens elem a]
}
type Alt :: ([Type] -> Type -> Type) -> Type -> Type -> Type -> Type -> Type
newtype Alt action rules tokens elem a = UnsafeAlt
{ unsafeAlt
:: SyntaxGrammar.Alt IntermNonTerminal Terminal elem (Maybe ()) action a
}
type Expr :: Type -> Type -> Type -> [Type] -> Type
newtype Expr rules tokens elem us = UnsafeExpr
{ unsafeExpr :: SyntaxGrammar.Expr IntermNonTerminal Terminal elem us
}
class TokensMember tokens t where
tokensMembership :: Proxy# '(tokens, t) -> Membership.Membership (TokensTag tokens) t
ruleExpr :: [Alt action rules tokens elem a] -> RuleExpr action rules tokens elem a
ruleExpr alts = RuleExpr alts
(<:>)
:: Expr rules tokens elem us -> action us a
-> Alt action rules tokens elem a
UnsafeExpr e <:> act = UnsafeAlt do SyntaxGrammar.Alt e Nothing act
infixl 4 <:>
eps :: action '[] a -> Alt action rules tokens elem a
eps act = UnsafeAlt do SyntaxGrammar.Alt HFList.HFNil Nothing act
(<^>)
:: Expr rules tokens elem us1 -> Expr rules tokens elem us2
-> Expr rules tokens elem (HFList.Concat us1 us2)
UnsafeExpr e1 <^> UnsafeExpr e2 = UnsafeExpr do HFList.hconcat e1 e2
infixr 5 <^>
var :: KnownSymbol v => proxy v -> Expr rules tokens elem '[RuleExprReturnType rules v]
var p = UnsafeExpr do HFList.HFCons u HFList.HFNil where
u = SyntaxGrammar.UnitVar do symbolVal p
varA :: forall v rules tokens elem.
KnownSymbol v => Expr rules tokens elem '[RuleExprReturnType rules v]
varA = var do Proxy @v
tok :: Membership.Membership (TokensTag tokens) t -> Expr rules tokens elem '[elem]
tok p = UnsafeExpr do HFList.HFCons u HFList.HFNil where
u = SyntaxGrammar.UnitToken
do HEnum.unsafeHEnum do HEnum.henum p
tokA :: forall t rules tokens elem.
TokensMember tokens t => Expr rules tokens elem '[elem]
tokA = tok do tokensMembership do proxy# @'(tokens, t)