Added default functions, isEmpty does not typecheck...
[cc1516.git] / gen.icl
diff --git a/gen.icl b/gen.icl
index be2c3ce..d139804 100644 (file)
--- a/gen.icl
+++ b/gen.icl
@@ -1,14 +1,12 @@
 implementation module gen
 
-
 import StdMisc
 import StdList
 import StdOverloaded
 import StdString
-from StdFunc import id
+from StdFunc import id, const
 import StdTuple
 import StdEnum
-from StdEnv import const
 
 import Data.Func
 import qualified Data.Map as Map
@@ -26,8 +24,6 @@ from Text import class Text(concat), instance Text String
 import AST
 import RWST
 
-//Instruction is an instruction, with possible arguments and a possible comment
-//Or is a label
 TRUE :== -1
 FALSE :== 0
 :: Instr    = Instr String [Arg] String
@@ -36,33 +32,62 @@ FALSE :== 0
 :: Arg = L Label | Lit Int | Raw String
 :: SSMProgram :== [Instr]
 :: GenError = Error String
-:: GenMap :== 'Map'.Map String LoadPlace
-//completely change to either Stack, Heap, Register?
-:: LoadPlace    = LDA Int | LDC Int | LDH Int | LDL Int 
-                | LDR Int | LDS Int
-                | FUNC Label
-:: Gen a :== RWST Label SSMProgram (GenMap, [Label]) (Either GenError) a
+:: Addressbook :== 'Map'.Map String Address
+:: Address = LAB String | ADDR Int
+:: Gen a :== RWST () SSMProgram (Addressbook, [Label]) (Either GenError) a
 
 labelStream :: [Label]
-labelStream = map (\i-> concat ["lab_", toString i]) [1..]
-
-gen :: AST -> String
-gen _ = prog
+labelStream = ["lbl_" +++ toString i\\i<-[1..]]
+
+defaultAddressBook :: Addressbook 
+defaultAddressBook = extend "print" (LAB "print")
+                        $ extend "read" (LAB "read")
+                        $ extend "isEmpty" (LAB "isEmpty")
+                        'Map'.newMap
+
+gen :: AST -> Either String String
+gen (AST fds) = case evalRWST prog () (defaultAddressBook, labelStream) of
+            Left (Error e) = Left e
+            Right (_, p) = Right $ toString p
     where
-        expr = (Op2Expr zero (Op1Expr zero UnMinus (IntExpr zero 4)) BiPlus (IntExpr zero 7))
-        expr2 = (FunExpr zero "test" [IntExpr zero 4] [])
-        stmt = (IfStmt (BoolExpr zero True) [] [])
-        prog = case evalRWST (g stmt) "end" ('Map'.newMap, labelStream) of
-            Left (Error e) = abort e
-            Right (_, prog) = toString prog
-//gen _ = toString    [Lab "Test"
-//                    ,Instr "ldc" [Lit 1] "Eerste instructie"
-//                    ,Instr "ldc" [Lit 2] "Tweede instructie"]
-
+        prog = tell [
+                       Instr "bsr" [L "main"] "",
+                       Instr "halt" [] ""
+                       ] >>| tell programContext
+            >>| mapM_ g fds
+
+programContext :: SSMProgram
+programContext =    [Lab "print" //there is no actual IO in SSM
+                    ,Instr "link" [Lit 0] ""
+                    ,Instr "unlink" [] ""
+                    ,Instr "ret" [] ""
+                    ,Lab "read" //there is no actual IO in SSM
+                    ,Instr "link" [Lit 0] ""
+                    ,Instr "ldc" [Lit 0] ""
+                    ,Instr "sth" [] ""
+                    ,Instr "str" [Raw "RR"] ""
+                    ,Instr "unlink" [] ""
+                    ,Instr "ret" [] ""
+                    ,Lab "isEmpty"
+                    ,Instr "link" [Lit 0] ""
+                    ,Instr "ldl" [Lit -2] "load prt to list"
+                    ,Instr "lda" [Lit 0] "derefrence ptr"
+                    ,Instr "ldc" [Lit 0] ""
+                    ,Instr "eq" [] "test for null pointer"
+                    ,Instr "str" [Raw "RR"] ""
+                    ,Instr "unlink" [] ""
+                    ,Instr "ret" [] ""
+                    ]
 
 //helper functions for the gen monad
-genMap :: Gen GenMap
-genMap = gets fst
+getAdressbook :: Gen Addressbook
+getAdressbook = gets fst
+
+updateAdressbook :: (Addressbook -> Addressbook) -> Gen Addressbook
+updateAdressbook f = modify (appFst f) >>| getAdressbook
+
+extend :: String Address Addressbook -> Addressbook
+extend k pl g = 'Map'.put k pl g 
 
 fresh :: Gen Label
 fresh = gets snd >>= \vars-> 
@@ -71,19 +96,62 @@ fresh = gets snd >>= \vars->
 
 class g a :: a -> Gen ()
 
+instance g Op1 where
+       g UnNegation = tell [Instr "not" [] ""]
+       g UnMinus = tell [Instr "neg" [] ""]
+
+instance g Op2 where
+       g o = tell [Instr s [] ""]
+               where
+                       s = case o of
+                   BiPlus = "add"
+                               BiMinus = "sub"
+                   BiTimes = "mul"
+                   BiDivide = "div"
+                   BiMod = "mod"
+                   BiEquals = "eq"
+                   BiLesser = "lt"
+                   BiGreater = "gt"
+                   BiLesserEq = "le"
+                   BiGreaterEq = "ge"
+                   BiUnEqual = "ne"
+                   BiAnd =  "and"
+                   BiOr = "or"
+                   BiCons = abort "Shit, Cons, how to deal with this?"
+
 instance g Expr where
-    g (VarExpr _ (VarDef k fs)) = load k >>= \instr-> tell [instr] //note: pure is pure for list, i.e. []
-    g (IntExpr _ i) = loadP (LDC i) >>= \instr-> tell [instr]
-    g (CharExpr _ c) = undef //how to deal with strings?
-    g (BoolExpr _ True) = loadP (LDC TRUE) >>= \instr-> tell [instr]
-    g (BoolExpr _ False) = loadP (LDC FALSE) >>= \instr-> tell [instr]
-    g (Op2Expr _ e1 op e2) = g e1 >>| g e2 >>| tell [Instr (op2ins op) [] ""]
-    g (Op1Expr _ UnNegation e) = g e >>| tell [Instr "not" [] ""]
-    g (Op1Expr _ UnMinus e) = g e >>| tell [Instr "neg" [] ""]
-    g (EmptyListExpr _) = abort "Shit, empty list expr"
-    g (TupleExpr p (e1,e2)) = abort "How to deal with tuples?"
-    g (FunExpr _ k es fs) = mapM g es >>| jump "bsr" k >>= \instr-> tell [instr]
-            //bra is probably not right, figure out function call way
+    g (IntExpr _ i) = tell [Instr "ldc" [Lit i] ""]
+    g (CharExpr _ c) = tell [Instr "ldc" [Lit (toInt c)] ""]
+       g (BoolExpr _ b) = tell [Instr "ldc" [Lit (if b TRUE FALSE)] ""]
+    g (EmptyListExpr _) = tell [Instr "ldc" [Lit 0] ""]
+               >>| tell [Instr "sth" [] ""]
+    g (Op1Expr _ o e) = g e >>| g o
+    g (Op2Expr _ e1 BiCons e2) = g e2 >>| g e1
+               >>| tell [Instr "sth" [] ""]
+               >>| tell [Instr "ajs" [Lit -1] ""]
+               >>| tell [Instr "sth" [] ""]
+    g (Op2Expr _ e1 op e2) = g e1 >>| g e2 >>| g op
+    g (TupleExpr _ (e1,e2)) = g e1
+               >>| tell [Instr "sth" [] ""]
+               >>| g e2
+               >>| tell [Instr "sth" [] ""]
+               >>| tell [Instr "ajs" [Lit -1] ""]
+    g (VarExpr _ (VarDef k fs)) = getAdressbook >>= \ab->case 'Map'.get k ab of
+               Nothing = liftT (Left $ Error "PANIC: undefined variable")
+               Just (ADDR t) = tell [Instr "ldl" [Lit t] ""]
+               Just (LAB t) = liftT (Left $ Error "PANIC: variable and function name clash")
+               //load k >>= \instr-> tell [instr] //note: pure is pure for list, i.e. []
+    g (FunExpr _ k es fs) = 
+               mapM_ g es
+               >>| jump "bsr" k
+        >>| mapM_ (const $ tell [Instr "ajs" [Lit -1] ""]) es //clean up args
+               >>| tell [Instr "ldr" [Raw "RR"] ""]
+
+jump :: String String -> Gen ()
+jump instr k = getAdressbook >>= \ab->case 'Map'.get k ab of
+       Nothing = liftT (Left $ Error $ concat ["PANIC: ", k, " not found as function"])
+       Just (LAB t) = tell [Instr instr [L t] (k +++"()")]
+       Just (ADDR t) = liftT (Left $ Error $ "PANIC: jump should go to label")
 
 instance g Stmt where
     g (IfStmt cond th el) = 
@@ -106,58 +174,46 @@ instance g Stmt where
         tell [Instr "bra" [L startLabel] "branch start while"] >>|
         tell [Lab endLabel]
     g (AssStmt (VarDef k fs) e) = 
-        g e >>|
-        abort "Shit, an assignment, figure out something with storing vars or something"
-    g (FunStmt _ _) = abort "CodeGen FunStmt unused" //not used
-    g (ReturnStmt Nothing)  = tell [Instr "ret" [] ""]
-    g (ReturnStmt (Just e)) = 
-        g e >>|
-        tell [Instr "str" [Raw "RR"] ""] >>|
-        g (ReturnStmt Nothing)
-
-
-
-op2ins :: Op2 -> String
-op2ins op = case op of
-    BiPlus = "add"
-    BiMinus = "sub"
-    BiTimes = "mul"
-    BiDivide = "div" 
-    BiMod = "mod"
-    BiEquals = "eq"
-    BiLesser = "lt"
-    BiGreater = "gt"
-    BiLesserEq = "le"
-    BiGreaterEq = "ge"
-    BiUnEqual = "ne"
-    BiAnd = "and"
-    BiOr = "or"
-    BiCons = abort "Shit, Cons, how to deal with this?"
-
-load :: String -> Gen Instr
-load k = genMap >>= \g-> case 'Map'.member k g of
-    False = liftT (Left $ Error $ concat ["PANIC: ", k, " not found in variable mapping"])
-    True = loadP $ 'Map'.find k g
-
-loadP :: LoadPlace -> Gen Instr
-loadP pl = dec pl >>= \(instr, arg)-> pure $ Instr instr [arg] ""
-where
-    dec (LDA i) = pure ("lda", Lit i)
-    dec (LDC i) = pure ("ldc", Lit i)
-    dec (LDH i) = pure ("ldh", Lit i)
-    dec (LDL i) = pure ("ldl", Lit i)
-    dec (LDR i) = pure ("ldr", Lit i)
-    dec (LDS i) = pure ("lds", Lit i)
-    dec _       = liftT (Left $ Error "PANIC: trying to load non adres")
-
-//Instruction (String), key of function to jump to    
-jump :: String String -> Gen Instr
-jump instr k = genMap >>= \g-> case 'Map'.member k g of
-    False = liftT (Left $ Error $ concat ["PANIC: ", k, " not found as function"])
-    True = dec ('Map'.find k g) >>= \lbl-> pure $ Instr instr [lbl] k 
-where
-    dec (FUNC l) = pure (L l)
-    dec _ = liftT (Left $ Error "PANIC: trying to jump to non label")
+        g e >>| getAdressbook >>= \ab->case 'Map'.get k ab of
+            Nothing = liftT (Left $ Error $ concat ["PANIC: ", k, " not found as var"])
+            Just (LAB t) = liftT (Left $ Error $ "PANIC: cannot assign to function")
+            Just (ADDR t) = tell [Instr "stl" [Lit t] ""]
+    g (FunStmt k es) = mapM_ g es 
+        >>| jump "bsr" k
+        >>| mapM_ (const $ tell [Instr "ajs" [Lit -1] ""]) es //clean up args
+        >>| pure ()
+    g (ReturnStmt Nothing) = tell [Instr "unlink" [] ""]
+               >>| tell [Instr "ret" [] ""]
+    g (ReturnStmt (Just e)) = g e
+               >>| tell [Instr "str" [Raw "RR"] ""] 
+               >>| g (ReturnStmt Nothing)
+
+foldVarDecl :: Int VarDecl -> Gen Int
+foldVarDecl x (VarDecl _ _ k e) = g e 
+    >>| annote x k
+       >>| updateAdressbook (extend k (ADDR x)) >>| pure (x + 1)
+
+addVars :: [String] -> (Addressbook -> Addressbook)
+addVars [] = id
+addVars [x:xs] = \ab->extend x (ADDR (-2 - (length xs))) (addVars xs ab)
+
+instance g FunDecl where
+    g (FunDecl _ k args _ vds stms) = 
+        //varDecls can call the enclosing function, so first reserve a label for it 
+        updateAdressbook (extend k (LAB k)) >>|
+        getAdressbook >>= \oldMap ->
+               updateAdressbook (addVars args) >>|
+        tell [Lab k] >>|
+               tell [Instr "link" [Lit 0] ""] >>|
+        //add the vars
+        foldM foldVarDecl 1 vds  >>|
+        //and the statements
+        mapM_ g stms >>|
+        updateAdressbook (const oldMap) >>| pure ()
+
+annote :: Int String -> Gen ()
+annote pos key = 
+    tell [Instr "annote" [Raw "MP", Lit pos, Lit pos, Raw "green", Raw key] ""]
 
 class print a :: a -> [String]
 
@@ -171,6 +227,7 @@ instance print [Arg] where
 instance toString Arg where
     toString (L l) = l
     toString (Lit int) = toString int
+    toString (Raw s) = s
 
 instance toString SSMProgram where
-    toString p = concat $ intersperse " " $ map (\i-> concat $ intersperse " " $ print i) p
\ No newline at end of file
+    toString p = concat $ intersperse " " $ map (\i-> concat $ intersperse " " $ print i) p