From 3d2b80cf454e682ba1fcd094465b7ee1a94297dd Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Thu, 1 Sep 2022 22:34:28 +0100 Subject: Variable declaration --- src/Ast.hs | 3 ++- src/Compiler.hs | 15 +++++++++-- src/Lexer.hs | 4 +-- src/Parser.hs | 14 ++++++++-- test/Language.hs | 81 ++++++++++++++++++++++++++++++++++++++------------------ 5 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/Ast.hs b/src/Ast.hs index 3d351c6..af87a8b 100644 --- a/src/Ast.hs +++ b/src/Ast.hs @@ -23,7 +23,8 @@ data Expr = Num Integer SourcePos | Bool' Bool SourcePos | BinOp Op Expr Expr - | Var Ident SourcePos + | Variable Ident SourcePos + | Var Ident Type Expr SourcePos | -- fn [params] return body private anomyous pos Func Ident [FuncParam] (Maybe Type) [Expr] Bool Bool SourcePos | Call Expr [Expr] SourcePos diff --git a/src/Compiler.hs b/src/Compiler.hs index a8cca5d..a708f96 100644 --- a/src/Compiler.hs +++ b/src/Compiler.hs @@ -92,7 +92,7 @@ verifyFuncType ident params ret pos = do map ( \(id, t, pos) -> if not (definedType t) - then Just $ Error UndefinedType ("undefined type in \"" ++ id ++ "\"") pos + then Just $ Error UndefinedType ("undefined type in function declaration \"" ++ id ++ "\"") pos else Nothing ) params @@ -145,6 +145,17 @@ compile x = do Nothing -> return $ Right rtyp Right _ -> addError $ Error NonCallable "non callable value in function call" pos _ -> return $ Right Nothing + (A.Var ident typ val pos) -> do + (ev, errs) <- get + (ev, errs) <- return $ foldlEither addSymUniq (ev, errs) [(ident, typ, pos)] + errs <- + return $ + if not (definedType typ) + then Error UndefinedType ("undefined type in variable declaration \"" ++ ident ++ "\"") pos : errs + else errs + -- TODO: typecheck value + put (ev, errs) + return $ Right $ Just typ (A.Return value pos) -> do (ev, errs) <- get case getSyml ev "$fn$" of @@ -154,7 +165,7 @@ compile x = do case r of Just err -> addError $ Error TypeError err pos Nothing -> return $ Right rtyp - (A.Var ident pos) -> do + (A.Variable ident pos) -> do (ev, errs) <- get case getSym ev ident of Just (_, t, _) -> return $ Right $ Just t diff --git a/src/Lexer.hs b/src/Lexer.hs index 1778b21..7d09752 100644 --- a/src/Lexer.hs +++ b/src/Lexer.hs @@ -9,8 +9,8 @@ import qualified Text.Parsec.Token as T scanner :: T.TokenParser () scanner = T.makeTokenParser style where - ops = ["+", "*", "-", ";"] - names = ["module", "private", "def", "return", "->", "true", "false"] + ops = ["+", "*", "-", ";", "="] + names = ["module", "private", "var", "def", "return", "->", "true", "false"] style = emptyDef { T.commentLine = "#", diff --git a/src/Parser.hs b/src/Parser.hs index ea698c8..f341bc2 100644 --- a/src/Parser.hs +++ b/src/Parser.hs @@ -43,7 +43,7 @@ variable :: Parser Expr variable = do pos <- getPosition var <- identifier - return $ Var var pos + return $ Variable var pos typ :: Parser Type typ = do @@ -116,6 +116,16 @@ call = do args <- parens $ commaSep expr return $ Call ident args pos +var :: Parser Expr +var = do + pos <- getPosition + reserved "var" + (ident, typ, _) <- arg + reservedOp "=" "assignation" + value <- expr + reservedOp ";" + return $ Var ident typ value pos + factor :: Parser Expr factor = number @@ -150,7 +160,7 @@ program = do n <- many $ do function - -- TODO: variable decl + <|> var <|> statement "statement" return $ [m] ++ n diff --git a/test/Language.hs b/test/Language.hs index 12c724a..9a3ca5d 100644 --- a/test/Language.hs +++ b/test/Language.hs @@ -89,7 +89,7 @@ testCase6 = \fn();" [ A.Module "main" $ newPos "test" 1 1, A.Func "fn" [] Nothing [] False False $ newPos "test" 2 1, - A.Call (A.Var "fn" $ newPos "test" 3 1) [] $ newPos "test" 3 1 + A.Call (A.Variable "fn" $ newPos "test" 3 1) [] $ newPos "test" 3 1 ] testCase7 = @@ -102,7 +102,7 @@ testCase7 = \fn(10);" [ A.Module "main" $ newPos "test" 1 1, A.Func "fn" [("a", A.Type "u8", newPos "test" 2 8)] Nothing [] False False $ newPos "test" 2 1, - A.Call (A.Var "fn" $ newPos "test" 3 1) [A.Num 10 $ newPos "test" 3 4] $ newPos "test" 3 1 + A.Call (A.Variable "fn" $ newPos "test" 3 1) [A.Num 10 $ newPos "test" 3 4] $ newPos "test" 3 1 ] testCase8 = @@ -126,7 +126,7 @@ testCase9 = \def fn() {\n\ \fn(); }" [ A.Module "main" $ newPos "test" 1 1, - A.Func "fn" [] Nothing [A.Call (A.Var "fn" $ newPos "test" 3 1) [] $ newPos "test" 3 1] False False $ newPos "test" 2 1 + A.Func "fn" [] Nothing [A.Call (A.Variable "fn" $ newPos "test" 3 1) [] $ newPos "test" 3 1] False False $ newPos "test" 2 1 ] testCase10 = @@ -145,12 +145,12 @@ testCase10 = "fn2" [("f", A.FuncType [] Nothing, newPos "test" 3 9)] Nothing - [ A.Call (A.Var "f" $ newPos "test" 4 1) [] $ newPos "test" 4 1 + [ A.Call (A.Variable "f" $ newPos "test" 4 1) [] $ newPos "test" 4 1 ] False False $ newPos "test" 3 1, - A.Call (A.Var "fn2" $ newPos "test" 5 1) [A.Var "fn1" $ newPos "test" 5 5] $ newPos "test" 5 1 + A.Call (A.Variable "fn2" $ newPos "test" 5 1) [A.Variable "fn1" $ newPos "test" 5 5] $ newPos "test" 5 1 ] testCase11 = @@ -167,11 +167,11 @@ testCase11 = "fn" [("f", A.FuncType [] Nothing, newPos "test" 2 8)] Nothing - [A.Call (A.Var "f" $ newPos "test" 3 1) [] $ newPos "test" 3 1] + [A.Call (A.Variable "f" $ newPos "test" 3 1) [] $ newPos "test" 3 1] False False $ newPos "test" 2 1, - A.Call (A.Var "fn" $ newPos "test" 4 1) [A.Func "lambda@4,4" [] Nothing [] True True $ newPos "test" 4 4] $ newPos "test" 4 1 + A.Call (A.Variable "fn" $ newPos "test" 4 1) [A.Func "lambda@4,4" [] Nothing [] True True $ newPos "test" 4 4] $ newPos "test" 4 1 ] testCase12 = @@ -184,9 +184,19 @@ testCase12 = A.Call (A.Func "lambda@2,1" [] Nothing [] True True $ newPos "test" 2 1) [] $ newPos "test" 2 1 ] +testCase13 = + TestLabel "parse a variable declaration" $ + TestCase $ + assertAst + "module main\n\ + \var a: u8 = 10;" + [ A.Module "main" $ newPos "test" 1 1, + A.Var "a" (A.Type "u8") (A.Num 10 $ newPos "test" 2 13) $ newPos "test" 2 1 + ] + -- test errors -testCase13 = +testCaseE1 = TestLabel "invalid return value (empty return)" $ TestCase $ expectError @@ -194,7 +204,7 @@ testCase13 = \def fn(): u8 { return; }" E.TypeError -testCase14 = +testCaseE2 = TestLabel "invalid return value" $ TestCase $ expectError @@ -202,7 +212,7 @@ testCase14 = \def fn(): u16 { return 1; }" E.TypeError -testCase15 = +testCaseE3 = TestLabel "return without function" $ TestCase $ expectError @@ -210,7 +220,7 @@ testCase15 = \return;" E.UnexpectedReturn -testCase16 = +testCaseE4 = TestLabel "symbol already defined" $ TestCase $ expectError @@ -219,7 +229,7 @@ testCase16 = \def fn() { }" E.AlreadyDefined -testCase17 = +testCaseE5 = TestLabel "parameter already defined" $ TestCase $ expectError @@ -227,7 +237,7 @@ testCase17 = \def fn(a: u8, a: u8) { }\n" E.AlreadyDefined -testCase18 = +testCaseE6 = TestLabel "call on non callable" $ TestCase $ expectError @@ -235,7 +245,7 @@ testCase18 = \def fn(a: u8): u8 { return a(); }\n" E.NonCallable -testCase19 = +testCaseE7 = TestLabel "undefined variable" $ TestCase $ expectError @@ -243,7 +253,7 @@ testCase19 = \def fn(a: u8): u8 { return undef; }\n" E.Undefined -testCase20 = +testCaseE8 = TestLabel "lambdas can use local variables only" $ TestCase $ expectError @@ -253,7 +263,7 @@ testCase20 = \}\n" E.Undefined -testCase21 = +testCaseE9 = TestLabel "undefined type in function parameters" $ TestCase $ expectError @@ -263,7 +273,7 @@ testCase21 = \}\n" E.UndefinedType -testCase22 = +testCaseE10 = TestLabel "undefined type in function return type" $ TestCase $ expectError @@ -273,6 +283,22 @@ testCase22 = \}\n" E.UndefinedType +testCaseE11 = + TestLabel "already defined variable" $ + TestCase $ + expectError + "module main\n\ + \var a: u8 = 1; var a: u8 = 1;\n" + E.AlreadyDefined + +testCaseE12 = + TestLabel "undefined type in variable declaration" $ + TestCase $ + expectError + "module main\n\ + \var a: undef = 1;\n" + E.UndefinedType + language = [ testCase2, testCase3, @@ -286,13 +312,16 @@ language = testCase11, testCase12, testCase13, - testCase14, - testCase15, - testCase16, - testCase17, - testCase18, - testCase19, - testCase20, - testCase21, - testCase22 + testCaseE1, + testCaseE2, + testCaseE3, + testCaseE4, + testCaseE5, + testCaseE6, + testCaseE7, + testCaseE8, + testCaseE9, + testCaseE10, + testCaseE11, + testCaseE12 ] -- cgit v1.2.3