summaryrefslogtreecommitdiff
path: root/lib/Language/Elna/Parser.hs
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2024-07-23 22:44:42 +0200
committerEugen Wissner <belka@caraus.de>2024-07-23 22:44:42 +0200
commit9d1f0385945e926e7084e60fc72fe5846e7139b2 (patch)
tree96bd319dc0dc26059ce3f42d5a91f84624fe3ea0 /lib/Language/Elna/Parser.hs
parent01398f48bf2d17a3836a5d5b5467d0fb05e3f337 (diff)
downloadelna-9d1f0385945e926e7084e60fc72fe5846e7139b2.tar.gz
Split in lib and tests
Diffstat (limited to 'lib/Language/Elna/Parser.hs')
-rw-r--r--lib/Language/Elna/Parser.hs107
1 files changed, 107 insertions, 0 deletions
diff --git a/lib/Language/Elna/Parser.hs b/lib/Language/Elna/Parser.hs
new file mode 100644
index 0000000..cd8f927
--- /dev/null
+++ b/lib/Language/Elna/Parser.hs
@@ -0,0 +1,107 @@
+module Language.Elna.Parser
+ ( Parser
+ , programP
+ ) where
+
+import Control.Monad (void)
+import Data.Text (Text)
+import qualified Data.Text as Text
+import Data.Void (Void)
+import Language.Elna.AST
+ ( Declaration(..)
+ , Identifier(..)
+ , Parameter(..)
+ , Program(..)
+ , TypeExpression(..)
+ , VariableDeclaration(..)
+ )
+import Text.Megaparsec (Parsec, (<?>), optional, between, sepBy)
+import Text.Megaparsec.Char (alphaNumChar, letterChar, space1)
+import qualified Text.Megaparsec.Char.Lexer as Lexer
+import Control.Applicative (Alternative(..))
+import Data.Maybe (isJust)
+
+type Parser = Parsec Void Text
+
+space :: Parser ()
+space = Lexer.space space1 (Lexer.skipLineComment "//")
+ $ Lexer.skipBlockComment "/*" "*/"
+
+lexeme :: forall a. Parser a -> Parser a
+lexeme = Lexer.lexeme space
+
+symbol :: Text -> Parser Text
+symbol = Lexer.symbol space
+
+blockP :: forall a. Parser a -> Parser a
+blockP = between (symbol "{") (symbol "}")
+
+procedureP :: Parser ()
+procedureP = void $ symbol "proc"
+
+parensP :: forall a. Parser a -> Parser a
+parensP = between (symbol "(") (symbol ")")
+
+openBracketP :: Parser ()
+openBracketP = void $ symbol "["
+
+closingBracketP :: Parser ()
+closingBracketP = void $ symbol "]"
+
+colonP :: Parser ()
+colonP = void $ symbol ":"
+
+semicolonP :: Parser ()
+semicolonP = void $ symbol ";"
+
+identifierP :: Parser Identifier
+identifierP =
+ let wordParser = (:) <$> letterChar <*> many alphaNumChar <?> "identifier"
+ in fmap Identifier $ lexeme $ Text.pack <$> wordParser
+
+typeExpressionP :: Parser TypeExpression
+typeExpressionP = arrayTypeExpression
+ <|> NamedType <$> identifierP
+ <?> "type expression"
+ where
+ arrayTypeExpression = flip ArrayType
+ <$> (symbol "array" *> openBracketP *> lexeme Lexer.decimal <* closingBracketP)
+ <*> (symbol "of" *> typeExpressionP)
+
+typeDefinitionP :: Parser Declaration
+typeDefinitionP = TypeDefinition
+ <$> (symbol "type" *> identifierP)
+ <*> (symbol "=" *> typeExpressionP)
+ <?> "type definition"
+
+variableDeclarationP :: Parser VariableDeclaration
+variableDeclarationP = VariableDeclaration
+ <$> (symbol "var" *> identifierP)
+ <*> (colonP *> typeExpressionP)
+ <* semicolonP
+ <?> "variable declaration"
+
+parameterP :: Parser Parameter
+parameterP = paramCons
+ <$> optional (symbol "ref")
+ <*> identifierP
+ <*> (colonP *> typeExpressionP)
+ where
+ paramCons ref name typeName = Parameter name typeName (isJust ref)
+
+parametersP :: Parser [Parameter]
+parametersP = parensP $ sepBy parameterP (symbol ",")
+
+procedureDefinitionP :: Parser Declaration
+procedureDefinitionP = ProcedureDefinition
+ <$> (procedureP *> identifierP)
+ <*> parametersP
+ <*> blockP (many variableDeclarationP)
+ <*> pure mempty -- TODO
+ <?> "procedure definition"
+
+declarationP :: Parser Declaration
+declarationP = typeDefinitionP <|> procedureDefinitionP
+
+programP :: Parser Program
+programP = Program <$> many declarationP