Complete the implementation of symbolic evaluator primitives.

This involves generalizing some of the concrete evaluator primitives
and reimplementing others in terms of SBV primitives.
This commit is contained in:
Rob Dockins 2016-05-30 17:02:08 -07:00
parent bdc4bae638
commit d6c3121678
4 changed files with 391 additions and 504 deletions

View File

@ -19,6 +19,7 @@
module Cryptol.Eval.Value where
import Data.Bits
import Data.IORef
--import Data.Map (Map)
import qualified Data.Map.Strict as Map
@ -336,6 +337,27 @@ class BitWord b w | b -> w, w -> b where
-- most significant bit is the first element of the list.
unpackWord :: w -> [b]
-- | NOTE first argument represents the more-significant bits
joinWord :: w -> w -> w
-- | Take the most-significant bits, and return
-- those bits and the remainder. The first element
-- of the pair is the most significant bits.
splitWord :: Integer -- ^ left width
-> Integer -- ^ right width
-> w
-> (w, w)
extractWord :: Integer -- ^ Number of bits to take
-> Integer -- ^ starting bit
-> w
-> w
wordPlus :: w -> w -> w
wordMinus :: w -> w -> w
wordMult :: w -> w -> w
class BitWord b w => EvalPrims b w where
evalPrim :: Decl -> GenValue b w
iteValue :: b
@ -375,19 +397,39 @@ instance BitWord Bool BV where
where
w' = fromInteger w
joinWord (BV i x) (BV j y) =
BV (i + j) (shiftL x (fromInteger j) + y)
splitWord leftW rightW (BV _ x) =
( BV leftW (x `shiftR` (fromInteger rightW)), mkBv rightW x )
extractWord n i (BV _ x) = mkBv n (x `shiftR` (fromInteger i))
wordPlus (BV i x) (BV j y)
| i == j = mkBv i (x+y)
| otherwise = panic "Attempt to add words of different sizes: wordPlus" []
wordMinus (BV i x) (BV j y)
| i == j = mkBv i (x-y)
| otherwise = panic "Attempt to subtract words of different sizes: wordMinus" []
wordMult (BV i x) (BV j y)
| i == j = mkBv i (x*y)
| otherwise = panic "Attempt to multiply words of different sizes: wordMult" []
-- Value Constructors ----------------------------------------------------------
-- | Create a packed word of n bits.
word :: Integer -> Integer -> Value
word n i = VWord $ mkBv n i
word :: BitWord b w => Integer -> Integer -> GenValue b w
word n i = VWord $ wordLit n i
lam :: (Eval (GenValue b w) -> Eval (GenValue b w)) -> GenValue b w
lam = VFun
-- | Functions that assume word inputs
wlam :: (Integer -> Eval Value) -> Value
wlam f = VFun (\x -> x >>= fromWord "wlam" >>= f)
wlam :: BitWord b w => (w -> Eval (GenValue b w)) -> GenValue b w
wlam f = VFun (\x -> x >>= fromVWord "wlam" >>= f)
-- | A type lambda that expects a @Type@.
tlam :: (TValue -> GenValue b w) -> GenValue b w

View File

@ -91,10 +91,10 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
lam $ \ l -> return $
lam $ \ r -> ccatV front back elty l r)
, ("@" , indexPrimOne indexFront)
, ("@@" , indexPrimMany indexFront)
, ("!" , indexPrimOne indexBack)
, ("!!" , indexPrimMany indexBack)
, ("@" , indexPrimOne indexFront_bits indexFront)
, ("@@" , indexPrimMany indexFront_bits indexFront)
, ("!" , indexPrimOne indexBack_bits indexBack)
, ("!!" , indexPrimMany indexBack_bits indexBack)
, ("zero" , tlam zeroV)
@ -115,18 +115,8 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
, ("fromThen" , fromThenV)
, ("fromTo" , fromToV)
, ("fromThenTo" , fromThenToV)
, ("infFrom" , tlam $ \(finTValue -> bits) ->
wlam $ \first ->
return $ VStream $ SeqMap $ \i ->
ready $ word bits (first+i))
, ("infFromThen", tlam $ \(finTValue -> bits) ->
wlam $ \first -> return $
wlam $ \next -> do
let diff = next - first
return $ VStream $ SeqMap $ \i ->
ready $ word bits (first + diff*i))
, ("infFrom" , infFromV)
, ("infFromThen", infFromThenV)
, ("error" , tlam $ \_ ->
tlam $ \_ ->
@ -147,22 +137,22 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
(bs `shiftL` 1) (as `shiftR` 1) (n-1)
in tlam $ \(finTValue -> a) ->
tlam $ \(finTValue -> b) ->
wlam $ \x -> return $
wlam $ \y -> return $ word (max 1 (a + b) - 1) (mul 0 x y b))
wlam $ \(bvVal -> x) -> return $
wlam $ \(bvVal -> y) -> return $ word (max 1 (a + b) - 1) (mul 0 x y b))
, ("pdiv" , tlam $ \(fromInteger . finTValue -> a) ->
tlam $ \(fromInteger . finTValue -> b) ->
wlam $ \x -> return $
wlam $ \y -> return $ word (toInteger a)
wlam $ \(bvVal -> x) -> return $
wlam $ \(bvVal -> y) -> return $ word (toInteger a)
(fst (divModPoly x a y b)))
, ("pmod" , tlam $ \(fromInteger . finTValue -> a) ->
tlam $ \(fromInteger . finTValue -> b) ->
wlam $ \x -> return $
wlam $ \y -> return $ word (toInteger b)
wlam $ \(bvVal -> x) -> return $
wlam $ \(bvVal -> y) -> return $ word (toInteger b)
(snd (divModPoly x a y (b+1))))
, ("random" , tlam $ \a ->
wlam $ \x -> return $ randomV a x)
wlam $ \(bvVal -> x) -> return $ randomV a x)
, ("trace" , tlam $ \_n ->
tlam $ \_a ->
tlam $ \_b ->
@ -505,16 +495,18 @@ zeroV ty
| otherwise = evalPanic "zeroV" ["invalid type for zero"]
joinWord :: BV -> BV -> BV
joinWord (BV i x) (BV j y) =
BV (i + j) (shiftL x (fromInteger j) + y)
joinWords :: Integer -> Integer -> SeqValMap -> Eval Value -> Eval Value
joinWords :: forall b w
. BitWord b w
=> Integer
-> Integer
-> SeqMap b w
-> Eval (GenValue b w)
-> Eval (GenValue b w)
joinWords nParts nEach xs fallback =
loop (mkBv 0 0) (enumerateSeqMap nParts xs)
loop (wordLit 0 0) (enumerateSeqMap nParts xs)
where
loop :: BV -> [Eval Value] -> Eval Value
loop :: w -> [Eval (GenValue b w)] -> Eval (GenValue b w)
loop !bv [] = return $ VWord bv
loop !bv (Ready (VWord w) : ws) = loop (joinWord bv w) ws
@ -529,7 +521,12 @@ joinWords nParts nEach xs fallback =
-- loop (joinWord bv w') ws
joinSeq :: TValue -> TValue -> TValue -> SeqValMap -> Eval Value
joinSeq :: BitWord b w
=> TValue
-> TValue
-> TValue
-> SeqMap b w
-> Eval (GenValue b w)
joinSeq parts each a xs
| Nat nEach <- numTValue each
= return $ mkSeq $ (SeqMap $ \i -> do
@ -544,7 +541,12 @@ joinSeq parts each a xs
Nat n -> VSeq n (isTBit a)
-- | Join a sequence of sequences into a single sequence.
joinV :: TValue -> TValue -> TValue -> Value -> Eval Value
joinV :: BitWord b w
=> TValue
-> TValue
-> TValue
-> (GenValue b w)
-> Eval (GenValue b w)
joinV parts each a val
-- Try to join a sequence of words, if we can determine that
-- each element is actually a word. Fall back on sequence
@ -559,16 +561,21 @@ joinV parts each a val =
joinSeq parts each a =<< fromSeq val
splitAtV :: TValue -> TValue -> TValue -> Value -> Eval Value
splitAtV :: BitWord b w
=> TValue
-> TValue
-> TValue
-> (GenValue b w)
-> Eval (GenValue b w)
splitAtV front back a val =
case numTValue back of
-- Remember that words are big-endian in cryptol, so the first component
-- needs to be shifted, and the second component just needs to be masked.
Nat rightWidth | aBit, VWord (BV _ i) <- val -> do
Nat rightWidth | aBit, VWord w <- val -> do
let (lw, rw) = splitWord leftWidth rightWidth w
return $ VTuple
[ ready $ VWord (BV leftWidth (i `shiftR` fromInteger rightWidth))
, ready $ VWord (mkBv rightWidth i) ]
[ ready $ VWord lw
, ready $ VWord rw
]
_ -> do
seq <- delay Nothing (fromSeq val)
@ -587,7 +594,8 @@ splitAtV front back a val =
-- | Split implementation.
ecSplitV :: Value
ecSplitV :: BitWord b w
=> GenValue b w
ecSplitV =
tlam $ \ parts ->
tlam $ \ each ->
@ -597,8 +605,7 @@ ecSplitV =
(Nat p, Nat e) | isTBit a -> do
val' <- delay Nothing (fromVWord "split" =<< val)
return $ VSeq p False $ SeqMap $ \i -> do
BV _ x <- val'
return $ VWord $ mkBv e $ (x `shiftR` (fromInteger ((p-i-1)*e)))
VWord . extractWord e ((p-i-1)*e) <$> val'
(Nat p, Nat e) -> do
val' <- delay Nothing (fromSeq =<< val)
return $ VSeq p False $ SeqMap $ \i ->
@ -625,21 +632,29 @@ finChunksOf parts each xs = let (as,bs) = genericSplitAt each xs
in as : finChunksOf (parts - 1) each bs
reverseV :: Value -> Eval Value
reverseV :: forall b w
. BitWord b w
=> GenValue b w
-> Eval (GenValue b w)
reverseV (VSeq n isWord xs) =
return $ VSeq n isWord $ reverseSeqMap n xs
reverseV (VWord w) = return (VWord revword)
where
revword = do
let bs = unpackWord w :: [Bool]
let bs = unpackWord w :: [b]
in packWord $ reverse bs
reverseV _ =
evalPanic "reverseV" ["Not a finite sequence"]
transposeV :: TValue -> TValue -> TValue -> Value -> Eval Value
transposeV :: BitWord b w
=> TValue
-> TValue
-> TValue
-> GenValue b w
-> Eval (GenValue b w)
transposeV a b c xs = do
let bseq =
let bseq =
case numTValue b of
Nat nb -> VSeq nb (isTBit b)
Inf -> VStream
@ -650,10 +665,17 @@ transposeV a b c xs = do
return $ bseq $ SeqMap $ \bi ->
return $ aseq $ SeqMap $ \ai -> do
ys <- flip lookupSeqMap ai =<< fromSeq xs
z <- flip lookupSeqMap bi =<< fromSeq ys
z <- flip lookupSeqMap bi =<< fromSeq ys
return z
ccatV :: TValue -> TValue -> TValue -> Eval Value -> Eval Value -> Eval Value
ccatV :: BitWord b w
=> TValue
-> TValue
-> TValue
-> Eval (GenValue b w)
-> Eval (GenValue b w)
-> Eval (GenValue b w)
ccatV _front _back (isTBit -> True) (Ready (VWord x)) (Ready (VWord y)) =
return $ VWord $ joinWord x y
@ -726,9 +748,9 @@ logicBinary opb opw = loop
| Just fields <- isTRec ty =
return $ VRecord [ (f,loop' fty a b)
| (f,fty) <- fields
| (f,fty) <- fields
, let a = lookupRecord f l
b = lookupRecord f r
b = lookupRecord f r
]
| otherwise = evalPanic "logicBinary" ["invalid logic type"]
@ -858,34 +880,51 @@ rotateRS w _ vs by = SeqMap $ \i ->
-- Sequence Primitives ---------------------------------------------------------
-- | Indexing operations that return one element.
indexPrimOne :: (Maybe Integer -> SeqValMap -> Integer -> Eval Value) -> Value
indexPrimOne op =
indexPrimOne :: BitWord b w
=> (Maybe Integer -> TValue -> SeqMap b w -> [b] -> Eval (GenValue b w))
-> (Maybe Integer -> TValue -> SeqMap b w -> w -> Eval (GenValue b w))
-> GenValue b w
indexPrimOne bits_op word_op =
tlam $ \ n ->
tlam $ \ _a ->
tlam $ \ a ->
tlam $ \ _i ->
lam $ \ l -> return $
lam $ \ r -> do
vs <- fromSeq =<< l
ix <- fromWord "index one" =<< r
op (fromNat (numTValue n)) vs ix
r >>= \case
VWord w ->
word_op (fromNat (numTValue n)) a vs w
VSeq m True xs -> do
bs <- traverse (fromVBit<$>) (enumerateSeqMap m xs)
bits_op (fromNat (numTValue n)) a vs bs
x -> evalPanic "Expected word value" ["indexPrimOne"]
indexFront :: Maybe Integer -> SeqValMap -> Integer -> Eval Value
indexFront mblen vs ix =
indexFront :: Maybe Integer -> TValue -> SeqValMap -> BV -> Eval Value
indexFront mblen _a vs (bvVal -> ix) =
case mblen of
Just len | len <= ix -> invalidIndex ix
_ -> lookupSeqMap vs ix
indexBack :: Maybe Integer -> SeqValMap -> Integer -> Eval Value
indexBack mblen vs ix =
indexFront_bits :: Maybe Integer -> TValue -> SeqValMap -> [Bool] -> Eval Value
indexFront_bits mblen a vs = indexFront mblen a vs . packWord
indexBack :: Maybe Integer -> TValue -> SeqValMap -> BV -> Eval Value
indexBack mblen _a vs (bvVal -> ix) =
case mblen of
Just len | len > ix -> lookupSeqMap vs (len - ix - 1)
| otherwise -> invalidIndex ix
Nothing -> evalPanic "indexBack"
["unexpected infinite sequence"]
indexBack_bits :: Maybe Integer -> TValue -> SeqValMap -> [Bool] -> Eval Value
indexBack_bits mblen a vs = indexBack mblen a vs . packWord
-- | Indexing operations that return many elements.
indexPrimMany :: (Maybe Integer -> SeqValMap -> Integer -> Eval Value) -> Value
indexPrimMany op =
indexPrimMany :: BitWord b w
=> (Maybe Integer -> TValue -> SeqMap b w -> [b] -> Eval (GenValue b w))
-> (Maybe Integer -> TValue -> SeqMap b w -> w -> Eval (GenValue b w))
-> GenValue b w
indexPrimMany bits_op word_op =
tlam $ \ n ->
tlam $ \ a ->
tlam $ \ m ->
@ -895,11 +934,17 @@ indexPrimMany op =
vs <- fromSeq =<< l
ixs <- fromSeq =<< r
mkSeq m a <$> memoMap (SeqMap $ \i -> do
i' <- fromWord "index many" =<< lookupSeqMap ixs i
op (fromNat (numTValue n)) vs i')
lookupSeqMap ixs i >>= \case
VWord w ->
word_op (fromNat (numTValue n)) a vs w
VSeq m True xs -> do
bs <- traverse (fromVBit<$>) (enumerateSeqMap m xs)
bits_op (fromNat (numTValue n)) a vs bs
x -> evalPanic "Expected word value" ["indexPrimMany"])
-- @[ 0, 1 .. ]@
fromThenV :: Value
fromThenV :: BitWord b w
=> GenValue b w
fromThenV =
tlamN $ \ first ->
tlamN $ \ next ->
@ -911,11 +956,12 @@ fromThenV =
(Nat first', Nat next', Nat len', Nat bits') ->
let diff = next' - first'
in VSeq len' False $ SeqMap $ \i ->
ready $ VWord $ BV bits' $ (first' + i*diff)
ready $ VWord $ wordLit bits' (first' + i*diff)
_ -> evalPanic "fromThenV" ["invalid arguments"]
-- @[ 0 .. 10 ]@
fromToV :: Value
fromToV :: BitWord b w
=> GenValue b w
fromToV =
tlamN $ \ first ->
tlamN $ \ lst ->
@ -926,11 +972,12 @@ fromToV =
(Nat first', Nat lst', Nat bits') ->
let len = 1 + (lst' - first')
in VSeq len False $ SeqMap $ \i ->
ready $ VWord $ BV bits' (first' + i)
ready $ VWord $ wordLit bits' (first' + i)
_ -> evalPanic "fromToV" ["invalid arguments"]
-- @[ 0, 1 .. 10 ]@
fromThenToV :: Value
fromThenToV :: BitWord b w
=> GenValue b w
fromThenToV =
tlamN $ \ first ->
tlamN $ \ next ->
@ -943,9 +990,28 @@ fromThenToV =
(Nat first', Nat next', Nat lst', Nat len', Nat bits') ->
let diff = next' - first'
in VSeq len' False $ SeqMap $ \i ->
ready $ VWord $ BV bits' $ (first' + i*diff)
ready $ VWord $ wordLit bits' (first' + i*diff)
_ -> evalPanic "fromThenToV" ["invalid arguments"]
infFromV :: BitWord b w
=> GenValue b w
infFromV =
tlam $ \(finTValue -> bits) ->
wlam $ \first ->
return $ VStream $ SeqMap $ \i ->
ready $ VWord $ wordPlus first (wordLit bits i)
infFromThenV :: BitWord b w
=> GenValue b w
infFromThenV =
tlam $ \(finTValue -> bits) ->
wlam $ \first -> return $
wlam $ \next -> do
let diff = wordMinus next first
return $ VStream $ SeqMap $ \i ->
ready $ VWord $ wordPlus first (wordMult diff (wordLit bits i))
-- Random Values ---------------------------------------------------------------
-- | Produce a random value with the given seed. If we do not support

View File

@ -16,14 +16,20 @@
module Cryptol.Symbolic.Prims where
import Data.Bits
import Data.List (genericDrop, genericReplicate, genericSplitAt, genericTake, sortBy, transpose)
import Data.Ord (comparing)
import Cryptol.Eval.Monad (Eval)
import Cryptol.Eval.Value (BitWord(..), EvalPrims(..), enumerateSeqMap, SeqMap(..))
import Cryptol.Eval.Monad (Eval(..), ready)
import Cryptol.Eval.Value (BitWord(..), EvalPrims(..), enumerateSeqMap, SeqMap(..),
finiteSeqMap, reverseSeqMap)
import Cryptol.Prims.Eval (binary, unary, tlamN, arithUnary,
arithBinary, Binary, BinArith,
logicBinary, logicUnary, zeroV)
logicBinary, logicUnary, zeroV,
ccatV, splitAtV, joinV, ecSplitV,
reverseV, infFromV, infFromThenV,
fromThenV, fromToV, fromThenToV,
transposeV, indexPrimOne, indexPrimMany)
import Cryptol.Symbolic.Value
import Cryptol.TypeCheck.AST (Decl(..))
import Cryptol.TypeCheck.Solver.InfNat(Nat'(..), nMul)
@ -82,6 +88,7 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
, ("^" , binary (logicBinary SBV.svXOr SBV.svXOr))
, ("complement" , unary (logicUnary SBV.svNot SBV.svNot))
, ("zero" , tlam zeroV)
, ("<<" , -- {m,n,a} (fin n) => [m] a -> [n] -> [m] a
tlam $ \m ->
tlam $ \n ->
@ -103,6 +110,7 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
else
lookupSeqMap x' (i+idx)
in selectV len shl =<< y)
, (">>" , -- {m,n,a} (fin n) => [m] a -> [n] -> [m] a
tlam $ \m ->
tlam $ \n ->
@ -110,7 +118,7 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
VFun $ \xs -> return $
VFun $ \y ->
xs >>= \case
VWord x -> VWord . SBV.svShiftLeft x <$> (fromVWord "<<" =<< y)
VWord x -> VWord . SBV.svShiftRight x <$> (fromVWord ">>" =<< y)
x -> do
x' <- fromSeq x
let Nat len = numTValue n
@ -127,173 +135,134 @@ primTable = Map.fromList $ map (\(n, v) -> (mkIdent (T.pack n), v))
return $ zeroV a
else
lookupSeqMap x' (idx-i)
in selectV len shr =<< y)
]
{-
selectV len shr =<< y)
, ("<<<" , -- {m,n,a} (fin m, fin n) => [m] a -> [n] -> [m] a
tlam $ \m ->
tlam $ \_ ->
tlam $ \_ ->
VFun $ \xs ->
tlam $ \n ->
tlam $ \a ->
VFun $ \xs -> return $
VFun $ \y ->
case xs of
VWord x -> VWord (SBV.svRotateLeft x (fromVWord y))
_ -> let rol :: Integer -> Value
rol i = catV (dropV k xs) (takeV k xs)
where k = i `mod` finTValue m
in selectV rol y)
xs >>= \case
VWord x -> VWord . SBV.svRotateLeft x <$> (fromVWord "<<<" =<< y)
x -> do
x' <- fromSeq x
let len = finTValue n
let m' = finTValue m
let rol :: Integer -> Value
rol i = VSeq m' (isTBit a) $ SeqMap $ \idx ->
lookupSeqMap x' ((i+idx) `mod` m')
selectV len rol =<< y)
, (">>>" , -- {m,n,a} (fin m, fin n) => [m] a -> [n] -> [m] a
tlam $ \m ->
tlam $ \_ ->
tlam $ \_ ->
VFun $ \xs ->
tlam $ \n ->
tlam $ \a ->
VFun $ \xs -> return $
VFun $ \y ->
case xs of
VWord x -> VWord (SBV.svRotateRight x (fromVWord y))
_ ->
let ror :: Integer -> Value
ror i = catV (dropV k xs) (takeV k xs)
where k = (- i) `mod` finTValue m
in selectV ror y)
xs >>= \case
VWord x -> VWord . SBV.svRotateRight x <$> (fromVWord ">>>" =<< y)
x -> do
x' <- fromSeq x
let len = finTValue n
let m' = finTValue m
let rol :: Integer -> Value
rol i = VSeq m' (isTBit a) $ SeqMap $ \idx ->
lookupSeqMap x' ((idx+m'-i) `mod` m')
selectV len rol =<< y)
, ("#" , -- {a,b,d} (fin a) => [a] d -> [b] d -> [a + b] d
tlam $ \_ ->
tlam $ \_ ->
tlam $ \_ ->
VFun $ \v1 ->
VFun $ \v2 -> catV v1 v2)
, ("#" , -- {a,b,d} (fin a) => [a] d -> [b] d -> [a + b] d
tlam $ \ front ->
tlam $ \ back ->
tlam $ \ elty ->
lam $ \ l -> return $
lam $ \ r -> ccatV front back elty l r)
, ("splitAt" , -- {a,b,c} (fin a) => [a+b] c -> ([a]c,[b]c)
tlam $ \(finTValue -> a) ->
tlam $ \_ ->
tlam $ \_ ->
VFun $ \v -> VTuple [takeV a v, dropV a v])
, ("splitAt" ,
tlam $ \ front ->
tlam $ \ back ->
tlam $ \ a ->
lam $ \ x ->
splitAtV front back a =<< x)
, ("join" , tlam $ \ parts ->
tlam $ \ each ->
tlam $ \ a -> lam (joinV parts each a))
, ("join" ,
tlam $ \ parts ->
tlam $ \ each ->
tlam $ \ a ->
lam $ \ x ->
joinV parts each a =<< x)
, ("split" , ecSplitV)
, ("reverse" ,
tlam $ \a ->
tlam $ \b ->
lam $ \(fromSeq -> xs) -> toSeq a b (reverse xs))
, ("reverse" , tlam $ \a ->
tlam $ \b ->
lam $ \xs -> reverseV =<< xs)
, ("transpose" ,
tlam $ \a ->
tlam $ \b ->
tlam $ \c ->
lam $ \((map fromSeq . fromSeq) -> xs) ->
case numTValue a of
Nat 0 ->
let v = toSeq a c []
in case numTValue b of
Nat n -> toSeq b (tvSeq a c) $ genericReplicate n v
Inf -> VStream $ repeat v
_ -> toSeq b (tvSeq a c) $ map (toSeq a c) $ transpose xs)
, ("@" , -- {n,a,i} (fin i) => [n]a -> [i] -> a
tlam $ \_ ->
tlam $ \a ->
tlam $ \_ ->
VFun $ \xs ->
VFun $ \y ->
let isInf = case xs of VStream _ -> True; _ -> False
err = zeroV a -- default for out-of-bounds accesses
in atV isInf err (fromSeq xs) y)
, ("@@" , -- {n,a,m,i} (fin i) => [n]a -> [m][i] -> [m]a
tlam $ \_ ->
tlam $ \a ->
tlam $ \_ ->
tlam $ \_ ->
VFun $ \xs ->
VFun $ \ys ->
let isInf = case xs of VStream _ -> True; _ -> False
err = zeroV a -- default for out-of-bounds accesses
in atV_list (isTBit a) isInf err (fromSeq xs) ys)
, ("!" , -- {n,a,i} (fin n, fin i) => [n]a -> [i] -> a
tlam $ \_ ->
tlam $ \a ->
tlam $ \_ ->
VFun $ \xs ->
VFun $ \y ->
let err = zeroV a -- default for out-of-bounds accesses
isInf = False -- type of (!) guarantess finite sequences
in atV isInf err (reverse $ fromSeq xs) y)
, ("!!" , -- {n,a,m,i} (fin n, fin i) => [n]a -> [m][i] -> [m]a
tlam $ \_ ->
tlam $ \a ->
tlam $ \_ ->
tlam $ \_ ->
VFun $ \xs ->
VFun $ \ys ->
let err = zeroV a -- default for out-of-bounds accesses
isInf = False -- type of (!!) guarantess finite sequences
in atV_list (isTBit a) isInf err (reverse $ fromSeq xs) ys)
, ("transpose" , tlam $ \a ->
tlam $ \b ->
tlam $ \c ->
lam $ \xs -> transposeV a b c =<< xs)
, ("fromThen" , fromThenV)
, ("fromTo" , fromToV)
, ("fromThenTo" , fromThenToV)
, ("infFrom" , infFromV)
, ("infFromThen" , infFromThenV)
, ("infFrom" ,
tlam $ \(finTValue -> bits) ->
lam $ \(fromVWord -> first) ->
toStream [ VWord (SBV.svPlus first (literalSWord (fromInteger bits) i)) | i <- [0 ..] ])
, ("@" , indexPrimOne indexFront_bits indexFront)
, ("@@" , indexPrimMany indexFront_bits indexFront)
, ("!" , indexPrimOne indexBack_bits indexBack)
, ("!!" , indexPrimMany indexBack_bits indexBack)
, ("infFromThen" , -- {a} (fin a) => [a] -> [a] -> [inf][a]
tlam $ \_ ->
lam $ \(fromVWord -> first) ->
lam $ \(fromVWord -> next) ->
toStream (map VWord (iterate (SBV.svPlus (SBV.svMinus next first)) first)))
, ("pmult" , -- {a,b} (fin a, fin b) => [a] -> [b] -> [max 1 (a + b) - 1]
tlam $ \(finTValue -> i) ->
tlam $ \(finTValue -> j) ->
VFun $ \v1 -> return $
VFun $ \v2 -> do
let k = max 1 (i + j) - 1
mul _ [] ps = ps
mul as (b:bs) ps = mul (SBV.svFalse : as) bs (ites b (as `addPoly` ps) ps)
xs <- traverse (fromVBit<$>) . enumerateSeqMap i =<< fromSeq =<< v1
ys <- traverse (fromVBit<$>) . enumerateSeqMap j =<< fromSeq =<< v2
let zs = genericTake k (mul xs ys [] ++ repeat SBV.svFalse)
VSeq k True <$> finiteSeqMap (map (ready . VBit) zs))
, ("pdiv" , -- {a,b} (fin a, fin b) => [a] -> [b] -> [a]
tlam $ \(finTValue -> i) ->
tlam $ \(finTValue -> j) ->
VFun $ \v1 -> return $
VFun $ \v2 -> do
xs <- traverse (fromVBit<$>) . enumerateSeqMap i =<< fromSeq =<< v1
ys <- traverse (fromVBit<$>) . enumerateSeqMap j =<< fromSeq =<< v2
let zs = take (fromInteger i) (fst (mdp (reverse xs) (reverse ys)) ++ repeat SBV.svFalse)
VSeq i True <$> finiteSeqMap (map (ready . VBit) (reverse zs)))
, ("pmod" , -- {a,b} (fin a, fin b) => [a] -> [b+1] -> [b]
tlam $ \(finTValue -> i) ->
tlam $ \(finTValue -> j) ->
VFun $ \v1 -> return $
VFun $ \v2 -> do
xs <- traverse (fromVBit<$>) . enumerateSeqMap i =<< fromSeq =<< v1
ys <- traverse (fromVBit<$>) . enumerateSeqMap (j+1) =<< fromSeq =<< v2
let zs = take (fromInteger j) (snd (mdp (reverse xs) (reverse ys)) ++ repeat SBV.svFalse)
VSeq j True <$> finiteSeqMap (map (ready . VBit) (reverse zs)))
-- {at,len} (fin len) => [len][8] -> at
, ("error" ,
tlam $ \at ->
tlam $ \(finTValue -> _len) ->
VFun $ \_msg -> zeroV at) -- error/undefined, is arbitrarily translated to 0
VFun $ \_msg ->
return $ zeroV at) -- error/undefined, is arbitrarily translated to 0
, ("pmult" , -- {a,b} (fin a, fin b) => [a] -> [b] -> [max 1 (a + b) - 1]
tlam $ \(finTValue -> i) ->
tlam $ \(finTValue -> j) ->
VFun $ \v1 ->
VFun $ \v2 ->
let k = max 1 (i + j) - 1
mul _ [] ps = ps
mul as (b:bs) ps = mul (SBV.svFalse : as) bs (ites b (as `addPoly` ps) ps)
xs = map fromVBit (fromSeq v1)
ys = map fromVBit (fromSeq v2)
zs = take (fromInteger k) (mul xs ys [] ++ repeat SBV.svFalse)
in VSeq True (map VBit zs))
, ("pdiv" , -- {a,b} (fin a, fin b) => [a] -> [b] -> [a]
tlam $ \(finTValue -> i) ->
tlam $ \_ ->
VFun $ \v1 ->
VFun $ \v2 ->
let xs = map fromVBit (fromSeq v1)
ys = map fromVBit (fromSeq v2)
zs = take (fromInteger i) (fst (mdp (reverse xs) (reverse ys)) ++ repeat SBV.svFalse)
in VSeq True (map VBit (reverse zs)))
, ("pmod" , -- {a,b} (fin a, fin b) => [a] -> [b+1] -> [b]
tlam $ \_ ->
tlam $ \(finTValue -> j) ->
VFun $ \v1 ->
VFun $ \v2 ->
let xs = map fromVBit (fromSeq v1)
ys = map fromVBit (fromSeq v2)
zs = take (fromInteger j) (snd (mdp (reverse xs) (reverse ys)) ++ repeat SBV.svFalse)
in VSeq True (map VBit (reverse zs)))
, ("random" , panic "Cryptol.Symbolic.Prims.evalECon"
[ "can't symbolically evaluae ECRandom" ])
, ("random" ,
tlam $ \_a ->
lam $ \_x -> return $
panic "Cryptol.Symbolic.Prims.evalECon"
[ "can't symbolically evaluae ECRandom" ])
]
-}
selectV :: Integer -> (Integer -> Value) -> Value -> Eval Value
selectV _len f (VWord v) | Just idx <- SBV.svAsInteger v = return $ f idx
@ -309,133 +278,90 @@ selectV len f v = sel 0 =<< bits
where m1 = sel (offset + 2 ^ length bs) bs
m2 = sel offset bs
{-
asWordList :: [Value] -> Maybe [SWord]
asWordList = go id
where go :: ([SWord] -> [SWord]) -> [Value] -> Maybe [SWord]
indexFront :: Maybe Integer
-> TValue
-> SeqMap SBool SWord
-> SWord
-> Eval Value
indexFront mblen a xs idx
| Just i <- SBV.svAsInteger idx
= lookupSeqMap xs i
| Just n <- mblen
, Just (finTValue -> wlen, a') <- isTSeq a
, isTBit a'
, Just ws <- asWordList (enumerateSeqMap n xs)
= return $ VWord $ SBV.svSelect ws (wordLit wlen 0) idx
| otherwise
= foldr f def [0 .. 2 ^ SBV.intSizeOf idx - 1]
where
k = SBV.kindOf idx
def = ready $ VWord $ SBV.svInteger k 0
f n y = iteValue (SBV.svEqual idx (SBV.svInteger k n)) (lookupSeqMap xs n) y
indexBack :: Maybe Integer
-> TValue
-> SeqMap SBool SWord
-> SWord
-> Eval Value
indexBack (Just n) a xs idx = indexFront (Just n) a (reverseSeqMap n xs) idx
indexBack Nothing _ _ _ = evalPanic "Expected finite sequence" ["indexBack"]
indexFront_bits :: Maybe Integer
-> TValue
-> SeqMap SBool SWord
-> [SBool]
-> Eval Value
indexFront_bits mblen a xs bits0 = go 0 (length bits0) bits0
where
go :: Integer -> Int -> [SBool] -> Eval Value
go i _k []
-- For indices out of range, return 0 arbitrarily
| Just n <- mblen
, i >= n
= return $ zeroV a
| otherwise
= lookupSeqMap xs i
go i k (b:bs)
| Just n <- mblen
, (i `shiftL` k) >= n
= return $ zeroV a
| otherwise
= iteValue b (go ((i `shiftL` 1) + 1) (k-1) bs)
(go (i `shiftL` 1) (k-1) bs)
indexBack_bits :: Maybe Integer
-> TValue
-> SeqMap SBool SWord
-> [SBool]
-> Eval Value
indexBack_bits (Just n) a xs idx = indexFront_bits (Just n) a (reverseSeqMap n xs) idx
indexBack_bits Nothing _ _ _ = evalPanic "Expected finite sequence" ["indexBack_bits"]
asBitList :: [Eval Value] -> Maybe [SBool]
asBitList = go id
where go :: ([SBool] -> [SBool]) -> [Eval Value] -> Maybe [SBool]
go f [] = Just (f [])
go f (VWord x:vs) = go (f . (x:)) vs
go f (VSeq True bs:vs) = go (f . (x:)) vs
where x = packWord $ map fromVBit bs
go f (Ready (VBit b):vs) = go (f . (b:)) vs
go _ _ = Nothing
atV_list :: Bool -- Are the elements of the resulting sequence bits?
-> Bool -- Is this an infinite sequence?
-> Value -- default value
-> [Value] -- values to select
-> Value -- index
-> Value
asWordList :: [Eval Value] -> Maybe [SWord]
asWordList = go id
where go :: ([SWord] -> [SWord]) -> [Eval Value] -> Maybe [SWord]
go f [] = Just (f [])
go f (Ready (VWord x):vs) = go (f . (x:)) vs
go f (Ready (VSeq i True bs):vs) =
case asBitList (enumerateSeqMap i bs) of
Just xs -> go (f . (packWord xs:)) vs
Nothing -> Nothing
go _ _ = Nothing
-- Use SBV selection primitives if possible
-- NB: only examine the list if it is finite
atV_list isBit False def (asWordList -> Just ws) v =
case v of
VSeq _ ys ->
VSeq isBit $ map (VWord . SBV.svSelect ws (fromVWord def) . fromVWord) ys
VStream ys ->
VStream $ map (VWord . SBV.svSelect ws (fromVWord def) . fromVWord) ys
_ -> panic "Cryptol.Symbolic.Prims.atV_list" [ "non-mappable value" ]
atV_list isBit _ def xs v =
case v of
VSeq _ ys ->
VSeq isBit $ map (iteAtV def xs) ys
VStream ys ->
VStream $ map (iteAtV def xs) ys
_ -> panic "Cryptol.Symbolic.Prims.atV_list" [ "non-mappable value" ]
atV :: Bool -- Is this an infinite sequence?
-> Value -- default value
-> [Value] -- values to select
-> Value -- index
-> Value
-- When applicable, use the SBV selection operation
-- NB: only examine the list if it is finite
atV False def (asWordList -> Just ws) i =
VWord $ SBV.svSelect ws (fromVWord def) (fromVWord i)
-- Otherwise, decompose into a sequence of if/then/else operations
atV _ def vs i = iteAtV def vs i
-- Select a value at an index by building a sequence of if/then/else operations
iteAtV :: Value -> [Value] -> Value -> Value
iteAtV def vs i =
case i of
VSeq True (map fromVBit -> bits) -> -- index bits in big-endian order
case foldr weave vs bits of
[] -> def
y : _ -> y
VWord x -> foldr f def (zip [0 .. 2 ^ SBV.intSizeOf x - 1] vs)
where
k = SBV.kindOf x
f (n, v) y = iteValue (SBV.svEqual x (SBV.svInteger k n)) v y
_ -> evalPanic "Cryptol.Symbolic.Prims.selectV" ["Invalid index argument"]
where
weave :: SBool -> [Value] -> [Value]
weave _ [] = []
weave b [x1] = [iteValue b def x1]
weave b (x1 : x2 : xs) = iteValue b x2 x1 : weave b xs
replicateV :: Integer -- ^ number of elements
-> TValue -- ^ type of element
-> Value -- ^ element
-> Value
replicateV n (toTypeVal -> TVBit) x = VSeq True (genericReplicate n x)
replicateV n _ x = VSeq False (genericReplicate n x)
nth :: a -> [a] -> Int -> a
nth def [] _ = def
nth def (x : xs) n
| n == 0 = x
| otherwise = nth def xs (n - 1)
nthV :: Value -> Value -> Integer -> Value
nthV err v n =
case v of
VStream xs -> nth err xs (fromInteger n)
VSeq _ xs -> nth err xs (fromInteger n)
VWord x -> let i = SBV.intSizeOf x - 1 - fromInteger n
in if i < 0 then err else
VBit (SBV.svTestBit x i)
_ -> err
mapV :: Bool -> (Value -> Value) -> Value -> Value
mapV isBit f v =
case v of
VSeq _ xs -> VSeq isBit (map f xs)
VStream xs -> VStream (map f xs)
_ -> panic "Cryptol.Symbolic.Prims.mapV" [ "non-mappable value" ]
catV :: Value -> Value -> Value
catV xs (VStream ys) = VStream (fromSeq xs ++ ys)
catV (VWord x) ys = VWord (SBV.svJoin x (fromVWord ys))
catV xs (VWord y) = VWord (SBV.svJoin (fromVWord xs) y)
catV (VSeq b xs) (VSeq _ ys) = VSeq b (xs ++ ys)
catV _ _ = panic "Cryptol.Symbolic.Prims.catV" [ "non-concatenable value" ]
dropV :: Integer -> Value -> Value
dropV 0 xs = xs
dropV n xs =
case xs of
VSeq b xs' -> VSeq b (genericDrop n xs')
VStream xs' -> VStream (genericDrop n xs')
VWord w -> VWord $ SBV.svExtract (SBV.intSizeOf w - 1 - fromInteger n) 0 w
_ -> panic "Cryptol.Symbolic.Prims.dropV" [ "non-droppable value" ]
takeV :: Integer -> Value -> Value
takeV n xs =
case xs of
VWord w -> VWord $ SBV.svExtract (SBV.intSizeOf w - 1) (SBV.intSizeOf w - fromInteger n) w
VSeq b xs' -> VSeq b (genericTake n xs')
VStream xs' -> VSeq b (genericTake n xs')
where b = case xs' of VBit _ : _ -> True
_ -> False
_ -> panic "Cryptol.Symbolic.Prims.takeV" [ "non-takeable value" ]
-}
-- | Make a numeric constant.
-- { val, bits } (fin val, fin bits, bits >= width val) => [bits]
@ -473,38 +399,6 @@ toTypeVal ty
| Just fields <- isTRec ty = TVRecord [ (n, toTypeVal aty) | (n, aty) <- fields ]
| otherwise = panic "Cryptol.Symbolic.Prims.toTypeVal" [ "bad TValue" ]
-- Arith -----------------------------------------------------------------------
type Binary = TValue -> Value -> Value -> Eval Value
type Unary = TValue -> Value -> Eval Value
-- | Models functions of type `{a} (Arith a) => a -> a -> a`
arithBinary :: (SWord -> SWord -> SWord) -> Binary
arithBinary op = loop . toTypeVal
where
loop ty l r =
case ty of
TVBit -> evalPanic "arithBinop" ["Invalid arguments"]
TVSeq _ TVBit -> VWord (op (fromVWord l) (fromVWord r))
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
TVRecord fs -> VRecord [ (f, loop t (lookupRecord f l) (lookupRecord f r)) | (f, t) <- fs ]
TVFun _ t -> VFun (\x -> loop t (fromVFun l x) (fromVFun r x))
-- | Models functions of type `{a} (Arith a) => a -> a`
arithUnary :: (SWord -> SWord) -> Unary
arithUnary op = loop . toTypeVal
where
loop ty v =
case ty of
TVBit -> evalPanic "arithUnary" ["Invalid arguments"]
TVSeq _ TVBit -> VWord (op (fromVWord v))
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
TVStream t -> VStream (map (loop t) (fromSeq v))
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
TVRecord fs -> VRecord [ (f, loop t (lookupRecord f v)) | (f, t) <- fs ]
TVFun _ t -> VFun (\x -> loop t (fromVFun v x))
-}
liftBinArith :: (SWord -> SWord -> SWord) -> BinArith SWord
@ -579,138 +473,6 @@ cmpBinary :: (SBool -> SBool -> Eval SBool -> Eval SBool)
-> SBool -> Binary SBool SWord
cmpBinary fb fw b _ty v1 v2 = VBit <$> cmpValue fb fw v1 v2 (return b)
{-
-- Logic -----------------------------------------------------------------------
errorV :: String -> TValue -> Value
errorV msg = go . toTypeVal
where
go ty =
case ty of
TVBit -> VBit (error msg)
TVSeq n t -> VSeq False (replicate n (go t))
TVStream t -> VStream (repeat (go t))
TVTuple ts -> VTuple [ go t | t <- ts ]
TVRecord fs -> VRecord [ (n, go t) | (n, t) <- fs ]
TVFun _ t -> VFun (const (go t))
zeroV :: TValue -> Value
zeroV = go . toTypeVal
where
go ty =
case ty of
TVBit -> VBit SBV.svFalse
TVSeq n TVBit -> VWord (literalSWord n 0)
TVSeq n t -> VSeq False (replicate n (go t))
TVStream t -> VStream (repeat (go t))
TVTuple ts -> VTuple [ go t | t <- ts ]
TVRecord fs -> VRecord [ (n, go t) | (n, t) <- fs ]
TVFun _ t -> VFun (const (go t))
-- | Join a sequence of sequences into a single sequence.
joinV :: TValue -> TValue -> TValue -> Value -> Value
joinV parts each a v =
let len = toNumTValue (numTValue parts `nMul` numTValue each)
in toSeq len a (concatMap fromSeq (fromSeq v))
-- | Split implementation.
ecSplitV :: Value
ecSplitV =
tlam $ \ parts ->
tlam $ \ each ->
tlam $ \ a ->
lam $ \ v ->
let mkChunks f = map (toFinSeq a) $ f $ fromSeq v
in case (numTValue parts, numTValue each) of
(Nat p, Nat e) -> VSeq False $ mkChunks (finChunksOf p e)
(Inf , Nat e) -> toStream $ mkChunks (infChunksOf e)
_ -> evalPanic "splitV" ["invalid type arguments to split"]
-- | Split into infinitely many chunks
infChunksOf :: Integer -> [a] -> [[a]]
infChunksOf each xs = let (as,bs) = genericSplitAt each xs
in as : infChunksOf each bs
-- | Split into finitely many chunks
finChunksOf :: Integer -> Integer -> [a] -> [[a]]
finChunksOf 0 _ _ = []
finChunksOf parts each xs = let (as,bs) = genericSplitAt each xs
in as : finChunksOf (parts - 1) each bs
-- | Merge two values given a binop. This is used for and, or and xor.
logicBinary :: (SBool -> SBool -> SBool) -> (SWord -> SWord -> SWord) -> Binary
logicBinary bop op = loop . toTypeVal
where
loop ty l r =
case ty of
TVBit -> VBit (bop (fromVBit l) (fromVBit r))
TVSeq _ TVBit -> VWord (op (fromVWord l) (fromVWord r))
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
TVRecord fs -> VRecord [ (f, loop t (lookupRecord f l) (lookupRecord f r)) | (f, t) <- fs ]
TVFun _ t -> VFun (\x -> loop t (fromVFun l x) (fromVFun r x))
logicUnary :: (SBool -> SBool) -> (SWord -> SWord) -> Unary
logicUnary bop op = loop . toTypeVal
where
loop ty v =
case ty of
TVBit -> VBit (bop (fromVBit v))
TVSeq _ TVBit -> VWord (op (fromVWord v))
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
TVStream t -> VStream (map (loop t) (fromSeq v))
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
TVRecord fs -> VRecord [ (f, loop t (lookupRecord f v)) | (f, t) <- fs ]
TVFun _ t -> VFun (\x -> loop t (fromVFun v x))
-- @[ 0, 1 .. ]@
fromThenV :: Value
fromThenV =
tlamN $ \ first ->
tlamN $ \ next ->
tlamN $ \ bits ->
tlamN $ \ len ->
case (first, next, len, bits) of
(Nat first', Nat next', Nat len', Nat bits') ->
let nums = enumFromThen first' next'
lit i = VWord (literalSWord (fromInteger bits') i)
in VSeq False (genericTake len' (map lit nums))
_ -> evalPanic "fromThenV" ["invalid arguments"]
-- @[ 0 .. 10 ]@
fromToV :: Value
fromToV =
tlamN $ \ first ->
tlamN $ \ lst ->
tlamN $ \ bits ->
case (first, lst, bits) of
(Nat first', Nat lst', Nat bits') ->
let nums = enumFromThenTo first' (first' + 1) lst'
len = 1 + (lst' - first')
lit i = VWord (literalSWord (fromInteger bits') i)
in VSeq False (genericTake len (map lit nums))
_ -> evalPanic "fromThenV" ["invalid arguments"]
-- @[ 0, 1 .. 10 ]@
fromThenToV :: Value
fromThenToV =
tlamN $ \ first ->
tlamN $ \ next ->
tlamN $ \ lst ->
tlamN $ \ bits ->
tlamN $ \ len ->
case (first, next, lst, len, bits) of
(Nat first', Nat next', Nat lst', Nat len', Nat bits') ->
let nums = enumFromThenTo first' next' lst'
lit i = VWord (literalSWord (fromInteger bits') i)
in VSeq False (genericTake len' (map lit nums))
_ -> evalPanic "fromThenV" ["invalid arguments"]
-- Polynomials -----------------------------------------------------------------
-- TODO: Data.SBV.BitVectors.Polynomials should export ites, addPoly,
@ -755,6 +517,7 @@ mdp xs ys = go (length ys - 1) (reverse ys)
ys' = replicate degQuot SBV.svFalse ++ ys
(qs, rs) = divx (degQuot+1) degTop xs ys'
-- return the element at index i; if not enough elements, return false
-- N.B. equivalent to '(xs ++ repeat false) !! i', but more efficient
idx :: [SBool] -> Int -> SBool
@ -768,4 +531,3 @@ divx n i xs ys' = (q:qs, rs)
where q = xs `idx` i
xs' = ites q (xs `addPoly` ys') xs
(qs, rs) = divx (n-1) (i-1) xs' (tail ys')
-}

View File

@ -118,9 +118,26 @@ instance BitWord SBool SWord where
| Just x <- svAsInteger v = ppBV opts (BV (wordLen v) x)
| otherwise = text "[?]"
bitLit b = svBool b
wordLit n x = svInteger (KBounded False (fromInteger n)) x
packWord bs = fromBitsLE (reverse bs)
unpackWord x = [ svTestBit x i | i <- reverse [0 .. intSizeOf x - 1] ]
joinWord x y = svJoin x y
splitWord leftW rightW w =
( svExtract (intSizeOf w - 1) (fromInteger rightW) w
, svExtract (fromInteger rightW - 1) 0 w
)
extractWord len start w =
svExtract (fromInteger start + fromInteger len) (fromInteger start) w
wordPlus = svPlus
wordMinus = svMinus
wordMult = svTimes
-- Errors ----------------------------------------------------------------------
evalPanic :: String -> [String] -> a