platinum-parsing-0.1.0.0: src/PP/Grammars/LexicalHelper.hs
{-|
Module : PP.Grammars.LexicalHelper
Description : Add lexical support to other grammars
Copyright : (c) 2017 Patrick Champion
License : see LICENSE file
Maintainer : chlablak@gmail.com
Stability : provisional
Portability : portable
-}
module PP.Grammars.LexicalHelper
( -- *AST helper for other grammars
LexicalRule(..)
, LexicalDefinitionList(..)
, LexicalDefinition(..)
-- *Helpers
, lexicalString
) where
import Control.Applicative ((<$>), (<*>))
import Data.Text (pack, strip, unpack)
import PP.Grammar
import qualified PP.Rule as R
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Language (emptyDef)
import qualified Text.ParserCombinators.Parsec.Token as Token
-- |Defines a lexical rule represented by a identifier
data LexicalRule = LexicalRule String LexicalDefinitionList
deriving (Show, Eq)
-- |Defines the definition list for a lexical rule
newtype LexicalDefinitionList = LexicalDefinitionList [LexicalDefinition]
deriving (Show, Eq)
-- |Lexical rule definition component
data LexicalDefinition
-- |Regular expression as a terminal string
= LexicalRegEx String
| LexicalString String
-- |Other lexical rule identifier
| LexicalIdentifier String
deriving (Show, Eq)
-- |Construct a simple lexical rule
lexicalString :: String -> String -> LexicalRule
lexicalString n s = LexicalRule n $ LexicalDefinitionList [LexicalString s]
-- |Parsing helpers
lexer = Token.makeTokenParser def
where
def = emptyDef {
Token.commentStart = "(*"
, Token.commentEnd = "*)"
, Token.commentLine = ""
, Token.nestedComments = False
, Token.identStart = letter
, Token.identLetter = alphaNum <|> oneOf "_- "
, Token.reservedNames = []
, Token.reservedOpNames = ["%=", ";", ","]
, Token.caseSensitive = True
}
identifier = Token.identifier lexer
reservedOp = Token.reservedOp lexer
stringLiteral = Token.stringLiteral lexer
whiteSpace = Token.whiteSpace lexer
-- |Parser for LexicalRule
lexicalRule :: Parser LexicalRule
lexicalRule = whiteSpace *>
(LexicalRule <$> (lexicalIdentifier <* reservedOp "%=")
<*> (lexicalDefinitionList <* reservedOp ";"))
<?> "lexical rule"
-- |Parser for LexicalDefinitionList$
lexicalDefinitionList :: Parser LexicalDefinitionList
lexicalDefinitionList = LexicalDefinitionList <$> sepBy1 lexicalDefinition (reservedOp ",")
<?> "lexical definition list"
-- |Parser for LexicalDefinition
lexicalDefinition :: Parser LexicalDefinition
lexicalDefinition = LexicalRegEx <$> stringLiteral
<|> LexicalIdentifier <$> lexicalIdentifier
<?> "lexical definition"
-- |Parser for LexicalIdentifier, helper
lexicalIdentifier :: Parser String
lexicalIdentifier = (unpack . strip . pack) <$> identifier
<?> "lexical identifier"
-- *Associated InputGrammar instances
instance InputGrammar LexicalRule where
parser = lexicalRule
stringify (LexicalRule li xs) = li ++ "%=" ++ stringify xs ++ ";"
rules (LexicalRule li xs) = R.uniformize [R.Rule li (rules xs ++ [R.Empty])]
instance InputGrammar LexicalDefinitionList where
parser = lexicalDefinitionList
stringify (LexicalDefinitionList []) = ""
stringify (LexicalDefinitionList [x]) = stringify x
stringify (LexicalDefinitionList (x:xs)) =
stringify x ++ "," ++ stringify (LexicalDefinitionList xs)
rules (LexicalDefinitionList xs) = [head (rules x) | x <- xs]
instance InputGrammar LexicalDefinition where
parser = lexicalDefinition
stringify (LexicalString x) = show x
stringify (LexicalRegEx x) = show x
stringify (LexicalIdentifier x) = x
rules (LexicalRegEx x) = [R.RegEx x]
rules (LexicalString x) = [R.RegExString x]
rules (LexicalIdentifier x) = [R.NonTerm x]