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