{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE RebindableSyntax #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeSynonymInstances #-} module Language.ArrayForth.HLL.AST where import Prelude hiding (Ord (..), Eq (..), not) import qualified Prelude import Control.Monad.Free import Data.String import Language.ArrayForth.Opcode (F18Word) data Expr = Num F18Word | ArrayRef String | Array String [F18Word] | Nil | Op Operator AST AST | UOp UOperator AST | If AST AST AST | For AST AST AST | While AST AST | Map AST AST AST | Fold AST AST AST AST deriving Show data Forth next = Forth Expr next deriving (Functor, Show) type AST = Free Forth () data Operator = Add | Sub | Mul | Lt | Gt | LtE | GtE | Eq | NEq | Set deriving (Show, Prelude.Eq) data UOperator = Neg | Not | Get deriving Show liftExpr :: Expr -> AST liftExpr expr = liftF $ Forth expr () op :: Operator -> AST -> AST -> AST op opr e₁ e₂ = liftExpr $ Op opr e₁ e₂ instance Num AST where fromInteger = liftExpr . Num . fromInteger (+) = op Add (-) = op Sub (*) = op Mul negate (Free (Forth (Num n) (Pure ()))) = Free $ Forth (Num $ negate n) (Pure ()) negate expr = liftExpr $ UOp Neg expr abs = undefined signum = undefined instance IsString AST where fromString = ref (<), (>), (<=), (≤), (>=), (≥), (==), (/=), (≠), (!), (=:) :: AST -> AST -> AST (<) = op Lt (>) = op Gt (<=) = op LtE (≤) = (<=) (>=) = op GtE (≥) = (>=) (==) = op Eq (/=) = op NEq (≠) = (/=) (!) = (+) (=:) = op Set not, val :: AST -> AST not = liftExpr . UOp Not val = liftExpr . UOp Get ifThenElse :: AST -> AST -> AST -> AST ifThenElse cond e₁ e₂ = liftExpr $ If cond e₁ e₂ array :: String -> [F18Word] -> AST array name values = liftExpr $ Array name values nil :: AST nil = liftExpr Nil for :: AST -> AST -> AST -> AST for var range body = liftExpr $ For var range body while :: AST -> AST -> AST while cond body = liftExpr $ While cond body map :: AST -> AST -> AST -> AST map var arr body = liftExpr $ Map var arr body fold :: AST -> AST -> AST -> AST -> AST fold var₁ var₂ arr body = liftExpr $ Fold var₁ var₂ arr body ref :: String -> AST ref name = liftExpr $ ArrayRef name