Added default functions, isEmpty does not typecheck...
[cc1516.git] / gen.icl
diff --git a/gen.icl b/gen.icl
index c8b45d3..d139804 100644 (file)
--- a/gen.icl
+++ b/gen.icl
@@ -1,12 +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
 
 import Data.Func
 import qualified Data.Map as Map
@@ -14,64 +14,206 @@ import Data.List
 import Data.Either
 import Data.Tuple
 import Data.Functor
+import Data.Monoid
+import Data.Maybe
 import Control.Applicative
 import Control.Monad
-import Control.Monad.State
 import Control.Monad.Trans
 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
-            | Lab String
+            | Lab Label
 :: Label :== String
-:: Arg = L Label | Lit Int
+:: Arg = L Label | Lit Int | Raw String
 :: SSMProgram :== [Instr]
-
-
-gen :: AST -> String
-gen _ = toString    [Lab "Test"
-                    ,Instr "ldc" [Lit 1] "Eerste instructie"
-                    ,Instr "ldc" [Lit 2] "Tweede instructie"]
-
-
-//Scrap this, we'll need shared state when generating
-//i.e. to figure out the positions of vars relative to the 
-//SP/MP/whatever or in which register they are 
-//and to supply with fresh labels 
-
-//The generation monad
 :: GenError = Error String
-:: GenMap :== 'Map'.Map String LoadPlace
-:: LoadPlace    = LDA Int | LDC Int | LDH Int | LDL Int 
-                | LDR Int | LDS Int
-:: Gen a :== StateT (GenMap, [Label]) (Either GenError) a
-
-genMap :: Gen GenMap
-genMap = gets fst
-
-class g a :: a -> Gen SSMProgram
+:: Addressbook :== 'Map'.Map String Address
+:: Address = LAB String | ADDR Int
+:: Gen a :== RWST () SSMProgram (Addressbook, [Label]) (Either GenError) a
+
+labelStream :: [Label]
+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
+        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
+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-> 
+        modify (appSnd $ const $ tail vars) >>| 
+        pure (head 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)) = pure <$> load k //note: pure is pure for list, i.e. []
-
-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")
+    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) = 
+        fresh >>= \elseLabel->
+        fresh >>= \endLabel->
+        g cond >>|
+        tell [Instr "brf" [L elseLabel] "branch else"] >>|
+        mapM_ g th >>|
+        tell [Instr "bra" [L endLabel] "branch end if"] >>|
+        tell [Lab elseLabel] >>|
+        mapM_ g el  >>|
+        tell [Lab endLabel]
+    g (WhileStmt cond th) = 
+        fresh >>= \startLabel->
+        fresh >>= \endLabel ->
+        tell [Lab startLabel] >>|
+        g cond >>|
+        tell [Instr "brf" [L endLabel] "branch end while"] >>|
+        mapM_ g th >>|
+        tell [Instr "bra" [L startLabel] "branch start while"] >>|
+        tell [Lab endLabel]
+    g (AssStmt (VarDef k fs) e) = 
+        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]
 
@@ -85,9 +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
-
-instance MonadTrans (StateT (GenMap,[Label])) where
-    liftT m = StateT \s-> m >>= \a-> return (a, s)
\ No newline at end of file