Skip to content

Commit

Permalink
add basic builtin function
Browse files Browse the repository at this point in the history
  • Loading branch information
antonkesy committed Mar 7, 2024
1 parent 2c670ce commit f19766a
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 28 deletions.
3 changes: 2 additions & 1 deletion app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ developProgram :: String
developProgram =
-- "int i = 1; int j = 2; int l = 3 + 4; int k = i + j + l; k = k * 0;"
-- "void test(int i, int k) { }"
"int main() { int i = 1; int k = i + 1; }"
-- "int main() { print(); }"
"print()"

main :: IO ()
main = do
Expand Down
2 changes: 2 additions & 0 deletions peter.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ source-repository head
library
exposed-modules:
AST
Interpreter.BuiltIn
Interpreter.Interpreter
Interpreter.Validator
Parser.Assignment
Expand Down Expand Up @@ -75,6 +76,7 @@ test-suite peter-test
other-modules:
E2E.Placeholder
Unit.Parser.Assignment
Unit.Parser.Atomic
Unit.Parser.Comment
Unit.Parser.Expression
Unit.Parser.Program
Expand Down
25 changes: 25 additions & 0 deletions src/Interpreter/BuiltIn.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Interpreter.BuiltIn (module Interpreter.BuiltIn) where

import AST
import Data.Map.Strict as Map

-- import Text.Parsec
-- import Text.Parsec.String

-- printBuiltIn :: Parser Statement

data BuiltIn = BuiltIn Name [Type] Type ([Type] -> IO Type)

getAllBuiltIns :: Map String BuiltIn
getAllBuiltIns = Map.fromList [("print", printBuiltIn)]

printBuiltIn :: BuiltIn
printBuiltIn =
BuiltIn
"print"
[CustomType "String"]
UnitType
( \[CustomType "String"] -> do
putStrLn "Hello, World!"
pure UnitType
)
19 changes: 13 additions & 6 deletions src/Interpreter/Interpreter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Interpreter.Interpreter (module Interpreter.Interpreter) where
import AST
import Control.Monad (foldM)
import Data.Map.Strict as Map
import Interpreter.BuiltIn
import Interpreter.Validator

data Value = IntValue Int | FloatValue Float | BoolValue Bool | UnitValue
Expand Down Expand Up @@ -67,12 +68,18 @@ interpretAtomic (ProgramState vars _) (VariableAtomic name) = do
Just value -> value
Nothing -> error $ "Variable not found: " ++ name
interpretAtomic (ProgramState vars funs) (FunctionCallAtomic name _args) = do
let fun = Map.lookup name funs
case fun of
Just (FunctionDefinitionStatement (Function _ _ _ body)) -> do
_ <- foldM interpretStatement (ProgramState vars funs) body
return UnitValue -- TODO: add return values
Nothing -> error $ "Function not found: " ++ name
let isBuiltIn = Map.lookup name getAllBuiltIns
case isBuiltIn of
Just (BuiltIn _ args outputType fn) -> do
_ <- fn args
return UnitValue
Nothing -> do
let fun = Map.lookup name funs
case fun of
Just (FunctionDefinitionStatement (Function _ _ _ body)) -> do
_ <- foldM interpretStatement (ProgramState vars funs) body
return UnitValue -- TODO: add return values
Nothing -> error $ "Function not found: " ++ name

interpretLiteral :: Literal -> IO Value
interpretLiteral (IntLiteral value) = do
Expand Down
2 changes: 2 additions & 0 deletions src/Interpreter/Validator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ hasEntryPoint (Program statements) =
isGlobalStatement (AssignmentStatement _) = True
isGlobalStatement (ExpressionStatement _) = True
isGlobalStatement _ = False

-- TODO: check no name clash with built-in functions
12 changes: 5 additions & 7 deletions src/Parser/Atomic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ import Text.Parsec.String

parseAtomic :: Parser Atomic
parseAtomic =
LiteralAtomic
<$> parseLiteral
<|> VariableAtomic
<$> parseVariableName
<|> parseFunctionCallAtomic
(LiteralAtomic <$> try parseLiteral)
<|> try parseFunctionCallAtomic
<|> (VariableAtomic <$> try parseVariableName)

parseFunctionCallAtomic :: Parser Atomic
parseFunctionCallAtomic = do
name <- parseVariableName
name <- try parseVariableName
_ <- char '('
args <- parseAtomic `sepBy` (spaces' >> char ',' >> spaces')
args <- try (parseAtomic `sepBy` (spaces' >> char ',' >> spaces'))
_ <- char ')'
return $ FunctionCallAtomic name args
8 changes: 4 additions & 4 deletions src/Parser/Expression.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ parseExpression =
parseOperation :: Parser Expression
parseOperation =
do
left <- parseAtomicExpression -- left side has to be atomic to avoid endless loop becase of left recursion
left <- try parseAtomicExpression -- left side has to be atomic to avoid endless loop becase of left recursion
_ <- spaces'
op <- parseOperator
op <- try parseOperator
_ <- spaces'
OperationExpression left op <$> parseExpression
OperationExpression left op <$> try parseExpression

parseAtomicExpression :: Parser Expression
parseAtomicExpression = do
AtomicExpression <$> parseAtomic
AtomicExpression <$> try parseAtomic
2 changes: 2 additions & 0 deletions src/Parser/Statement.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import AST
import Control.Monad (void)
import Parser.Assignment
import Parser.EndOfLine
import Parser.Expression
import Parser.Space
import Parser.Type
import Parser.Variable
Expand All @@ -15,6 +16,7 @@ parseStatement =
( (VariableStatement <$> try (spaces' *> try parseVariable))
<|> (AssignmentStatement <$> try (spaces' *> try parseAssignment))
<|> (FunctionDefinitionStatement <$> try (spaces' *> try parseFunction))
<|> ExpressionStatement <$> try (spaces' *> try parseExpression)
)
<* spaces
<* endOfStatement
Expand Down
2 changes: 2 additions & 0 deletions test/Spec.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import E2E.Placeholder
import Test.HUnit (Test (TestList), runTestTTAndExit)
import Unit.Parser.Assignment
import Unit.Parser.Atomic
import Unit.Parser.Comment
import Unit.Parser.Expression
import Unit.Parser.Program
Expand All @@ -11,6 +12,7 @@ main =
runTestTTAndExit
( TestList
( Unit.Parser.Assignment.allTests
++ Unit.Parser.Atomic.allTests
++ Unit.Parser.Comment.allTests
++ Unit.Parser.Expression.allTests
++ Unit.Parser.Program.allTests
Expand Down
30 changes: 30 additions & 0 deletions test/Unit/Parser/Atomic.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module Unit.Parser.Atomic (allTests) where

import AST
import Data.Either (fromRight, isRight)
import Parser.Atomic
import Test.HUnit
import Text.Parsec (parse)

allTests :: [Test]
allTests =
[ TestLabel "simple" testSimple
]

emptyTestAtomic :: Atomic
emptyTestAtomic = (LiteralAtomic (UnitLiteral))

testSimple :: Test
testSimple = TestCase $ do
assertEqual
"empty"
False
(isRight (parse parseAtomic "" ""))
assertEqual
"Single Number"
(LiteralAtomic (IntLiteral 1))
(fromRight emptyTestAtomic (parse parseAtomic "" "1"))
assertEqual
"Function Call"
(FunctionCallAtomic "print" [])
(fromRight emptyTestAtomic (parse parseAtomic "" "print()"))
4 changes: 4 additions & 0 deletions test/Unit/Parser/Expression.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ testSimple = TestCase $ do
"Single Number"
(AtomicExpression (LiteralAtomic (IntLiteral 1)))
(fromRight emptyTestExpression (parse parseExpression "" "1"))
assertEqual
"Function Call"
(AtomicExpression (FunctionCallAtomic "print" []))
(fromRight emptyTestExpression (parse parseExpression "" "print()"))
16 changes: 12 additions & 4 deletions test/Unit/Parser/Program.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ testSimple = TestCase $ do
True
(isRight (parse parseProgram "" ""))
assertEqual
"Single variable statement"
"int k = 1;"
( Program
[ VariableStatement
( Variable
Expand All @@ -33,7 +33,7 @@ testSimple = TestCase $ do
)
(fromRight emptyProgram (parse parseProgram "" "int k = 1;"))
assertEqual
"Multiple variable statements"
"int k = 1; int j = 2;"
( Program
[ VariableStatement
( Variable
Expand All @@ -51,7 +51,7 @@ testSimple = TestCase $ do
)
(fromRight emptyProgram (parse parseProgram "" "int k = 1; int j = 2;"))
assertEqual
"Single assignment statement"
"k = 1;"
( Program
[ AssignmentStatement
( Assignment
Expand All @@ -63,7 +63,7 @@ testSimple = TestCase $ do
)
(fromRight emptyProgram (parse parseProgram "" "k = 1;"))
assertEqual
"variable statement and assignment statement"
"int k = 1; j = 2;"
( Program
[ VariableStatement
( Variable
Expand All @@ -80,3 +80,11 @@ testSimple = TestCase $ do
]
)
(fromRight emptyProgram (parse parseProgram "" "int k = 1; j = 2;"))
assertEqual
"print();"
( Program
[ ExpressionStatement
(AtomicExpression (FunctionCallAtomic "print" []))
]
)
(fromRight emptyProgram (parse parseProgram "" "print();"))
16 changes: 10 additions & 6 deletions test/Unit/Parser/Statement.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ testSimple = TestCase $ do
False
(isRight (parse parseStatement "" ""))
assertEqual
"var defintion"
"int i = 1;"
(VariableStatement (Variable (VariableDeclaration "i" IntType) (AtomicExpression (LiteralAtomic (IntLiteral 1)))))
(fromRight emptyTestStatement (parse parseStatement "" "int i = 1;"))
assertEqual
"var assignment literal number"
"k = 2;"
(AssignmentStatement (Assignment "k" (AtomicExpression (LiteralAtomic (IntLiteral 2)))))
(fromRight emptyTestStatement (parse parseStatement "" "k = 2;"))
assertEqual
"var assignment with var and number"
"k = k * 1;"
( AssignmentStatement
( Assignment
"k"
Expand All @@ -47,6 +47,10 @@ testSimple = TestCase $ do
)
)
(fromRight emptyTestStatement (parse parseStatement "" "k = k * 1;"))
assertEqual
"print();"
(ExpressionStatement (AtomicExpression (FunctionCallAtomic "print" [])))
(fromRight emptyTestStatement (parse parseStatement "" "print();"))

emptyTestFunction :: Function
emptyTestFunction = Function "TEST" [] IntType []
Expand All @@ -58,11 +62,11 @@ testFunctions = TestCase $ do
False
(isRight (parse parseFunction "" ""))
assertEqual
"empty main function"
"void main() { }"
(Function "main" [] UnitType [])
(fromRight emptyTestFunction (parse parseFunction "" "void main() { }"))
assertEqual
"main function"
"void main() { int i = 1; i = 2; }"
( Function
"main"
[]
Expand All @@ -73,7 +77,7 @@ testFunctions = TestCase $ do
)
(fromRight emptyTestFunction (parse parseFunction "" "void main() { int i = 1; i = 2; }"))
assertEqual
"function with arguments"
"float test(int i, int k) { }"
( (Function "test" [VariableDeclaration "i" IntType, VariableDeclaration "k" IntType] FloatType [])
)
(fromRight emptyTestFunction (parse parseFunction "" "float test(int i, int k) { }"))

0 comments on commit f19766a

Please sign in to comment.