elna/lib/Language/Elna/Frontend/Parser.hs

224 lines
5.9 KiB
Haskell
Raw Normal View History

2024-10-02 22:56:15 +02:00
module Language.Elna.Frontend.Parser
2024-07-23 22:44:42 +02:00
( Parser
, programP
) where
2024-09-15 23:03:25 +02:00
import Control.Monad (void)
2024-09-29 19:50:55 +02:00
import Control.Monad.Combinators.Expr (Operator(..), makeExprParser)
2024-07-23 22:44:42 +02:00
import Data.Text (Text)
2024-09-15 23:03:25 +02:00
import qualified Data.Text as Text
2024-07-23 22:44:42 +02:00
import Data.Void (Void)
2024-10-02 22:56:15 +02:00
import Language.Elna.Frontend.AST
2024-09-15 23:03:25 +02:00
( Declaration(..)
2024-07-23 22:44:42 +02:00
, Identifier(..)
, Parameter(..)
2024-09-15 23:03:25 +02:00
, Program(..)
2024-07-24 01:22:20 +02:00
, Statement(..)
2024-07-23 22:44:42 +02:00
, TypeExpression(..)
2024-09-15 23:03:25 +02:00
, VariableDeclaration(..)
2024-11-06 22:23:49 +01:00
, VariableAccess(..)
2024-10-11 16:14:01 +02:00
, Condition(..)
2024-09-15 23:03:25 +02:00
, Expression(..)
2024-09-24 22:20:57 +02:00
, Literal(..)
2024-07-23 22:44:42 +02:00
)
2024-07-25 01:39:53 +02:00
import Text.Megaparsec
( Parsec
, (<?>)
2024-09-24 22:20:57 +02:00
, MonadParsec(..)
2024-09-15 23:03:25 +02:00
, eof
2024-07-25 01:39:53 +02:00
, optional
, between
, sepBy
2024-09-24 22:20:57 +02:00
, choice
2024-07-25 01:39:53 +02:00
)
2024-09-15 23:03:25 +02:00
import qualified Text.Megaparsec.Char.Lexer as Lexer
import Text.Megaparsec.Char
2024-07-25 01:39:53 +02:00
( alphaNumChar
2024-10-04 18:26:10 +02:00
, char
2024-07-25 01:39:53 +02:00
, letterChar
, space1
2024-10-04 18:26:10 +02:00
, string
2024-07-25 01:39:53 +02:00
)
2024-07-23 22:44:42 +02:00
import Control.Applicative (Alternative(..))
import Data.Maybe (isJust)
2024-09-15 23:03:25 +02:00
2024-07-23 22:44:42 +02:00
type Parser = Parsec Void Text
2024-07-24 01:22:20 +02:00
literalP :: Parser Literal
literalP
= HexadecimalLiteral <$> Lexer.signed space hexadecimalP
<|> DecimalLiteral <$> Lexer.signed space decimalP
2024-10-04 18:26:10 +02:00
<|> CharacterLiteral <$> lexeme charP
2024-07-24 01:22:20 +02:00
where
charP = fromIntegral . fromEnum
2024-10-04 18:26:10 +02:00
<$> between (char '\'') (char '\'') Lexer.charLiteral
2024-10-17 00:37:42 +02:00
2024-09-24 22:20:57 +02:00
typeDefinitionP :: Parser Declaration
typeDefinitionP = TypeDefinition
<$> (symbol "type" *> identifierP)
<*> (symbol "=" *> typeExpressionP)
<* semicolonP
<?> "type definition"
2024-10-17 00:37:42 +02:00
2024-07-24 01:22:20 +02:00
termP :: Parser Expression
termP = choice
[ parensP expressionP
, LiteralExpression <$> literalP
2024-11-06 22:23:49 +01:00
, VariableExpression <$> variableAccessP
2024-07-24 01:22:20 +02:00
]
2024-08-15 20:13:56 +02:00
2024-07-24 01:22:20 +02:00
operatorTable :: [[Operator Parser Expression]]
operatorTable =
2024-10-02 22:56:15 +02:00
[ unaryOperator
2024-10-04 18:26:10 +02:00
, factorOperator
2024-10-02 22:56:15 +02:00
, termOperator
2024-07-24 01:22:20 +02:00
]
where
2024-10-02 22:56:15 +02:00
unaryOperator =
2024-07-24 01:22:20 +02:00
[ prefix "-" NegationExpression
, prefix "+" id
]
2024-10-04 18:26:10 +02:00
factorOperator =
2024-07-24 01:22:20 +02:00
[ binary "*" ProductExpression
2024-10-06 18:07:57 +02:00
, binary "/" DivisionExpression
2024-10-04 18:26:10 +02:00
]
2024-07-24 01:22:20 +02:00
termOperator =
[ binary "+" SumExpression
, binary "-" SubtractionExpression
]
2024-10-02 22:56:15 +02:00
prefix name f = Prefix (f <$ symbol name)
2024-07-24 01:22:20 +02:00
binary name f = InfixL (f <$ symbol name)
2024-09-29 19:50:55 +02:00
2024-07-24 01:22:20 +02:00
expressionP :: Parser Expression
2024-09-29 19:50:55 +02:00
expressionP = makeExprParser termP operatorTable
2024-11-06 22:23:49 +01:00
2024-09-29 19:50:55 +02:00
variableAccessP :: Parser VariableAccess
2024-12-02 13:57:03 +01:00
variableAccessP = do
2024-09-29 19:50:55 +02:00
identifier <- identifierP
indices <- many $ bracketsP expressionP
2024-12-02 13:57:03 +01:00
pure $ foldr (flip ArrayAccess) (VariableAccess identifier) indices
2024-11-06 22:23:49 +01:00
2024-08-15 20:13:56 +02:00
conditionP :: Parser Condition
conditionP = do
lhs <- expressionP
conditionCons <- choice comparisonOperator
conditionCons lhs <$> expressionP
where
comparisonOperator =
2024-10-13 12:59:47 +02:00
[ symbol "<=" >> pure LessOrEqualCondition
, symbol "<" >> pure LessCondition
, symbol ">=" >> pure GreaterOrEqualCondition
, symbol ">" >> pure GreaterCondition
, symbol "=" >> pure EqualCondition
, symbol "#" >> pure NonEqualCondition
2024-08-15 20:13:56 +02:00
]
2024-10-11 16:14:01 +02:00
2024-09-15 23:03:25 +02:00
symbol :: Text -> Parser Text
symbol = Lexer.symbol space
space :: Parser ()
space = Lexer.space space1 (Lexer.skipLineComment "//")
$ Lexer.skipBlockComment "/*" "*/"
lexeme :: forall a. Parser a -> Parser a
lexeme = Lexer.lexeme space
blockP :: forall a. Parser a -> Parser a
blockP = between (symbol "{") (symbol "}")
parensP :: forall a. Parser a -> Parser a
parensP = between (symbol "(") (symbol ")")
bracketsP :: forall a. Parser a -> Parser a
bracketsP = between (symbol "[") (symbol "]")
colonP :: Parser ()
colonP = void $ symbol ":"
commaP :: Parser ()
commaP = void $ symbol ","
semicolonP :: Parser ()
semicolonP = void $ symbol ";"
decimalP :: Integral a => Parser a
decimalP = lexeme Lexer.decimal
hexadecimalP :: Integral a => Parser a
hexadecimalP = string "0x" *> lexeme Lexer.hexadecimal
2024-10-02 22:56:15 +02:00
2024-09-15 23:03:25 +02:00
identifierP :: Parser Identifier
identifierP =
let wordParser = (:) <$> letterChar <*> many alphaNumChar <?> "identifier"
in fmap Identifier $ lexeme $ Text.pack <$> wordParser
procedureP :: Parser ()
procedureP = void $ symbol "proc"
parameterP :: Parser Parameter
parameterP = paramCons
<$> optional (symbol "ref")
<*> identifierP
<*> (colonP *> typeExpressionP)
where
paramCons ref name typeName = Parameter name typeName (isJust ref)
typeExpressionP :: Parser TypeExpression
typeExpressionP = arrayTypeExpression
<|> NamedType <$> identifierP
<?> "type expression"
where
arrayTypeExpression = ArrayType
<$> (symbol "array" *> bracketsP literalP)
2024-09-15 23:03:25 +02:00
<*> (symbol "of" *> typeExpressionP)
procedureDeclarationP :: Parser Declaration
procedureDeclarationP = procedureCons
<$> (procedureP *> identifierP)
<*> parensP (sepBy parameterP commaP)
<*> blockP ((,) <$> many variableDeclarationP <*> many statementP)
<?> "procedure definition"
where
procedureCons procedureName parameters (variables, body) =
ProcedureDeclaration procedureName parameters variables body
2024-08-15 20:13:56 +02:00
2024-07-24 01:22:20 +02:00
statementP :: Parser Statement
statementP
= EmptyStatement <$ semicolonP
2024-10-11 16:14:01 +02:00
<|> ifElseP
2024-10-13 12:59:47 +02:00
<|> CompoundStatement <$> blockP (many statementP)
2024-11-06 22:23:49 +01:00
<|> try assignmentP
2024-11-24 13:05:11 +01:00
<|> try whileP
2024-10-11 16:14:01 +02:00
<|> callP
2024-07-25 01:39:53 +02:00
<?> "statement"
2024-09-24 22:20:57 +02:00
where
callP = CallStatement
<$> identifierP
<*> parensP (sepBy expressionP commaP)
<* semicolonP
2024-10-11 16:14:01 +02:00
ifElseP = IfStatement
2024-08-15 20:13:56 +02:00
<$> (symbol "if" *> parensP conditionP)
2024-07-25 01:39:53 +02:00
<*> statementP
<*> optional (symbol "else" *> statementP)
2024-11-24 13:05:11 +01:00
whileP = WhileStatement
2024-08-15 20:13:56 +02:00
<$> (symbol "while" *> parensP conditionP)
2024-11-24 13:05:11 +01:00
<*> statementP
2024-07-25 01:39:53 +02:00
assignmentP = AssignmentStatement
2024-08-15 20:13:56 +02:00
<$> variableAccessP
2024-07-25 01:39:53 +02:00
<* symbol ":="
<*> expressionP
2024-11-06 22:23:49 +01:00
<* semicolonP
2024-09-29 19:50:55 +02:00
2024-09-15 23:03:25 +02:00
variableDeclarationP :: Parser VariableDeclaration
variableDeclarationP = VariableDeclaration
<$> (symbol "var" *> identifierP)
<*> (colonP *> typeExpressionP)
<* semicolonP
<?> "variable declaration"
2024-07-23 22:44:42 +02:00
declarationP :: Parser Declaration
2024-10-17 00:37:42 +02:00
declarationP = procedureDeclarationP <|> typeDefinitionP
2024-09-15 23:03:25 +02:00
2024-07-23 22:44:42 +02:00
programP :: Parser Program
2024-09-15 23:03:25 +02:00
programP = Program <$> many declarationP <* eof