packages feed

shentong-0.3.2: Shentong/Environment.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}

module Environment ( initEnv, evalKL ) where

import Control.Applicative
import Control.Monad.Except
import qualified Data.HashMap as HM
import Data.IORef
import Data.Traversable hiding (mapM)
import qualified Data.Vector as V
import Interpreter.Interpreter
import Core.Primitives
import System.IO
import Core.Types
import Core.Utils
import Wrap

valueToTopLevel :: KLValue -> KLContext Env TopLevel
valueToTopLevel (Cons (Atom (UnboundSym "defun"))
                      (Cons (Atom (UnboundSym name))
                            (Cons args (Cons e (Atom Nil))))) =
    Defun name <$> toParamList args <*> valueToSExpr e
    where toParamList (Cons (Atom (UnboundSym a)) as) = (a :) <$> toParamList as
          toParamList (Atom Nil) = pure []
          toParamList _  = throwError "defun form contains invalid lambda list"
valueToTopLevel se = SE <$> valueToSExpr se

valueToSExpr :: KLValue -> KLContext Env SExpr
valueToSExpr (ApplC (PL name _)) = return (Sym name)
valueToSExpr (ApplC (Func name _)) = return (Sym name)
valueToSExpr (Atom (UnboundSym sym)) = return (Sym sym)
valueToSExpr (Atom Nil) = return EmptyList
valueToSExpr (Atom a) = return (Lit a)
valueToSExpr (Cons v vs) = applToSExpr v (consToList vs)
    where consToList (Cons v vs) = v : consToList vs
          consToList (Atom Nil)  = []
          consToList v = [v]
valueToSExpr (Vec v)
  | V.null v  = pure emptyVec
  | otherwise = vecToSExprList (V.tail v)
    where emptyVec = Appl [Lit (UnboundSym "vector"), Lit (N (KI 0))]
          
          vecToSExprList vec 
            | V.null vec = pure emptyVec
            | otherwise  = do
                se <- valueToSExpr (V.head vec)
                ss <- vecToSExprList (V.tail vec)
                return (Appl [Lit (UnboundSym "@v"), se , ss])
valueToSExpr v = throwError "cannot evaluate list containing non-literal values"

applToSExpr :: KLValue -> [KLValue] -> KLContext Env SExpr
applToSExpr (Atom (UnboundSym "cond")) l = Cond <$> listOfConds l
    where listOfConds (Cons cond (Cons clause (Atom Nil)) : cs) =
              (:) <$> ((,) <$> valueToSExpr cond <*> valueToSExpr clause)
                  <*> listOfConds cs
          listOfConds [] = pure []
          listOfConds _  = throwError "improperly formed cond clause list"
applToSExpr (Atom (UnboundSym "if")) [c,t,f] =
    If <$> valueToSExpr c <*> valueToSExpr t <*> valueToSExpr f
applToSExpr (Atom (UnboundSym "let")) [Atom (UnboundSym s),b,e] =
    Let s <$> valueToSExpr b <*> valueToSExpr e
applToSExpr (Atom (UnboundSym "lambda")) [Atom (UnboundSym s), e] =
    Lambda s <$> valueToSExpr e
applToSExpr (Atom (UnboundSym "and")) [c1,c2] =
    And <$> valueToSExpr c1 <*> valueToSExpr c2
applToSExpr (Atom (UnboundSym "or")) [c1,c2] =
    Or <$> valueToSExpr c1 <*> valueToSExpr c2
applToSExpr (Atom (UnboundSym "freeze")) [e] =
    Freeze <$> valueToSExpr e
applToSExpr (Atom (UnboundSym "trap-error")) [e, h] =
    TrapError <$> valueToSExpr e <*> valueToSExpr h
applToSExpr l ls =
    Appl <$> liftA2 (:) (valueToSExpr l) (traverse valueToSExpr ls)

evalKL :: KLValue -> KLContext Env KLValue
evalKL = valueToTopLevel >=> evalTopLevel

primitives :: [(Symbol, Function)]
primitives = [("intern", wrap intern),
              ("pos", wrap pos),
              ("tlstr", wrap tlstr),
              ("cn", wrap cn),
              ("str", wrap str),
              ("string?", wrap stringP),
              ("n->string", wrap nToString),
              ("string->n", wrap stringToN),
              ("set", wrap klSet),
              ("value", wrap value),
              ("simple-error", wrap simpleError),
              ("error-to-string", wrap errorToString),
              ("cons", wrap klCons),
              ("hd", wrap hd),
              ("tl", wrap tl),
              ("cons?", wrap consP),
              ("=", wrap eq),
              ("type", wrap typeA),
              ("absvector", wrap absvector),
              ("address->", wrap addressTo),
              ("<-address", wrap addressFrom),
              ("absvector?", wrap absvectorP),
              ("write-byte", wrap writeByte),
              ("read-byte", wrap readByte),
              ("open", wrap openStream),
              ("close", wrap closeStream),
              ("get-time", wrap getTime),
              ("+", wrap add),
              ("-", wrap Core.Primitives.subtract),
              ("*", wrap multiply),
              ("/", wrap divide),
              (">", wrap greaterThan),
              ("<", wrap lessThan),
              (">=", wrap greaterThanOrEqualTo),
              ("<=", wrap lessThanOrEqualTo),   
              ("number?", wrap numberP),
              ("eval-kl", wrap evalKL)]

initEnv :: (Applicative m, MonadIO m) => m Env
initEnv = Env initSymbolTable <$> HM.fromList <$> mapM update primitives
    where update (n, f) = (n,) <$> liftIO (newIORef $! Func n f)

initSymbolTable :: HM.Map Symbol KLValue
initSymbolTable = HM.fromList [("*stoutput*", OutStream stdout),
                               ("*stinput*", InStream stdin)]