packages feed

keelung-0.9.0.0: src/Keelung/Syntax/Encode/Syntax.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}

-- | Module for encoding Keelung programs
module Keelung.Syntax.Encode.Syntax where

import Control.DeepSeq (NFData)
import Data.Array.Unboxed (Array)
import Data.Foldable (toList)
import Data.IntMap.Strict (IntMap)
import Data.Serialize (Serialize)
import GHC.Generics (Generic)
import Keelung.Data.Struct
import Keelung.Field (FieldType)
import Keelung.Syntax (Var, Width)
import Keelung.Syntax.Counters

--------------------------------------------------------------------------------

-- | Booleans
data Boolean
  = -- | Boolean values
    ValB Bool
  | -- | Boolean variables
    VarB Var
  | -- | Boolean public input variables
    VarBI Var
  | -- | Boolean private input variables
    VarBP Var
  | -- | Conjunction
    AndB Boolean Boolean
  | -- | Disjunction
    OrB Boolean Boolean
  | -- | Exclusive disjunction
    XorB Boolean Boolean
  | -- | Complement
    NotB Boolean
  | -- | Conditional that returns a Boolean
    IfB Boolean Boolean Boolean
  | -- | Equality on Booleans
    EqB Boolean Boolean
  | -- | Equality on Field elements
    EqF Field Field
  | -- | Equality on Unsigned integers
    EqU Width UInt UInt
  | -- | Bit test on Unsigned integers
    BitU Width UInt Int
  deriving (Generic, Eq, NFData)

instance Serialize Boolean

instance Show Boolean where
  showsPrec prec expr = case expr of
    ValB n -> shows n
    VarB var -> showString "$B" . shows var
    VarBI var -> showString "$BI" . shows var
    VarBP var -> showString "$BP" . shows var
    AndB x y -> showParen (prec > 3) $ showsPrec 4 x . showString " ∧ " . showsPrec 3 y
    OrB x y -> showParen (prec > 2) $ showsPrec 3 x . showString " ∨ " . showsPrec 2 y
    XorB x y -> showParen (prec > 4) $ showsPrec 5 x . showString " ⊕ " . showsPrec 4 y
    NotB x -> showParen (prec > 8) $ showString "¬ " . showsPrec 9 x
    IfB p x y -> showParen (prec > 1) $ showString "if " . showsPrec 2 p . showString " then " . showsPrec 2 x . showString " else " . showsPrec 2 y
    EqB x y -> showParen (prec > 5) $ showsPrec 6 x . showString " = " . showsPrec 6 y
    EqF x y -> showParen (prec > 5) $ showsPrec 6 x . showString " = " . showsPrec 6 y
    EqU _ x y -> showParen (prec > 5) $ showsPrec 6 x . showString " = " . showsPrec 6 y
    BitU _ x i -> showParen (prec > 6) $ showsPrec 7 x . showString " [" . shows i . showString "]"

--------------------------------------------------------------------------------

-- | Field elements
data Field
  = -- | Integral values
    ValF Integer
  | -- | Rational values
    ValFR Rational
  | -- | Field element variables
    VarF Var
  | -- | Field element public input variables
    VarFI Var
  | -- | Field element private input variables
    VarFP Var
  | -- | Addition
    AddF Field Field
  | -- | Subtraction
    SubF Field Field
  | -- | Multiplication
    MulF Field Field
  | -- |  Division (without remainders)
    DivF Field Field
  | -- | Conditional that returns a Field element
    IfF Boolean Field Field
  | -- | Conversion from Boolean to Field element
    BtoF Boolean
  deriving (Generic, Eq, NFData)

instance Serialize Field

instance Show Field where
  showsPrec prec expr = case expr of
    ValF n -> shows n
    ValFR n -> shows n
    VarF var -> showString "$F" . shows var
    VarFI var -> showString "$FI" . shows var
    VarFP var -> showString "$FP" . shows var
    AddF x y -> showParen (prec > 6) $ showsPrec 6 x . showString " + " . showsPrec 7 y
    SubF x y -> showParen (prec > 6) $ showsPrec 6 x . showString " - " . showsPrec 7 y
    MulF x y -> showParen (prec > 7) $ showsPrec 7 x . showString " * " . showsPrec 8 y
    DivF x y -> showParen (prec > 7) $ showsPrec 7 x . showString " / " . showsPrec 8 y
    IfF p x y -> showParen (prec > 1) $ showString "if " . showsPrec 2 p . showString " then " . showsPrec 2 x . showString " else " . showsPrec 2 y
    BtoF x -> showString "B→F " . showsPrec prec x

--------------------------------------------------------------------------------

-- | Unsigned Integers
data UInt
  = -- | Unsigned integers values
    ValU Width Integer
  | -- | Unsigned integer variables
    VarU Width Var
  | -- | Unsigned integer public input variables
    VarUI Width Var
  | -- | Unsigned integer private input variables
    VarUP Width Var
  | -- | Addition
    AddU Width UInt UInt
  | -- | Subtraction
    SubU Width UInt UInt
  | -- | Multiplication
    MulU Width UInt UInt
  | -- | Bitwise conjunction
    AndU Width UInt UInt
  | -- | Bitwise disjunction
    OrU Width UInt UInt
  | -- | Bitwise exclusive disjunction
    XorU Width UInt UInt
  | -- | Bitwise complement
    NotU Width UInt
  | -- | Rotate left
    RoLU Width Int UInt
  | -- | Shift left
    ShLU Width Int UInt
  | -- | Set bit and return the result
    SetU Width UInt Int Boolean
  | -- | Conditional that returns an Unsigned integer
    IfU Width Boolean UInt UInt
  | -- | Conversion from Boolean to Unsigned integer
    BtoU Width Boolean
  deriving (Generic, Eq, NFData)

instance Serialize UInt

instance Show UInt where
  showsPrec prec expr = case expr of
    ValU _ n -> shows n
    VarU w var -> showString "$U" . showString (toSubscript w) . shows var
    VarUI w var -> showString "$UI" . showString (toSubscript w) . shows var
    VarUP w var -> showString "$UP" . showString (toSubscript w) . shows var
    AddU _ x y -> showParen (prec > 6) $ showsPrec 6 x . showString " + " . showsPrec 7 y
    SubU _ x y -> showParen (prec > 6) $ showsPrec 6 x . showString " - " . showsPrec 7 y
    MulU _ x y -> showParen (prec > 7) $ showsPrec 7 x . showString " * " . showsPrec 8 y
    AndU _ x y -> showParen (prec > 3) $ showsPrec 4 x . showString " ∧ " . showsPrec 3 y
    OrU _ x y -> showParen (prec > 2) $ showsPrec 3 x . showString " ∨ " . showsPrec 2 y
    XorU _ x y -> showParen (prec > 4) $ showsPrec 5 x . showString " ⊕ " . showsPrec 4 y
    NotU _ x -> showParen (prec > 8) $ showString "¬ " . showsPrec prec x
    RoLU _ n x -> showParen (prec > 8) $ showString "RoL " . showsPrec 9 n . showString " " . showsPrec 9 x
    ShLU _ n x -> showParen (prec > 8) $ showString "ShL " . showsPrec 9 n . showString " " . showsPrec 9 x
    SetU _ x i b -> showParen (prec > 8) $ showsPrec 9 x . showString "[" . shows i . showString "] := " . showsPrec 9 b
    IfU _ p x y -> showParen (prec > 1) $ showString "if " . showsPrec 2 p . showString " then " . showsPrec 2 x . showString " else " . showsPrec 2 y
    BtoU _ x -> showString "B→U " . showsPrec prec x
    where
      toSubscript :: Int -> String
      toSubscript = map go . show
        where
          go c = case c of
            '0' -> '₀'
            '1' -> '₁'
            '2' -> '₂'
            '3' -> '₃'
            '4' -> '₄'
            '5' -> '₅'
            '6' -> '₆'
            '7' -> '₇'
            '8' -> '₈'
            '9' -> '₉'
            _ -> c

--------------------------------------------------------------------------------

-- | Encoding of the Keelung syntax
data Expr
  = -- | Unit
    Unit
  | -- | Booleans
    Boolean Boolean
  | -- | Field element
    Field Field
  | -- | Unsigned integers
    UInt UInt
  | -- | Arrays
    Array (Array Int Expr)
  deriving (Generic, Eq, NFData)

instance Show Expr where
  showsPrec prec expr = case expr of
    Unit -> showString "()"
    Boolean bool -> showsPrec prec bool
    Field num -> showsPrec prec num
    UInt uint -> showsPrec prec uint
    Array xs -> showList (toList xs)

instance Serialize Expr

instance Serialize FieldType

--------------------------------------------------------------------------------

-- | Encoding of a Keelung program after elaboration
data Elaborated = Elaborated
  { -- | The resulting 'Expr'
    elabExpr :: !Expr,
    -- | The state of computation after elaboration
    elabComp :: Computation
  }
  deriving (Generic, NFData)

instance Show Elaborated where
  show (Elaborated expr comp) =
    "{\n  Expression: \n    "
      <> showExpr
      <> "\n"
      <> showExprBindings (compExprBindings comp)
      <> showAssertions (compAssertions comp)
      <> "}"
    where
      showExpr = case expr of
        Array xs -> prettyList2 4 (toList xs)
        _ -> show expr

      showExprBindings eb =
        if empty eb
          then ""
          else
            "  Bindings of expressions: \n"
              <> unlines (map ("    " <>) (prettyStruct "" eb))
              <> "\n"
      showAssertions assertions =
        if null assertions
          then ""
          else "  Assertions: \n" <> unlines (map (("    " <>) . show) assertions) <> "\n"

      prettyList2 :: Show a => Int -> [a] -> String
      prettyList2 n list = case list of
        [] -> "[]"
        [x] -> "[" <> show x <> "]"
        (x : xs) ->
          unlines $
            map (replicate n ' ' <>) $
              "" : "[ " <> show x : map (\y -> ", " <> show y) xs <> ["]"]

instance Serialize Elaborated

--------------------------------------------------------------------------------

-- | Data structure for elaboration bookkeeping
data Computation = Computation
  { -- Variable bookkeeping
    compCounters :: !Counters,
    -- Bindings from variables to expressions
    compExprBindings :: Struct (IntMap Field) (IntMap Boolean) (IntMap UInt),
    -- Assertions are expressions that are expected to be true
    compAssertions :: [Expr],
    -- DivMod relations: dividend = divisor * quotient + remainder
    compDivModRelsU :: IntMap (UInt, UInt, UInt, UInt)
  }
  deriving (Show, Generic, NFData)

instance Serialize Computation