diff --git a/lvtc/lvtc.cabal b/lvtc/lvtc.cabal new file mode 100644 index 0000000..bf73442 --- /dev/null +++ b/lvtc/lvtc.cabal @@ -0,0 +1,102 @@ +cabal-version: 2.2 + +-- This file has been generated from package.yaml by hpack version 0.36.0. +-- +-- see: https://github.com/sol/hpack + +name: lvtc +version: 0.1.0.0 +description: Please see the README on GitHub at +homepage: https://github.com/githubuser/lvtc#readme +bug-reports: https://github.com/githubuser/lvtc/issues +author: Author name here +maintainer: example@example.com +copyright: 2023 Author name here +license: BSD-3-Clause +license-file: LICENSE +build-type: Simple +extra-source-files: + README.md + CHANGELOG.md + +source-repository head + type: git + location: https://github.com/githubuser/lvtc + +library + exposed-modules: + Alias + AST + Builtins + Expression + Leb128Encode + Lexeme + Lib + LvtLibVersion + ParseLvt + Parser + ParseUtil + ShuntingYard + TypeCheck + Wasm + WasmUtils + WatAST + WatLike + WatLikeToWat + WatToWasm + WriteWasm + other-modules: + Paths_lvtc + autogen-modules: + Paths_lvtc + hs-source-dirs: + src + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints + build-depends: + base >=4.7 && <5 + , bytestring + default-language: Haskell2010 + +executable lvtc-exe + main-is: Main.hs + other-modules: + Args + Run + Version + Paths_lvtc + autogen-modules: + Paths_lvtc + hs-source-dirs: + app + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N + build-depends: + base >=4.7 && <5 + , directory + , filepath + , lvtc + default-language: Haskell2010 + +test-suite lvtc-test + type: exitcode-stdio-1.0 + main-is: Spec.hs + other-modules: + UTLexeme + UTParseLvt + UTShuntingYard + UTTypeCheck + UTWasm + UTWat + UTWatLike + Paths_lvtc + autogen-modules: + Paths_lvtc + hs-source-dirs: + test + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N + build-depends: + base >=4.7 && <5 + , lvtc + , process + , tasty + , tasty-hunit + default-language: Haskell2010 diff --git a/lvtc/src/TypeCheck.hs b/lvtc/src/TypeCheck.hs index dd536f8..9a2f09d 100644 --- a/lvtc/src/TypeCheck.hs +++ b/lvtc/src/TypeCheck.hs @@ -10,7 +10,6 @@ module TypeCheck ) where import AST -import Debug.Trace data Env = Env FuncPrototype [VarAssignation] [FuncPrototype] @@ -26,11 +25,12 @@ findVarInVar s ((s', v):xs) env | s == s' = findValueType v env | otherwise = findVarInVar s xs env -findTypeReturnFunc :: Symbol -> [FuncPrototype] -> Maybe FuncPrototype -findTypeReturnFunc _ [] = Nothing -findTypeReturnFunc s ((s', ps, t):xs) - | s == s' = Just (s', ps, t) - | otherwise = findTypeReturnFunc s xs +findTypeReturnFunc :: Symbol -> Env -> Maybe FuncPrototype +findTypeReturnFunc s (Env (e, s', ps, t) _ _) | s == s' = Just (e, s', ps, t) +findTypeReturnFunc _ (Env _ _ []) = Nothing +findTypeReturnFunc s (Env proto vars ((e, s', ps, t):xs)) + | s == s' = Just (e, s', ps, t) + | otherwise = findTypeReturnFunc s (Env proto vars xs) getValueType :: Value -> Maybe Type getValueType (Integer _) = Just "Int" @@ -40,20 +40,22 @@ getValueType _ = Nothing checkFuncType :: [Value] -> Env -> Maybe FuncPrototype -> Maybe Type checkFuncType _ _ Nothing = Nothing -checkFuncType [] _ _ = Nothing -checkFuncType callParams (Env proto params env) (Just (_, ps, t)) +checkFuncType callParams (Env proto params env) (Just (_, _, ps, t)) | checkVarsTypes callParams (Just ps) (Env proto params env) = Just t | otherwise = Nothing handleFinders :: Maybe Type -> Symbol -> Env -> Maybe Type -handleFinders _ _ (Env (_, [], _) [] _) = Nothing -handleFinders Nothing s (Env proto vars env) = findVarInVar s vars (Env proto vars env) +handleFinders _ _ (Env (_, _, [], _) [] _) = Nothing +handleFinders Nothing s (Env proto vars env) = + findVarInVar s vars (Env proto vars env) handleFinders (Just t) _ _ = Just t findValueType :: Value -> Env -> Maybe Type -findValueType (Var s) (Env (ps, params, t) vars env) = - handleFinders (findVarInParams s params (Env (ps, params, t) vars env)) s (Env (ps, params, t) vars env) -findValueType (FuncValue (s, vs)) (Env proto vars env) = checkFuncType vs (Env proto vars env) (findTypeReturnFunc s env) +findValueType (Var s) (Env (e, ps, params, t) vars env) = + handleFinders (findVarInParams s params (Env (e, ps, params, t) vars env)) + s (Env (e, ps, params, t) vars env) +findValueType (FuncValue (s, vs)) env = + checkFuncType vs env (findTypeReturnFunc s env) findValueType v _ = getValueType v checkValueType :: Type -> Maybe Type -> Bool @@ -61,22 +63,21 @@ checkValueType _ Nothing = False checkValueType t (Just t') = t == t' assertTypeAndValue :: Type -> Value -> Env -> Bool -assertTypeAndValue _ (Var _) (Env (_, [], _) [] _) = False -assertTypeAndValue _ (FuncValue _) (Env (_, _, _) _ []) = False +assertTypeAndValue _ (Var _) (Env (_, _, [], _) [] _) = False assertTypeAndValue t v env = checkValueType t (findValueType v env) assertMTypeAndValue :: Maybe Type -> Value -> Env -> Bool assertMTypeAndValue Nothing _ _ = False assertMTypeAndValue (Just t) v env = assertTypeAndValue t v env -sFu + isTypeValid :: Type -> Bool isTypeValid "Int" = True isTypeValid "Bool" = True isTypeValid _ = False checkVarsTypes :: [Value] -> Maybe [Var] -> Env -> Bool -checkVarsTypes [] _ _ = False checkVarsTypes _ Nothing _ = False +checkVarsTypes [] (Just []) _ = True checkVarsTypes values (Just param) _ | length values /= length param = False checkVarsTypes [v] (Just [(_, t)]) env = assertTypeAndValue t v env checkVarsTypes (v:vs) (Just ((_, t):xs)) env @@ -86,30 +87,48 @@ checkVarsTypes _ _ _ = False findFunc :: Symbol -> [FuncPrototype] -> Maybe [Var] findFunc _ [] = Nothing -findFunc s ((s', params, _):_) | s == s' = Just params +findFunc s ((_, s', params, _):_) | s == s' = Just params findFunc s (_:xs) = findFunc s xs checkCall :: FuncCall -> Env -> [Instruction] -> Bool -checkCall (symbol, values) (Env (s, params, t) vars env) xs - | s == symbol && checkVarsTypes values (Just params) (Env (s, params, t) vars env) || - checkVarsTypes values (findFunc symbol env) (Env (s, params, t) vars env) = - checkInstructions xs (Env (s, params, t) vars env) +checkCall (symbol, values) (Env (e, s, params, t) vars env) xs + | s == symbol && + checkVarsTypes values (Just params) (Env (e, s, params, t) vars env) || + checkVarsTypes values (findFunc symbol env) + (Env (e, s, params, t) vars env) = + checkInstructions xs (Env (e, s, params, t) vars env) | otherwise = False checkReturn :: Value -> Env -> [Instruction] -> Bool -checkReturn v (Env (s, params, t) vars env) xs - | assertTypeAndValue t v (Env (s, params, t) vars env) = - checkInstructions xs (Env (s, params, t) vars env) +checkReturn v (Env (e, s, params, t) vars env) xs + | assertTypeAndValue t v (Env (e, s, params, t) vars env) = + checkInstructions xs (Env (e, s, params, t) vars env) checkReturn _ _ _ = False +findInVar :: Symbol -> [Var] -> Bool +findInVar _ [] = False +findInVar s ((s', _):_) | s == s' = True +findInVar s (_:xs) = findInVar s xs + +searchName :: Symbol -> [VarAssignation] -> [Var] -> Bool +searchName s [] vars = findInVar s vars +searchName s ((s', _):_) _ | s == s' = True +searchName s (_:xs) params = searchName s xs params + +nameExist :: Symbol -> FuncPrototype -> [VarAssignation] -> Bool +nameExist s (_, s', _, _) _ | s == s' = True +nameExist s (_, _, params, _) vs = searchName s vs params + checkDeclaration :: VarDeclaration -> Env -> [Instruction] -> Bool -checkDeclaration ((s, t), v) (Env proto vars env) xs | - assertTypeAndValue t v (Env proto vars env) = - checkInstructions xs (Env proto ((s, v):vars) env) +checkDeclaration ((s, t), v) (Env proto vars env) xs + | not (nameExist s proto vars) && + assertTypeAndValue t v (Env proto vars env) = + checkInstructions xs (Env proto ((s, v):vars) env) checkDeclaration _ _ _ = False checkAssignation :: VarAssignation -> Env -> [Instruction] -> Bool -checkAssignation (s, v) env xs | assertMTypeAndValue (findValueType (Var s) env) v env = +checkAssignation (s, v) env xs | + assertMTypeAndValue (findValueType (Var s) env) v env = checkInstructions xs env checkAssignation _ _ _ = False @@ -121,32 +140,36 @@ checkCondition _ _ _ = False checkInstructions :: [Instruction] -> Env -> Bool checkInstructions [] _ = True -checkInstructions ((Call func):xs) env = checkCall func env xs +checkInstructions ((Function func):xs) env = checkCall func env xs checkInstructions ((Return ret):xs) env = checkReturn ret env xs -checkInstructions ((Declaration declaration):xs) env = checkDeclaration declaration env xs -checkInstructions ((Assignation assignation):xs) env = checkAssignation assignation env xs +checkInstructions ((Declaration declaration):xs) env = + checkDeclaration declaration env xs +checkInstructions ((Assignation assignation):xs) env = + checkAssignation assignation env xs checkInstructions ((Cond condition):xs) env = checkCondition condition env xs checkVarTypes :: [Var] -> Bool checkVarTypes [] = True checkVarTypes [x] = isTypeValid (snd x) checkVarTypes (x:xs) | isTypeValid (snd x) = checkVarTypes xs +checkVarTypes _ = False checkFunction :: FuncDeclaration -> [FuncPrototype] -> Bool -checkFunction ((_, args, _), _) _ | not (checkVarTypes args) = False -checkFunction ((_, _, t), _) _ | not (isTypeValid t) = False +checkFunction ((_, _, args, _), _) _ | not (checkVarTypes args) = False +checkFunction ((_, _, _, t), _) _ | not (isTypeValid t) = False checkFunction (prototype, instructions) env | checkInstructions instructions (Env prototype [] env) = True checkFunction _ _ = False checkNotExisting :: FuncDeclaration -> [FuncPrototype] -> Bool checkNotExisting _ [] = True -checkNotExisting ((s, args, t), instr) ((ls, _, _):xs) +checkNotExisting ((e, s, args, t), instr) ((_, ls, _, _):xs) | s == ls = False - | otherwise = checkNotExisting ((s, args, t), instr) xs + | otherwise = checkNotExisting ((e, s, args, t), instr) xs receiveCheckFuncRes :: Bool -> [FuncDeclaration] -> FuncDeclaration -> [FuncPrototype] -> Bool -receiveCheckFuncRes True xs (prototype, _) env = checkDeclarations xs (Just (prototype:env)) +receiveCheckFuncRes True xs (prototype, _) env = + checkDeclarations xs (Just (prototype:env)) receiveCheckFuncRes _ _ _ _ = False checkDeclarations :: [FuncDeclaration] -> Maybe [FuncPrototype] -> Bool @@ -158,14 +181,15 @@ checkDeclarations (func:xs) (Just env) | otherwise = False createCalcPrototype :: Symbol -> Type -> FuncPrototype -createCalcPrototype s t = (s, [("x", t), ("y", t)], "Int") +createCalcPrototype s t = (False, s, [("x", t), ("y", t)], "Int") createCompPrototype :: Symbol -> Type -> FuncPrototype -createCompPrototype s t = (s, [("x", t), ("y", t)], "Bool") +createCompPrototype s t = (False, s, [("x", t), ("y", t)], "Bool") createCompPolyMorph :: Symbol -> [Type] -> [FuncPrototype] createCompPolyMorph _ [] = [] -createCompPolyMorph s (x:xs) = createCompPrototype s x : createCompPolyMorph s xs +createCompPolyMorph s (x:xs) = + createCompPrototype s x : createCompPolyMorph s xs createCompOp :: [Symbol] -> [FuncPrototype] createCompOp [] = [] @@ -176,7 +200,8 @@ createCalcOp [] = [] createCalcOp (x:xs) = createCalcPrototype x "Int" : createCalcOp xs defaultEnv :: Maybe [FuncPrototype] -defaultEnv = Just (createCalcOp ["+", "-", "*", "%", "/"] ++ createCompOp ["==", "!=", "<", ">", "<=", ">="]) +defaultEnv = Just (createCalcOp ["+", "-", "*", "%", "/"] ++ + createCompOp ["==", "!=", "<", ">", "<=", ">="]) typeCheck :: [FuncDeclaration] -> Bool typeCheck expressions = checkDeclarations expressions defaultEnv diff --git a/lvtc/test/Spec.hs b/lvtc/test/Spec.hs index 9e5229b..e106fca 100644 --- a/lvtc/test/Spec.hs +++ b/lvtc/test/Spec.hs @@ -18,6 +18,7 @@ import UTWatLike import UTWat import UTWasm import UTLexeme +import UTTypeCheck main :: IO () main = defaultMain tests @@ -33,7 +34,8 @@ tests = testGroup "Leviator Tests - Compiler" utWatLike, utWat, utWasm, - utLexeme + utLexeme, + uTTypeCheck ] testParserHelper :: String -> String -> Expression -> IO () diff --git a/lvtc/test/UTTypeCheck.hs b/lvtc/test/UTTypeCheck.hs new file mode 100644 index 0000000..b85efad --- /dev/null +++ b/lvtc/test/UTTypeCheck.hs @@ -0,0 +1,64 @@ +{- +-- EPITECH PROJECT, 2023 +-- Leviator compiler +-- File description: +-- UTShuntingYard +-} + +module UTTypeCheck ( + uTTypeCheck +) where + +import Test.Tasty +import Test.Tasty.HUnit +import AST +import TypeCheck + +uTTypeCheck :: TestTree +uTTypeCheck = testGroup "typeCheck tests" + [testReturn, testFuncCall, testVars] + +testReturn :: TestTree +testReturn = testGroup "testReturn" + [ + testCase "testReturn" (shouldBeTrue + [((True, "main", [], "Int"), ([Return (Integer 0)]))]), + testCase "testWrongReturnType" (shouldBeFalse + [((True, "main", [], "Int"), ([Return (Boolean True)]))]), + testCase "test return param" (shouldBeFalse + [((True, "main", [("a", "Int"), ("b", "Bool")], "Int"), [Return (Var "b")])]) + ] + +testFuncCall :: TestTree +testFuncCall = testGroup "testFuncCall" + [ + testCase "test recursive" (shouldBeTrue + [((True, "main", [], "Int"), [Return (FuncValue ("main", []))])]), + testCase "test return wrong type" (shouldBeFalse + [((True, "main", [], "Int"), [Return (Integer 0)]), ((True, "snd", [], "Bool"), [Return (FuncValue ("main", []))])]), + testCase "test call with params" (shouldBeTrue + [((True, "main", [("a", "Int"), ("b", "Bool")], "Int"), [Return (Var "a")]), ((True, "snd", [], "Int"), [Return (FuncValue ("main", [(Integer 0), (Boolean True)]))])]), + testCase "test call with wrongs params" (shouldBeFalse + [((True, "main", [("a", "Int"), ("b", "Bool")], "Int"), [Return (Var "a")]), ((True, "snd", [], "Int"), [Return (FuncValue ("main", [(Integer 0), (Integer 2)]))])]) + ] + +testVars :: TestTree +testVars = testGroup "testVars" + [ + testCase "test vars" (shouldBeTrue + [((True, "main", [], "Int"), [Declaration (("a", "Int"), Integer 0), Assignation ("a", (FuncValue ("+", [(Var "a"), (Integer 1)]))), Return (Var "a")])]), + testCase "test params" (shouldBeTrue + [((True, "main", [("a", "Int")], "Int"), [Assignation ("a", (FuncValue ("+", [(Var "a"), (Integer 1)]))), Return (Var "a")])]), + testCase "test params" (shouldBeTrue + [((True, "main", [("a", "Int")], "Int"), [Declaration (("b", "Int"), (Var "a")), Declaration (("c", "Int"), (Var "b")), Return (Var "c")])]), + testCase "test wrong var declaration" (shouldBeFalse + [((True, "main", [("a", "Int")], "Int"), [Declaration (("a", "Int"), Integer 0)])]), + testCase "test double func name" (shouldBeFalse + [((True, "main", [("a", "Int")], "Int"), [Return (Integer 0)]), ((True, "main", [("a", "Int")], "Int"), [Return (Integer 0)])]) + ] + +shouldBeTrue :: [FuncDeclaration] -> Assertion +shouldBeTrue funcs = (typeCheck funcs) @?= True + +shouldBeFalse :: [FuncDeclaration] -> Assertion +shouldBeFalse funcs = (typeCheck funcs) @?= False diff --git a/lvtc/test/typeCheck.hs b/lvtc/test/typeCheck.hs deleted file mode 100644 index 534eeef..0000000 --- a/lvtc/test/typeCheck.hs +++ /dev/null @@ -1,22 +0,0 @@ -import Test.Tasty -import Test.Tasty.HUnit -import AST - -main :: IO () -main = defaultMain tests - -tests :: TestTree -tests = testGroup "typeCheck tests" - [testReturn] - -testReturn :: TestTree -testReturn = testGroup "testReturn" [ - testCase "testReturn" (True == - (typeCheck (("main", [], "Int"), ([Declaration (("a", "Int"), Integer 0), Return (Integer 69)])))) -] - -shouldBeTrue :: [FuncDeclaration] -> Assertion -shouldBeTrue funcs = (typeCheck funcs) @?= True - -shouldBeFalse :: [FuncDeclaration] -> Assertion -shouldBeFalse funcs = (typeCheck funcs) @?= False