git @ Cat's Eye Technologies Iphigeneia / master src / MonadInterp.hs
master

Tree @master (Download .tar.gz)

MonadInterp.hs @masterraw · history · blame

--
-- Copyright (c)2007 Chris Pressey, Cat's Eye Technologies.
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
--   1. Redistributions of source code must retain the above copyright
--      notices, this list of conditions and the following disclaimer.
--   2. Redistributions in binary form must reproduce the above copyright
--      notices, this list of conditions, and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--   3. Neither the names of the copyright holders nor the names of their
--      contributors may be used to endorse or promote products derived
--      from this software without specific prior written permission. 
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
-- COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--

-----------------------------------------------------------------------
-- ======================= Monadic Interpreter ===================== --
-----------------------------------------------------------------------

--
-- This interpreter performs I/O.  It is not as straightforward as
-- PureInterp, as it must frame every function in terms of IO monads,
-- which tends to obscure the logic of the interpreter somewhat.
--

module MonadInterp where

import qualified Data.Char as Char

import Map
import AST
import Primitive

--
-- The eval* functions are passed a store and a continuation (cc).
--
-- The store maps VarName objects to their values (Integers).
--
-- The continuation is used with the loop and repeat constructs.
-- It is not a full-blown continuation in the sense of being a
-- function which represents the entire rest of the computation.
-- Rather, it represents only the matchings between occurrences
-- of loop and occurrences of repeat.
--
-- The continuation is implemented as list of NumExprs, where the
-- head NumExpr is the most recently encountered (innermost) loop
-- expression.  Each loop expression extends the continuation with
-- the expression being looped around, and a repeat expression
-- executes the continuation.
--

evalBool :: BoolExpr -> Map VarName Integer -> [NumExpr] -> IO Bool

evalBool (BoolOp op b1 b2) store cc = do
    val1 <- evalBool b1 store cc
    val2 <- evalBool b2 store cc
    return (applyBoolOp op val1 val2)

evalBool (RelOp op e1 e2) store cc  = do
    val1 <- evalNum e1 store cc
    val2 <- evalNum e2 store cc
    return (applyRelOp op val1 val2)

evalBool (Not b) store cc           = do
    val <- evalBool b store cc
    return (not val)

evalBool (BoolConst b) store cc     = do
    return b


evalNum :: NumExpr -> Map VarName Integer -> [NumExpr] -> IO Integer

evalNum (NumOp op e1 e2) store cc = do
    val1 <- evalNum e1 store cc
    val2 <- evalNum e2 store cc
    return (applyNumOp op val1 val2)

evalNum (NumConst i) store cc     = do
    return i

evalNum (IfExpr b e1 e2) store cc = do
    result <- evalBool b store cc
    evalNum (if result then e1 else e2) store cc

evalNum (VarRef v) store cc       = do
    return (get v store 0)

evalNum (Let v e1 e2) store cc    = do
    val <- evalNum e1 store cc
    evalNum e2 (set v val store) cc

evalNum (Loop e) store cc         = evalNum e store ((Loop e):cc)
evalNum (Repeat) store cc         = evalNum (head cc) store (tail cc)

evalNum (ValueOf v s) store cc    = do
    newStore <- interpret s store
    return (get v newStore 0)

evalNum (Input v e) store cc      = do
    symbol <- getChar
    evalNum e (set v (Prelude.fromIntegral (Char.ord symbol)) store) cc


interpret :: Statement -> Map VarName Integer -> IO (Map VarName Integer)

interpret (Block []) store = do
    return store
interpret (Block (s:rest)) store = do
    newStore <- interpret s store
    interpret (Block rest) newStore

interpret (Var v s) store = interpret s store

interpret (Assign v e) store = do
    val <- evalNum e store []
    return (set v val store)

interpret (IfStmt b s1 s2) store = do
    result <- evalBool b store []
    interpret (if result then s1 else s2) store

interpret (While b s) store = do
    result <- evalBool b store []
    loop result
  where
    loop True = do
          newStore <- interpret s store
          interpret (While b s) newStore
    loop False = do
          return store

interpret (Print e) store = do
    val <- evalNum e store []
    putChar (Char.chr (Prelude.fromIntegral val))
    return store