Merge branch 'master' of github.com:dopefishh/cc1516
[cc1516.git] / sem.icl
diff --git a/sem.icl b/sem.icl
index 603d53a..a041cee 100644 (file)
--- a/sem.icl
+++ b/sem.icl
@@ -3,6 +3,7 @@ implementation module sem
 import qualified Data.Map as Map
 from Data.Func import $
 import Data.Maybe
+import Data.Void
 import Data.Either
 import Data.Functor
 import Control.Applicative
@@ -40,19 +41,47 @@ sem (AST vd fd) = case runStateT m ('Map'.newMap, getRandomStream 1) of
 where 
     m :: Env ([VarDecl], [FunDecl])
     m = mapM semVarDecl vd >>= \vds ->
-        mapM semFunDecl fd >>= \fds -> 
-        pure (vds, fds)
+        mapM semFunDecl fd >>= \fds1 -> 
+        mapM semFunDecl fds1 >>= \fds2 -> 
+        pure (vds, fds2)
 
 semFunDecl :: FunDecl -> Env FunDecl
 semFunDecl fd=:(FunDecl p f args mt vds stmts) = 
-    saveGamma >>= \gamma ->
     (case mt of
-        Nothing = let t = IdType f in putIdent f t >>| pure t
+        Nothing = genType args >>= \infft->putIdent f infft >>| pure infft
         Just t = putIdent f t >>| pure t) >>= \ft ->
-    mapM_ (\a-> freshIdent >>= \fr-> putIdent a (IdType fr)) args >>|
-    mapM_ semVarDecl vds >>| 
-    mapM_ (checkStmt $ resultType ft) stmts >>| 
-    restoreGamma gamma >>| pure fd 
+    saveGamma >>= \gamma ->
+       matchFunctions args ft >>= \tres->
+    mapM semVarDecl vds >>= \newvds->
+    mapM (checkStmt tres) stmts >>= \newstmts->
+       pure IntType >>= \returntype->
+       case mt of
+               Nothing = reconstructType args returntype 
+               >>= \ftype->restoreGamma gamma 
+                       >>| putIdent f ftype >>| pure (
+                       FunDecl p f args (Just ftype) newvds newstmts) 
+               Just t = restoreGamma gamma 
+                       >>| pure (FunDecl p f args mt newvds newstmts) 
+
+reconstructType :: [String] Type -> Env Type
+reconstructType [] t = pure t
+reconstructType [x:xs] t = gets (\(st, r)->'Map'.get x st)
+       >>= \mtype->case mtype of
+               Nothing = liftT $ Left $ Error "Not used ????"
+               Just type = reconstructType xs t >>= \resttype->pure (type ->> resttype)
+
+genType :: [String] -> Env Type
+genType [] = freshIdent >>= \fi->pure $ IdType fi
+genType [x:xs] = liftM2 (->>) (freshIdent >>= \fi->pure $ IdType fi)
+       (genType xs)
+
+matchFunctions :: [String] Type -> Env Type
+matchFunctions [] (_ ->> _) = liftT $ Left $ Error "Not enough arguments"
+matchFunctions _ (VoidType ->> _) = liftT $ Left $ Error "Cannot have a void type in the middle of the function definition"
+matchFunctions [x:xs] (t1 ->> t2) = 
+       modify (\(st, r)->('Map'.put x t1 st, r)) >>| matchFunctions xs t2
+matchFunctions [] t = pure t
+matchFunctions _ t = liftT $ Left $ Error "Too much argumnts"
 
 semVarDecl :: VarDecl -> Env VarDecl
 semVarDecl (VarDecl pos type ident ex) = unify type ex
@@ -63,7 +92,10 @@ checkStmt t (IfStmt c st se) = unify BoolType c >>| mapM (checkStmt t) st
     >>= \st1-> mapM (checkStmt t) se >>= \se1-> pure (IfStmt c st1 se1)
 checkStmt t w=:(WhileStmt c et) = unify BoolType c >>| mapM (checkStmt t) et
     >>= \et1-> pure w
-checkStmt t (AssStmt (VarDef ident fs) e) = undef
+checkStmt t a=:(AssStmt (VarDef ident fs) e) = gets (\(st, r)->'Map'.get ident st)
+    >>= \mt->case mt of
+        Nothing = liftT $ Left $ UndeclaredVariableError zero ident
+        Just t = unify t fs >>= \t1 -> unify t1 e >>| pure a
 checkStmt t r=:(FunStmt (FunCall f es)) = typeFun f es >>| pure r
 checkStmt VoidType r=:(ReturnStmt Nothing) = pure r
 checkStmt t r=:(ReturnStmt (Just e)) = unify t e >>| pure r
@@ -134,8 +166,8 @@ instance unify Expr where
                        "Expression cannot be a higher order function. Yet..."
        unify VoidType e = liftT $ Left $ ParseError (extrPos e)
                        "Expression cannot be a Void type."
-       unify (IdType _) e = liftT $ Left $ ParseError (extrPos e)
-                       "Expression cannot be an polymorf type."
+//     unify (IdType _) e = liftT $ Left $ ParseError (extrPos e)
+//                     "Expression cannot be an polymorf type."
     unify VarType e = typeExpr e
     //we have to cheat to decorate the error, can be done nicer?
     unify t e = StateT $ \s0 -> let res = runStateT m s0 in case res of
@@ -238,4 +270,4 @@ saveGamma :: Env Gamma
 saveGamma = get
 
 restoreGamma :: Gamma -> Env Void
-restoreGamma g = put g
\ No newline at end of file
+restoreGamma (oldstate, _) = gets snd >>= \newr->put (oldstate, newr)