aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2022-09-01 22:34:28 +0100
committerJuan J. Martinez <jjm@usebox.net>2022-09-01 22:34:38 +0100
commit3d2b80cf454e682ba1fcd094465b7ee1a94297dd (patch)
tree68b6731494756df20fc4cc0cea3b556f92f0ed12
parent476b0d2d6c27b9ec326b465480795582a3b22f4c (diff)
downloadmicro-lang-hs-3d2b80cf454e682ba1fcd094465b7ee1a94297dd.tar.gz
micro-lang-hs-3d2b80cf454e682ba1fcd094465b7ee1a94297dd.zip
Variable declaration
-rw-r--r--src/Ast.hs3
-rw-r--r--src/Compiler.hs15
-rw-r--r--src/Lexer.hs4
-rw-r--r--src/Parser.hs14
-rw-r--r--test/Language.hs81
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
]