rtk-0.12: Syntax.hs
-- | The normalized-grammar data types: 'NormalGrammar' and friends, the
-- representation the code generators ('GenX', 'GenY', 'GenAST', 'GenQ')
-- consume, plus the pure helpers over them.
--
-- The parsed-grammar half of the pipeline has no types of its own anymore:
-- since task 8c the front half computes directly over the GENERATED AST
-- ('GrammarParser''s @Grammar@\/@Rule@\/@Clause@, compiled from the
-- @test/golden/grammar/@ snapshot; helpers in "Frontend"). The historic
-- @InitialGrammar@\/@IRule@\/@IClause@ types are retired. The one place the
-- generated AST threads into THIS module is 'LClause': lexical rules keep
-- their clause unnormalized so 'GenX' can translate it to an Alex
-- specification.
module Syntax where
import Data.Char (isLower)
import Data.Data (Data)
import qualified Data.Map as M
import qualified Data.Set as S
import qualified GrammarParser as GP
type ConstructorName = String
type ID = String
-- | The first line of every generated artifact (lexer spec, parser spec,
-- quasi-quoter module). The banner names the grammar, not the grammar file:
-- a file path would make the generated output - and with it every golden
-- snapshot - depend on where the grammar happens to live. It also carries
-- no rtk version: a version in the banner would couple every release bump
-- to a full golden churn even when the generated code is byte-identical.
provenanceBanner :: String -> String
provenanceBanner name =
"-- Generated by RTK from grammar '" ++ name ++ "'. Do not edit by hand."
data GrammarInfo =
GrammarInfo
{
getStartRuleName :: Maybe String,
getRuleToStartInfo :: M.Map String String,
getNameCounter :: Int,
getProxyRules :: S.Set String
}
deriving (Eq, Show, Data)
data AntiRule = AntiRule { arTypeName :: ID,
arQQName :: ID,
arConstr :: ID ,
arIsList :: Bool
}
deriving (Eq, Show, Data)
data NormalGrammar = NormalGrammar { getNGrammarName :: String,
getSyntaxRuleGroups :: [SyntaxRuleGroup],
getLexicalRules :: [LexicalRule],
getAntiRules :: [AntiRule],
getShortcuts :: [(String, String)],
getNImports :: String,
getGrammarInfo :: GrammarInfo }
deriving (Eq, Show, Data)
data SyntaxRuleGroup = SyntaxRuleGroup { getSDataTypeName :: ID,
getSRules :: [SyntaxRule]}
deriving (Eq, Show, Data)
data SyntaxRule = SyntaxRule { getSRuleName :: ID,
getSClause :: SyntaxTopClause}
deriving (Eq, Show, Data)
data STManyOp = STStar
| STPlus
deriving (Eq, Show, Data)
data STSeq = STSeq ConstructorName [SyntaxSimpleClause]
deriving (Eq, Show, Data)
data SyntaxTopClause = STMany STManyOp SyntaxSimpleClause (Maybe SyntaxSimpleClause)
| STOpt SyntaxSimpleClause
| STAltOfSeq { getAltOfSeq :: [STSeq] } -- alternative of sequences
deriving (Eq, Show, Data)
data SyntaxSimpleClause = SSId ID
| SSLifted ID
| SSIgnore ID
deriving (Eq, Show, Data)
data LexicalRule = LexicalRule { getLRuleDataType :: String,
getLRuleFunc :: String,
getLRuleName :: String,
getLClause :: LClause}
| MacroRule { getLRuleName :: String, getLClause :: LClause}
deriving (Eq, Show, Data)
-- | A lexical rule's clause stays unnormalized all the way to 'GenX': it is
-- the generated front end's clause type (token text already cleaned by
-- @Frontend.cleanGrammarTokens@). Synthesized rules (keyword tokens, QQ
-- splice tokens, start-wrapper dummies) build their clauses with
-- 'GP.rtkNoPos' positions.
type LClause = GP.Clause
isLexicalRule :: String -> Bool
isLexicalRule [] = False
isLexicalRule (c:_) = isLower c
filterProxyRules :: S.Set ID -> [SyntaxRuleGroup] -> [SyntaxRuleGroup]
filterProxyRules proxyRules rules = filter (((flip S.notMember) proxyRules) . getSDataTypeName) rules