Skip to content

Commit

Permalink
add if
Browse files Browse the repository at this point in the history
  • Loading branch information
antonkesy committed Mar 11, 2024
1 parent 3cdff0b commit f82c21d
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 3 deletions.
5 changes: 5 additions & 0 deletions examples/control.mmm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
if 1 < 2 {
println("true");
} else {
println("false");
}
4 changes: 4 additions & 0 deletions src/AST.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ type Comment = String
data Type = IntType | FloatType | BoolType | UnitType | CustomType Name | StringType
deriving (Show, Eq)

data Control = IfControl Expression [Statement] (Maybe [Statement])
deriving (Show, Eq)

data Statement
= VariableStatement Variable
| AssignmentStatement Assignment
| FunctionDefinitionStatement Function
| ExpressionStatement Expression
| ReturnStatement Expression
| ControlStatement Control
deriving (Show, Eq)

data Function = Function Name [VariableDeclaration] Type [Statement]
Expand Down
28 changes: 28 additions & 0 deletions src/Interpreter/Interpreter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ interpretStatement (InterpretState state _) (FunctionDefinitionStatement _) = do
interpretStatement (InterpretState state _) (ReturnStatement expression) = do
ret <- interpretExpression state expression
return (InterpretState state (Just ret))
interpretStatement (InterpretState state _) (ControlStatement control) = do
interpretControl state control

updateState :: ProgramState -> Name -> Value -> ProgramState
updateState (ProgramState vars funs) name value = ProgramState (Map.insert name value vars) funs
Expand Down Expand Up @@ -106,4 +108,30 @@ interpretOperation Minus (FloatValue left) (FloatValue right) = FloatValue $ lef
interpretOperation Multiply (IntValue left) (IntValue right) = IntValue $ left * right
interpretOperation Multiply (FloatValue left) (FloatValue right) = FloatValue $ left * right
interpretOperation Divide (IntValue left) (IntValue right) = IntValue $ left `div` right
interpretOperation Lt (IntValue left) (IntValue right) = BoolValue $ left < right
interpretOperation Gt (IntValue left) (IntValue right) = BoolValue $ left > right
interpretOperation Le (IntValue left) (IntValue right) = BoolValue $ left <= right
interpretOperation Ge (IntValue left) (IntValue right) = BoolValue $ left >= right
interpretOperation Eq (IntValue left) (IntValue right) = BoolValue $ left == right
interpretOperation operator left right = error $ "Unsupported operation: " ++ show operator ++ " " ++ show left ++ " " ++ show right

interpretControl :: ProgramState -> Control -> IO InterpretState
interpretControl (ProgramState vars funs) (IfControl test body elseBody) = do
testValue <- interpretExpression (ProgramState vars funs) test
if not (isBoolValue testValue)
then do error "Control statement test must be a boolean value."
else do
if testValue == BoolValue True
then do
(InterpretState _ ret) <- foldM interpretStatement (InterpretState (ProgramState vars funs) Nothing) body
return $ InterpretState (ProgramState vars funs) ret
else do
case elseBody of
Just elseStatements -> do
(InterpretState _ ret) <- foldM interpretStatement (InterpretState (ProgramState vars funs) Nothing) elseStatements
return $ InterpretState (ProgramState vars funs) ret
Nothing -> return $ InterpretState (ProgramState vars funs) Nothing
where
isBoolValue :: Value -> Bool
isBoolValue (BoolValue _) = True
isBoolValue _ = False
1 change: 1 addition & 0 deletions src/Interpreter/Validator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ hasEntryPoint (Program statements) =
isMainFunction _ = False
isGlobalStatement (AssignmentStatement _) = True
isGlobalStatement (ExpressionStatement _) = True
isGlobalStatement (ControlStatement _) = True
isGlobalStatement _ = False

-- TODO: check no name clash with built-in functions
20 changes: 19 additions & 1 deletion src/Parser/Statement.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import Text.Parsec.String

parseStatement :: Parser Statement
parseStatement =
try parseReturnStatement
(ControlStatement <$> try (spaces' *> try parseControl))
<|> try parseReturnStatement
<|> (FunctionDefinitionStatement <$> try (spaces' *> try parseFunction))
<|> (VariableStatement <$> try (spaces' *> try parseVariable) <* endOfStatement)
<|> (AssignmentStatement <$> try (spaces' *> try parseAssignment) <* endOfStatement)
Expand Down Expand Up @@ -46,3 +47,20 @@ parseFunction = do
_ <- spaces'
statements <- manyTill (try parseStatement <* spaces') (spaces' *> char '}' <* spaces')
return $ Function name vars fnType statements

parseControl :: Parser Control
parseControl =
try parseIfControl

parseIfControl :: Parser Control
parseIfControl = do
_ <- spaces'
_ <- try (string "if")
test <- try (spaces1' *> parseExpression)
_ <- spaces1' *> char '{'
trueBlock <- spaces' *> many (try parseStatement)
_ <- spaces' *> char '}'
elseBlock <- optionMaybe (try (spaces' *> string "else" *> spaces' *> char '{' *> spaces' *> many parseStatement <* spaces' <* char '}'))
case elseBlock of
Nothing -> return $ IfControl test trueBlock Nothing
Just els -> return $ IfControl test trueBlock (Just els)
30 changes: 28 additions & 2 deletions test/Unit/Parser/Statement.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ allTests :: [Test]
allTests =
[ TestLabel "simple" testSimple,
TestLabel "functions" testFunctions,
TestLabel "return" testReturn
TestLabel "return" testReturn,
TestLabel "if" testIf
]

emptyTestStatement :: Statement
Expand Down Expand Up @@ -79,7 +80,7 @@ testFunctions = TestCase $ do
(fromRight emptyTestFunction (parse parseFunction "" "void main() { int i = 1; i = 2; }"))
assertEqual
"float test(int i, int k) { }"
( (Function "test" [VariableDeclaration "i" IntType, VariableDeclaration "k" IntType] FloatType [])
( Function "test" [VariableDeclaration "i" IntType, VariableDeclaration "k" IntType] FloatType []
)
(fromRight emptyTestFunction (parse parseFunction "" "float test(int i, int k) { }"))

Expand All @@ -105,3 +106,28 @@ testReturn = TestCase $ do
"return 1; -> statement"
(fromRight emptyTestStatement (parse parseReturnStatement "" "return 1;"))
(fromRight emptyTestStatement (parse parseStatement "" "return 1;"))

testIf :: Test
testIf = TestCase $ do
assertEqual
"empty"
False
(isRight (parse parseControl "" ""))
assertEqual
"if true {}"
(ControlStatement (IfControl (AtomicExpression (LiteralAtomic (BoolLiteral True))) [] Nothing))
(either (const emptyTestStatement) ControlStatement (parse parseControl "" "if true {}"))
assertEqual
"if true {} -> statement"
(either (const emptyTestStatement) ControlStatement (parse parseControl "" "if true {}"))
(fromRight emptyTestStatement (parse parseStatement "" "if true {}"))
assertEqual
"if true { return 0; } else { return 1; }"
( ControlStatement
( IfControl
(AtomicExpression (LiteralAtomic (BoolLiteral True)))
[ReturnStatement (AtomicExpression (LiteralAtomic (IntLiteral 0)))]
(Just [ReturnStatement (AtomicExpression (LiteralAtomic (IntLiteral 1)))])
)
)
(either (const emptyTestStatement) ControlStatement (parse parseControl "" "if true { return 0; } else { return 1; }"))

0 comments on commit f82c21d

Please sign in to comment.