packages feed

g2-0.2.0.0: tests_quasiquote/Arithmetics/Interpreter.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}

module Arithmetics.Interpreter where

import Control.Monad
import Data.Data
import G2.QuasiQuotes.G2Rep

type Ident = String
type Env = [(Ident, Int)]

data AExpr = I Int | Var Ident
    | Add AExpr AExpr | Mul AExpr AExpr
    deriving (Eq, Show, Data)

$(derivingG2Rep ''AExpr)

data BExpr = Not BExpr | And BExpr BExpr | Or BExpr BExpr
    | Lt AExpr AExpr | Eq AExpr AExpr
    deriving (Eq, Show, Data)

$(derivingG2Rep ''BExpr)

type Stmts = [Stmt]
data Stmt = Assign Ident AExpr
          | If BExpr Stmts Stmts
          | While BExpr Stmts
          | Assert BExpr
          deriving (Eq, Show, Data)
          
$(derivingG2Rep ''Stmt)

type Bound = [Ident]
type Return = Ident
data Func = Func Bound Stmts Return

$(derivingG2Rep ''Func)

evalFunc :: [Int] -> Func -> Maybe Int
evalFunc is (Func b s r) =
  lookup r =<< evalStmts (zip b is) s

evalStmts :: Env -> Stmts -> Maybe Env
evalStmts = foldM evalStmt  

evalStmt :: Env -> Stmt -> Maybe Env
evalStmt env (Assign ident aexpr) =
  Just $ (ident, evalA env aexpr):env
evalStmt env (If bexpr lhs rhs) =
  if evalB env bexpr
    then evalStmts env lhs
    else evalStmts env rhs
evalStmt env (While bexpr loop) =
  if evalB env bexpr
    then evalStmts env (loop ++ [While bexpr loop])
    else Just env
evalStmt env (Assert bexpr) =
  if evalB env bexpr
    then Just env
    else Nothing

evalA :: Env -> AExpr -> Int
evalA _ (I int) = int
evalA env (Add lhs rhs) =
  evalA env lhs + evalA env rhs
evalA env (Mul lhs rhs) =
  evalA env lhs * evalA env rhs
evalA env (Var ident) =
  case lookup ident env of
    Just int -> int
    _ -> error $
          "lookup with " ++ show (ident, env)

evalB :: Env -> BExpr -> Bool
evalB env (Not bexpr) = not $ evalB env bexpr
evalB env (And lhs rhs) =
  evalB env lhs && evalB env rhs
evalB env (Or lhs rhs) =
  evalB env lhs || evalB env rhs
evalB env (Lt lhs rhs) =
  evalA env lhs < evalA env rhs
evalB env (Eq lhs rhs) =
  evalA env lhs == evalA env rhs