packages feed

melody-0.2: src/Language/Melody/Interpret/Env/Primops.hs

module Language.Melody.Interpret.Env.Primops where
import Language.Melody.Syntax
import Language.Melody.Interpret.Types
import Language.Melody.Interpret.Pop
import Language.Melody.Interpret.Compile
import Control.Monad.Reader
import Control.Applicative
import Control.Lens hiding (cons, uncons)
import qualified Data.Map as M

primops :: MelodyState
primops = MS builtins M.empty []

arith :: (Double -> Double -> Double) -> Melody
arith f = liftM2 f popNum popNum >>= push . NumLit

cons :: Melody
cons = do
  t <- pop
  case t of
    StrLit s       -> pushWith popStr           $ StrLit . (++ s)
    List   l       -> pushWith pop              $ List . (:l)
    Dictionary   d -> pushWith (pop >>= toPair) $ Dictionary . (:d)
    _              -> typeError "cons: Not sequence"
  where toPair (List [a, b]) = return (a, b)
        toPair _             = typeError "cons: Not a list of two elements"
        pushWith f with = f >>= push . with

uncons :: Melody
uncons = do
  expr <- pop
  case expr of
    StrLit (s : ss)        -> pushBoth (StrLit [s]) (StrLit ss)
    List   (l : ll)        -> pushBoth l (List ll)
    Dictionary ((a,b): hh) -> pushBoth (List [a, b]) (Dictionary hh)
    _                      -> typeError "Not sequence"
  where pushBoth a b = push b >> push a

apply :: Melody
apply = do
  (body, clos) <- popFunc
  clos' <- maybe (fail "$: Caught non-closed lambda") return clos
  void . local (M.union clos') $ compile body
    -- Use the closure attached to a function

equals :: Melody
equals = do
  l <- pop
  r <- pop
  when (isOpaque l || isOpaque r) $
    typeError "Comparing Opaques"
  if l == r then true else false
  where true  = void pop
        false = pop <* pop >>= push
        isOpaque (Opaque {}) = True
        isOpaque _           = False


unbox :: Melody
unbox = popBoxed >>= mapM_ push . reverse . contents
  where contents (_, _, es) = es

builtins :: M.Map String Melody
builtins = M.fromList
           [("pop", void pop),
            ("print", pop >>= liftIO . print),
            ("putStr", popStr >>= liftIO . putStrLn),
            ("+", arith (+)),
            ("-", arith (-)),
            ("/", arith (/)),
            ("*", arith (*)),
            ("dump", use stack >>= liftIO . print),
            ("cons", cons),
            ("uncons", uncons),
            ("$", apply),
            ("no-op", return ()),
            ("=", equals),
            ("unbox", unbox),
            ("typeOf", pop >>= push . StrLit . typeName)]