-- | Surface language
module Circuit.Lang
( c
, add
, sub
, mul
, and_
, or_
, xor_
, not_
, eq
, deref
, e
, cond
, ret
, input
) where
import Protolude
import Circuit.Affine (AffineCircuit(..))
import Circuit.Arithmetic (Gate(..), Wire(..))
import Circuit.Expr
-- | Convert constant to expression
c :: f -> Expr Wire f f
c = EConst
-- | Binary arithmetic operations on expressions
add, sub, mul :: Expr Wire f f -> Expr Wire f f -> Expr Wire f f
add = EBinOp BAdd
sub = EBinOp BSub
mul = EBinOp BMul
-- | Binary logic operations on expressions
-- Have to use underscore or similar to avoid shadowing @and@ and @or@
-- from Prelude/Protolude.
and_, or_, xor_ :: Expr Wire f Bool -> Expr Wire f Bool -> Expr Wire f Bool
and_ = EBinOp BAnd
or_ = EBinOp BOr
xor_ = EBinOp BXor
-- | Negate expression
not_ :: Expr Wire f Bool -> Expr Wire f Bool
not_ = EUnOp UNot
-- | Compare two expressions
eq :: Expr Wire f f -> Expr Wire f f -> Expr Wire f Bool
eq = EEq
-- | Convert wire to expression
deref :: Wire -> Expr Wire f f
deref = EVar
-- | Return compilation of expression into an intermediate wire
e :: Num f => Expr Wire f f -> ExprM f Wire
e = compileWithWire imm
-- | Conditional statement on expressions
cond :: Expr Wire f Bool -> Expr Wire f ty -> Expr Wire f ty -> Expr Wire f ty
cond = EIf
-- | Return compilation of expression into an output wire
ret :: Num f => Expr Wire f f -> ExprM f Wire
ret = compileWithWire freshOutput
compileWithWire :: Num f => ExprM f Wire -> Expr Wire f f -> ExprM f Wire
compileWithWire freshWire expr = do
compileOut <- compile expr
case compileOut of
Left wire -> pure wire
Right circ -> do
wire <- freshWire
emit $ Mul (ConstGate 1) circ wire
pure wire
input :: ExprM f Wire
input = freshInput