module Parser.Statement (parseALL, pStatement) where
import Text.Megaparsec
import qualified Data.Text as DT
import Text.Megaparsec.Char (char)
import qualified Text.Megaparsec.Char.Lexer as L
import AST.Ast (Ast(..))
import Parser.Lexer
import Parser.Expression (pExpr)
import Data.Void (Void)
import Parser.Conditions (pIf, pWhile, pFor)
import Data.Char (ord)
import Common.Type.Integer (IntValue(..))
data Accessor
= AccIndex Ast
| AccField DT.Text
pListType :: Parser DT.Text
pListType :: Parser Text
pListType = do
_ <- Text -> Parser Text
symbol (String -> Text
DT.pack String
"[")
innerType <- pType
_ <- symbol (DT.pack "]")
return (DT.pack "[" <> innerType <> DT.pack "]")
pType :: Parser DT.Text
pType :: Parser Text
pType = [Parser Text] -> Parser Text
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice
[ Parser Text
pListType
, Parser Text -> Parser Text
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"int"))
, Parser Text -> Parser Text
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"bool"))
, Parser Text -> Parser Text
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"void"))
, Parser Text
pIdentifier
] Parser Text -> String -> Parser Text
forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"type"
pArgDeclaration :: Parser (DT.Text, DT.Text)
pArgDeclaration :: Parser (Text, Text)
pArgDeclaration = do
name <- Parser Text
pIdentifier
maybeType <- optional (colon >> pType)
let finalType = case Maybe Text
maybeType of
Just Text
t -> Text
t
Maybe Text
Nothing -> String -> Text
DT.pack String
"auto"
return (name, finalType)
pReturn :: Parser Ast
pReturn :: Parser Ast
pReturn = do
_ <- Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"ret")
val <- pExpr
_ <- semicolon
return (AReturn val)
pBlock :: Parser Ast
pBlock :: Parser Ast
pBlock = Parser Ast -> Parser Ast
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
braces (Parser Ast -> Parser Ast) -> Parser Ast -> Parser Ast
forall a b. (a -> b) -> a -> b
$ do
stmts <- Parser Ast -> ParsecT Void Text Identity [Ast]
forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
many Parser Ast
pStatement
case stmts of
[] -> Ast -> Parser Ast
forall a. a -> ParsecT Void Text Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return Ast
AVoid
[Ast]
xs -> Ast -> Parser Ast
forall a. a -> ParsecT Void Text Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Ast] -> Ast
ABlock [Ast]
xs)
pFunc :: Parser Ast
pFunc :: Parser Ast
pFunc = do
_ <- Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"func")
name <- pIdentifier
args <- parens (pArgDeclaration `sepBy` comma)
maybeRetType <- optional (symbol (DT.pack "->") >> pType)
let retType = case Maybe Text
maybeRetType of
Just Text
t -> Text
t
Maybe Text
Nothing -> String -> Text
DT.pack String
"Void"
body <- pBlock
return (ADefineFunc name args retType body)
makeOpCall :: DT.Text -> DT.Text -> Ast -> Ast
makeOpCall :: Text -> Text -> Ast -> Ast
makeOpCall Text
op Text
name Ast
expr = Ast -> [Ast] -> Ast
ACall (Text -> Ast
ASymbol Text
op) [Text -> Ast
ASymbol Text
name, Ast
expr]
pAssignOp :: DT.Text -> Parser (Ast -> Ast)
pAssignOp :: Text -> Parser (Ast -> Ast)
pAssignOp Text
name = [Parser (Ast -> Ast)] -> Parser (Ast -> Ast)
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice
[ (\Ast
e -> Ast
e) (Ast -> Ast) -> Parser Text -> Parser (Ast -> Ast)
forall a b.
a -> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
symbol (String -> Text
DT.pack String
"=")
, Text -> Text -> Ast -> Ast
makeOpCall (String -> Text
DT.pack String
"+") Text
name (Ast -> Ast) -> Parser Text -> Parser (Ast -> Ast)
forall a b.
a -> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
symbol (String -> Text
DT.pack String
"+=")
, Text -> Text -> Ast -> Ast
makeOpCall (String -> Text
DT.pack String
"-") Text
name (Ast -> Ast) -> Parser Text -> Parser (Ast -> Ast)
forall a b.
a -> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
symbol (String -> Text
DT.pack String
"-=")
, Text -> Text -> Ast -> Ast
makeOpCall (String -> Text
DT.pack String
"*") Text
name (Ast -> Ast) -> Parser Text -> Parser (Ast -> Ast)
forall a b.
a -> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
symbol (String -> Text
DT.pack String
"*=")
, Text -> Text -> Ast -> Ast
makeOpCall (String -> Text
DT.pack String
"div") Text
name (Ast -> Ast) -> Parser Text -> Parser (Ast -> Ast)
forall a b.
a -> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
symbol (String -> Text
DT.pack String
"/=")
, Text -> Text -> Ast -> Ast
makeOpCall (String -> Text
DT.pack String
"mod") Text
name (Ast -> Ast) -> Parser Text -> Parser (Ast -> Ast)
forall a b.
a -> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Text -> Parser Text
symbol (String -> Text
DT.pack String
"%=")
]
fieldToAst :: DT.Text -> Ast
fieldToAst :: Text -> Ast
fieldToAst Text
txt = [Ast] -> Ast
AList ([Ast] -> Ast) -> [Ast] -> Ast
forall a b. (a -> b) -> a -> b
$ (Char -> Ast) -> String -> [Ast]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Ast
charToAst (Text -> String
DT.unpack Text
txt)
where
charToAst :: Char -> Ast
charToAst Char
c = IntValue -> Ast
AInteger (Int8 -> IntValue
IChar (Int -> Int8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
ord Char
c)))
recursiveUpdate :: Ast -> [Accessor] -> Ast -> Ast
recursiveUpdate :: Ast -> [Accessor] -> Ast -> Ast
recursiveUpdate Ast
base [AccIndex Ast
idx] Ast
val =
Ast -> [Ast] -> Ast
ACall (Text -> Ast
ASymbol (String -> Text
DT.pack String
"nth_update")) [Ast
base, Ast
idx, Ast
val]
recursiveUpdate Ast
base [AccField Text
field] Ast
val =
Ast -> [Ast] -> Ast
ACall (Text -> Ast
ASymbol (String -> Text
DT.pack String
"attr_update")) [Ast
base, Text -> Ast
fieldToAst Text
field, Ast
val]
recursiveUpdate Ast
base (AccIndex Ast
idx : [Accessor]
rest) Ast
val =
let inner :: Ast
inner = Ast -> [Ast] -> Ast
ACall (Text -> Ast
ASymbol (String -> Text
DT.pack String
"nth")) [Ast
base, Ast
idx]
newVal :: Ast
newVal = Ast -> [Accessor] -> Ast -> Ast
recursiveUpdate Ast
inner [Accessor]
rest Ast
val
in Ast -> [Ast] -> Ast
ACall (Text -> Ast
ASymbol (String -> Text
DT.pack String
"nth_update")) [Ast
base, Ast
idx, Ast
newVal]
recursiveUpdate Ast
base (AccField Text
field : [Accessor]
rest) Ast
val =
let inner :: Ast
inner = Ast -> Text -> Ast
AAccessStruct Ast
base Text
field
newVal :: Ast
newVal = Ast -> [Accessor] -> Ast -> Ast
recursiveUpdate Ast
inner [Accessor]
rest Ast
val
in Ast -> [Ast] -> Ast
ACall (Text -> Ast
ASymbol (String -> Text
DT.pack String
"attr_update"))
[Ast
base, Text -> Ast
fieldToAst Text
field, Ast
newVal]
recursiveUpdate Ast
_ [] Ast
_ = String -> Ast
forall a. HasCallStack => String -> a
error String
"Should not happen in buildUpdateChain"
buildUpdateChain :: DT.Text -> [Accessor] -> Ast -> Ast
buildUpdateChain :: Text -> [Accessor] -> Ast -> Ast
buildUpdateChain Text
name [Accessor]
accessors Ast
finalVal =
Ast -> [Accessor] -> Ast -> Ast
recursiveUpdate (Text -> Ast
ASymbol Text
name) [Accessor]
accessors Ast
finalVal
pSimpleDef :: DT.Text -> Parser Ast
pSimpleDef :: Text -> Parser Ast
pSimpleDef Text
name = do
varType <- Parser Text -> ParsecT Void Text Identity (Maybe Text)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (Text -> Parser Text
symbol (String -> Text
DT.pack String
":") Parser Text -> Parser Text -> Parser Text
forall a b.
ParsecT Void Text Identity a
-> ParsecT Void Text Identity b -> ParsecT Void Text Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser Text
pType)
makeValue <- pAssignOp name
val <- pExpr
_ <- semicolon <?> "\";\" at the end of statement"
let finalType = Text -> (Text -> Text) -> Maybe Text -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Text
DT.pack String
"auto") Text -> Text
forall a. a -> a
id Maybe Text
varType
return (ASetVar name finalType (makeValue val))
pComplexUpdate :: DT.Text -> [Accessor] -> Parser Ast
pComplexUpdate :: Text -> [Accessor] -> Parser Ast
pComplexUpdate Text
name [Accessor]
accessors = do
_ <- Text -> Parser Text
symbol (String -> Text
DT.pack String
"=")
val <- pExpr
_ <- semicolon
let updateExpr = Text -> [Accessor] -> Ast -> Ast
buildUpdateChain Text
name [Accessor]
accessors Ast
val
return (ASetVar name (DT.pack "auto") updateExpr)
pAccIndex :: Parser Accessor
pAccIndex :: Parser Accessor
pAccIndex = do
_ <- Text -> Parser Text
symbol (String -> Text
DT.pack String
"[")
expr <- pExpr
_ <- symbol (DT.pack "]")
return (AccIndex expr)
pAccField :: Parser Accessor
pAccField :: Parser Accessor
pAccField = do
_ <- Text -> Parser Text
symbol (String -> Text
DT.pack String
".")
field <- pIdentifier
return (AccField field)
pVarDef :: Parser Ast
pVarDef :: Parser Ast
pVarDef = do
name <- Parser Text
pIdentifier
accessors <- many (pAccIndex <|> pAccField)
if null accessors
then pSimpleDef name
else pComplexUpdate name accessors
pStructField :: Parser (DT.Text, DT.Text)
pStructField :: Parser (Text, Text)
pStructField = do
name <- Parser Text
pIdentifier
_ <- colon
fType <- pType
_ <- semicolon
return (name, fType)
pStruct :: Parser Ast
pStruct :: Parser Ast
pStruct = do
_ <- Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"struct")
name <- pIdentifier
fields <- braces (many pStructField)
return (ADefineStruct name fields)
pImportPath :: Parser DT.Text
pImportPath :: Parser Text
pImportPath = Parser Text -> Parser Text
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
lexeme (Parser Text -> Parser Text) -> Parser Text -> Parser Text
forall a b. (a -> b) -> a -> b
$ do
_ <- Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token Text
'"'
content <- manyTill L.charLiteral (char '"')
return (DT.pack content)
pImport :: Parser Ast
pImport :: Parser Ast
pImport = do
_ <- Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"import")
path <- pImportPath
_ <- semicolon
return (AImport path)
pControlFlow :: [Parser Ast]
pControlFlow :: [Parser Ast]
pControlFlow =
[ Parser Ast -> Parser Ast
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Parser Ast -> Parser Ast -> Parser Ast
pIf Parser Ast
pVarDef Parser Ast
pBlock)
, Parser Ast -> Parser Ast
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Parser Ast -> Parser Ast
pWhile Parser Ast
pBlock)
, Parser Ast -> Parser Ast
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try (Parser Ast -> Parser Ast -> Parser Ast
pFor Parser Ast
pVarDef Parser Ast
pBlock)
]
pDeclarations :: [Parser Ast]
pDeclarations :: [Parser Ast]
pDeclarations =
[ Parser Ast
pImport
, Parser Ast
pStruct
, Parser Ast
pFunc
]
pVarDefStmt :: Parser Ast
pVarDefStmt :: Parser Ast
pVarDefStmt = do
stmt <- Parser Ast
pVarDef
return (AExprStmt stmt)
pExprStatement :: Parser Ast
pExprStatement :: Parser Ast
pExprStatement = do
expr <- Parser Ast
pExpr
_ <- semicolon <?> "\";\" after expression"
return (AExprStmt expr)
pBreak :: Parser Ast
pBreak :: Parser Ast
pBreak = do
_ <- Text -> Parser Text
pKeyword (String -> Text
DT.pack String
"break")
_ <- semicolon
return (AExprStmt ABreak)
pBasic :: [Parser Ast]
pBasic :: [Parser Ast]
pBasic =
[ Parser Ast
pReturn
, Parser Ast
pBreak
, Parser Ast -> Parser Ast
forall a.
ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m a
try Parser Ast
pVarDefStmt
, Parser Ast
pExprStatement
]
pStatement :: Parser Ast
pStatement :: Parser Ast
pStatement = Parser Ast -> Parser Ast
withPos (Parser Ast -> Parser Ast) -> Parser Ast -> Parser Ast
forall a b. (a -> b) -> a -> b
$ [Parser Ast] -> Parser Ast
forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, Alternative m) =>
f (m a) -> m a
choice ([Parser Ast]
pControlFlow [Parser Ast] -> [Parser Ast] -> [Parser Ast]
forall a. [a] -> [a] -> [a]
++ [Parser Ast]
pDeclarations [Parser Ast] -> [Parser Ast] -> [Parser Ast]
forall a. [a] -> [a] -> [a]
++ [Parser Ast]
pBasic)
parseALL :: DT.Text -> Either (ParseErrorBundle DT.Text Void) [Ast]
parseALL :: Text -> Either (ParseErrorBundle Text Void) [Ast]
parseALL = ParsecT Void Text Identity [Ast]
-> String -> Text -> Either (ParseErrorBundle Text Void) [Ast]
forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
parse (Parser ()
sc Parser ()
-> ParsecT Void Text Identity [Ast]
-> ParsecT Void Text Identity [Ast]
forall a b.
ParsecT Void Text Identity a
-> ParsecT Void Text Identity b -> ParsecT Void Text Identity b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser Ast -> ParsecT Void Text Identity [Ast]
forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
many Parser Ast
pStatement ParsecT Void Text Identity [Ast]
-> Parser () -> ParsecT Void Text Identity [Ast]
forall a b.
ParsecT Void Text Identity a
-> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ()
forall e s (m :: * -> *). MonadParsec e s m => m ()
eof) String
"ParseALL"