mirror of
https://github.com/anoma/juvix.git
synced 2025-01-05 22:46:08 +03:00
Add builtin ByteArray type (#2933)
This PR adds support for a builtin `ByteArray` type and associated
functions for constructing a `ByteArray` from a list of bytes and a
function to query the size of the `ByteArray`. It is only available in
the Anoma backend.
In Core / Tree, ByteArray constant is stored using a Haskell ByteString.
In Anoma the ByteArray is stored as a cell where the head is the length
of the ByteArray and the tail is an integer is an integer formed by
concatenating the bytes in the array using little-endian byte ordering.
The Nock for constructing a `ByteArray` uses the `length`, `add`,
`folder` and `lsh` functions from the Anoma hoon stdlib. See the [code
comment](fa068a30e7/src/Juvix/Compiler/Nockma/StdlibFunction.hs (L37)
)
for more details.
Example:
```
module test082;
import Stdlib.Prelude open;
import Stdlib.Debug.Trace open;
builtin bytearray
axiom ByteArray : Type;
builtin bytearray-from-list-byte
axiom mkByteArray : List Byte -> ByteArray;
builtin bytearray-size
axiom size : ByteArray -> Nat;
bs0 : ByteArray := mkByteArray [];
bs1 : ByteArray := mkByteArray [0x0; 0x0; 0x0];
bs2 : ByteArray := mkByteArray [0x1; 0x0; 0x0; 0x0];
bs3 : ByteArray := mkByteArray [0x2; 0x1];
bs4 : ByteArray := mkByteArray [0x100];
main : ByteArray :=
trace (size bs0)
>-> trace bs0
>-> trace (size bs1)
>-> trace bs1
>-> trace (size bs2)
>-> trace bs2
>-> trace (size bs3)
>-> trace bs3
>-> trace (size bs4)
>-> bs4;
```
Output using `tests/Anoma/Compilation/positive/test082.juvix`
```
$ juvix compile anoma -g test082.juvix
$ juvix dev nockma run test082.pretty.nockma
0
[0 0]
3
[3 0]
4
[4 1]
2
[2 258]
1
[1 0]
```
This commit is contained in:
parent
2b5ece7b28
commit
ce5c2c5c55
@ -110,6 +110,7 @@ getConstantType = \case
|
||||
ConstUnit -> TyUnit
|
||||
ConstVoid -> TyVoid
|
||||
ConstUInt8 {} -> mkTypeUInt8
|
||||
ConstByteArray {} -> TyByteArray
|
||||
|
||||
getValueType' :: (Member (Error AsmError) r) => Maybe Location -> InfoTable -> Memory -> Value -> Sem r Type
|
||||
getValueType' loc tab mem = \case
|
||||
|
@ -39,6 +39,7 @@ genCode fi =
|
||||
Tree.Binop x -> goBinop isTail x
|
||||
Tree.Unop x -> goUnop isTail x
|
||||
Tree.Cairo x -> goCairo isTail x
|
||||
Tree.ByteArray {} -> error "ByteArray instructions are not supported in the Asm backend"
|
||||
Tree.Anoma {} -> error "Anoma instructions are not supported in the Asm backend"
|
||||
Tree.Constant x -> goConstant isTail x
|
||||
Tree.MemRef x -> goMemRef isTail x
|
||||
|
@ -350,6 +350,7 @@ fromRegInstr bNoStack info = \case
|
||||
Reg.ConstUnit -> macroVar "OBJ_UNIT"
|
||||
Reg.ConstVoid -> macroVar "OBJ_VOID"
|
||||
Reg.ConstUInt8 x -> macroCall "make_smallint" [integer x]
|
||||
Reg.ConstByteArray {} -> impossible
|
||||
|
||||
fromPrealloc :: Reg.InstrPrealloc -> Statement
|
||||
fromPrealloc Reg.InstrPrealloc {..} =
|
||||
|
@ -251,6 +251,7 @@ fromRegInstr info = \case
|
||||
Reg.ConstUnit -> mkVar "OBJ_UNIT"
|
||||
Reg.ConstVoid -> mkVar "OBJ_VOID"
|
||||
Reg.ConstUInt8 x -> mkCall "make_smallint" [mkInteger x]
|
||||
Reg.ConstByteArray {} -> impossible
|
||||
|
||||
fromAlloc :: Reg.InstrAlloc -> [Statement]
|
||||
fromAlloc Reg.InstrAlloc {..} =
|
||||
|
@ -13,12 +13,14 @@ module Juvix.Compiler.Builtins
|
||||
module Juvix.Compiler.Builtins.Anoma,
|
||||
module Juvix.Compiler.Builtins.Cairo,
|
||||
module Juvix.Compiler.Builtins.Byte,
|
||||
module Juvix.Compiler.Builtins.ByteArray,
|
||||
)
|
||||
where
|
||||
|
||||
import Juvix.Compiler.Builtins.Anoma
|
||||
import Juvix.Compiler.Builtins.Bool
|
||||
import Juvix.Compiler.Builtins.Byte
|
||||
import Juvix.Compiler.Builtins.ByteArray
|
||||
import Juvix.Compiler.Builtins.Cairo
|
||||
import Juvix.Compiler.Builtins.Control
|
||||
import Juvix.Compiler.Builtins.Debug
|
||||
|
27
src/Juvix/Compiler/Builtins/ByteArray.hs
Normal file
27
src/Juvix/Compiler/Builtins/ByteArray.hs
Normal file
@ -0,0 +1,27 @@
|
||||
module Juvix.Compiler.Builtins.ByteArray where
|
||||
|
||||
import Juvix.Compiler.Builtins.Effect
|
||||
import Juvix.Compiler.Internal.Extra
|
||||
import Juvix.Prelude
|
||||
|
||||
registerByteArray :: (Member Builtins r) => AxiomDef -> Sem r ()
|
||||
registerByteArray d = do
|
||||
unless (isSmallUniverse' (d ^. axiomType)) (error "ByteArray should be in the small universe")
|
||||
registerBuiltin BuiltinByteArray (d ^. axiomName)
|
||||
|
||||
registerByteArrayFromListByte :: (Member Builtins r) => AxiomDef -> Sem r ()
|
||||
registerByteArrayFromListByte d = do
|
||||
let loc = getLoc d
|
||||
byte_ <- getBuiltinName loc BuiltinByte
|
||||
list_ <- getBuiltinName loc BuiltinList
|
||||
byteArray <- getBuiltinName loc BuiltinByteArray
|
||||
unless (d ^. axiomType == (list_ @@ byte_ --> byteArray)) (error "bytearray-from-list-byte has the wrong type")
|
||||
registerBuiltin BuiltinByteArrayFromListByte (d ^. axiomName)
|
||||
|
||||
registerByteArrayLength :: (Member Builtins r) => AxiomDef -> Sem r ()
|
||||
registerByteArrayLength d = do
|
||||
let loc = getLoc d
|
||||
byteArray <- getBuiltinName loc BuiltinByteArray
|
||||
nat_ <- getBuiltinName loc BuiltinNat
|
||||
unless (d ^. axiomType == (byteArray --> nat_)) (error "bytearray-length has the wrong type")
|
||||
registerBuiltin BuiltinByteArrayLength (d ^. axiomName)
|
@ -250,6 +250,7 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
|
||||
Reg.ConstVoid -> 0
|
||||
Reg.ConstString {} -> unsupported "strings"
|
||||
Reg.ConstUInt8 {} -> unsupported "uint8"
|
||||
Reg.ConstByteArray {} -> unsupported "bytearray"
|
||||
|
||||
mkLoad :: Reg.ConstrField -> Sem r RValue
|
||||
mkLoad Reg.ConstrField {..} = do
|
||||
|
@ -222,6 +222,9 @@ data BuiltinAxiom
|
||||
| BuiltinByteEq
|
||||
| BuiltinByteToNat
|
||||
| BuiltinByteFromNat
|
||||
| BuiltinByteArray
|
||||
| BuiltinByteArrayFromListByte
|
||||
| BuiltinByteArrayLength
|
||||
deriving stock (Show, Eq, Ord, Enum, Bounded, Generic, Data)
|
||||
|
||||
instance HasNameKind BuiltinAxiom where
|
||||
@ -263,7 +266,9 @@ instance HasNameKind BuiltinAxiom where
|
||||
BuiltinByteEq -> KNameFunction
|
||||
BuiltinByteToNat -> KNameFunction
|
||||
BuiltinByteFromNat -> KNameFunction
|
||||
|
||||
BuiltinByteArray -> KNameInductive
|
||||
BuiltinByteArrayFromListByte -> KNameFunction
|
||||
BuiltinByteArrayLength -> KNameFunction
|
||||
getNameKindPretty :: BuiltinAxiom -> NameKind
|
||||
getNameKindPretty = getNameKind
|
||||
|
||||
@ -312,6 +317,9 @@ instance Pretty BuiltinAxiom where
|
||||
BuiltinByteEq -> Str.byteEq
|
||||
BuiltinByteToNat -> Str.byteToNat
|
||||
BuiltinByteFromNat -> Str.byteFromNat
|
||||
BuiltinByteArray -> Str.byteArray
|
||||
BuiltinByteArrayFromListByte -> Str.byteArrayFromListByte
|
||||
BuiltinByteArrayLength -> Str.byteArrayLength
|
||||
|
||||
data BuiltinType
|
||||
= BuiltinTypeInductive BuiltinInductive
|
||||
|
@ -288,6 +288,17 @@ declareMaybeBuiltins = do
|
||||
(tagJust, "just", mkPi' mkDynamic', Just BuiltinMaybeJust)
|
||||
]
|
||||
|
||||
declareListBuiltins :: (Member InfoTableBuilder r) => Sem r ()
|
||||
declareListBuiltins = do
|
||||
tagNil <- freshTag
|
||||
tagCons <- freshTag
|
||||
declareInductiveBuiltins
|
||||
"BuiltinList"
|
||||
(Just (BuiltinTypeInductive BuiltinList))
|
||||
[ (tagNil, "builtinListNil", mkPis' [mkSmallUniv], Just BuiltinListNil),
|
||||
(tagCons, "builtinListCons", \x -> mkPis' [mkSmallUniv, mkDynamic', x] x, Just BuiltinListCons)
|
||||
]
|
||||
|
||||
reserveLiteralIntToNatSymbol :: (Member InfoTableBuilder r) => Sem r ()
|
||||
reserveLiteralIntToNatSymbol = do
|
||||
sym <- freshSymbol
|
||||
|
@ -2,6 +2,7 @@ module Juvix.Compiler.Core.Evaluator where
|
||||
|
||||
import Control.Exception qualified as Exception
|
||||
import Crypto.Sign.Ed25519 qualified as E
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Data.Serialize qualified as S
|
||||
import GHC.Base (seq)
|
||||
@ -215,6 +216,8 @@ geval opts herr tab env0 = eval' env0
|
||||
OpRandomEcPoint -> randomEcPointOp
|
||||
OpUInt8ToInt -> uint8ToIntOp
|
||||
OpUInt8FromInt -> uint8FromIntOp
|
||||
OpByteArrayFromListByte -> byteArrayFromListByteOp
|
||||
OpByteArrayLength -> byteArrayLengthOp
|
||||
where
|
||||
err :: Text -> a
|
||||
err msg = evalError msg n
|
||||
@ -533,6 +536,30 @@ geval opts herr tab env0 = eval' env0
|
||||
. uint8FromNode
|
||||
$ v
|
||||
{-# INLINE uint8ToIntOp #-}
|
||||
|
||||
byteArrayFromListByteOp :: [Node] -> Node
|
||||
byteArrayFromListByteOp =
|
||||
unary $ \node ->
|
||||
let !v = eval' env node
|
||||
in nodeFromByteString
|
||||
. BS.pack
|
||||
. fromMaybe (evalError "expected list byte" v)
|
||||
. listUInt8FromNode
|
||||
$ v
|
||||
{-# INLINE byteArrayFromListByteOp #-}
|
||||
|
||||
byteArrayLengthOp :: [Node] -> Node
|
||||
byteArrayLengthOp =
|
||||
unary $ \node ->
|
||||
let !v = eval' env node
|
||||
in nodeFromInteger
|
||||
. fromIntegral
|
||||
. BS.length
|
||||
. fromMaybe (evalError "expected bytearray" v)
|
||||
. byteArrayFromNode
|
||||
$ v
|
||||
{-# INLINE byteArrayLengthOp #-}
|
||||
|
||||
{-# INLINE applyBuiltin #-}
|
||||
|
||||
-- secretKey, publicKey are not encoded with their length as
|
||||
@ -558,6 +585,10 @@ geval opts herr tab env0 = eval' env0
|
||||
nodeFromUInt8 !w = mkConstant' (ConstUInt8 w)
|
||||
{-# INLINE nodeFromUInt8 #-}
|
||||
|
||||
nodeFromByteString :: ByteString -> Node
|
||||
nodeFromByteString !b = mkConstant' (ConstByteArray b)
|
||||
{-# INLINE nodeFromByteString #-}
|
||||
|
||||
nodeFromBool :: Bool -> Node
|
||||
nodeFromBool b = mkConstr' (BuiltinTag tag) []
|
||||
where
|
||||
@ -567,10 +598,10 @@ geval opts herr tab env0 = eval' env0
|
||||
{-# INLINE nodeFromBool #-}
|
||||
|
||||
mkBuiltinConstructor :: BuiltinConstructor -> [Node] -> Maybe Node
|
||||
mkBuiltinConstructor ctor args =
|
||||
(\tag -> mkConstr' tag args)
|
||||
. (^. constructorTag)
|
||||
<$> lookupTabBuiltinConstructor tab ctor
|
||||
mkBuiltinConstructor ctor args = (\tag -> mkConstr' tag args) <$> builtinConstructorTag ctor
|
||||
|
||||
builtinConstructorTag :: BuiltinConstructor -> Maybe Tag
|
||||
builtinConstructorTag ctor = (^. constructorTag) <$> lookupTabBuiltinConstructor tab ctor
|
||||
|
||||
nodeMaybeNothing :: Node
|
||||
nodeMaybeNothing =
|
||||
@ -611,6 +642,29 @@ geval opts herr tab env0 = eval' env0
|
||||
_ -> Nothing
|
||||
{-# INLINE uint8FromNode #-}
|
||||
|
||||
byteArrayFromNode :: Node -> Maybe ByteString
|
||||
byteArrayFromNode = \case
|
||||
NCst (Constant _ (ConstByteArray b)) -> Just b
|
||||
_ -> Nothing
|
||||
{-# INLINE byteArrayFromNode #-}
|
||||
|
||||
listUInt8FromNode :: Node -> Maybe [Word8]
|
||||
listUInt8FromNode = \case
|
||||
NCtr (Constr _ t xs) -> do
|
||||
consTag <- builtinConstructorTag BuiltinListCons
|
||||
nilTag <- builtinConstructorTag BuiltinListNil
|
||||
if
|
||||
| t == nilTag -> return []
|
||||
| t == consTag -> case (filter (not . isType') xs) of
|
||||
(hd : tl) -> do
|
||||
uint8Hd <- uint8FromNode hd
|
||||
uint8Tl <- concatMapM listUInt8FromNode tl
|
||||
return (uint8Hd : uint8Tl)
|
||||
_ -> Nothing
|
||||
| otherwise -> Nothing
|
||||
_ -> Nothing
|
||||
{-# INLINE listUInt8FromNode #-}
|
||||
|
||||
printNode :: Node -> Text
|
||||
printNode = \case
|
||||
NCst (Constant _ (ConstString s)) -> s
|
||||
|
@ -200,6 +200,12 @@ mkTypeUInt8 i = mkTypePrim i primitiveUInt8
|
||||
mkTypeUInt8' :: Type
|
||||
mkTypeUInt8' = mkTypeUInt8 Info.empty
|
||||
|
||||
mkTypeByteArray :: Info -> Type
|
||||
mkTypeByteArray i = mkTypePrim i PrimByteArray
|
||||
|
||||
mkTypeByteArray' :: Type
|
||||
mkTypeByteArray' = mkTypeByteArray Info.empty
|
||||
|
||||
mkDynamic :: Info -> Type
|
||||
mkDynamic i = NDyn (DynamicTy i)
|
||||
|
||||
|
@ -435,6 +435,8 @@ builtinOpArgTypes = \case
|
||||
OpRandomEcPoint -> []
|
||||
OpUInt8ToInt -> [mkTypeUInt8']
|
||||
OpUInt8FromInt -> [mkTypeInteger']
|
||||
OpByteArrayFromListByte -> [mkDynamic']
|
||||
OpByteArrayLength -> [mkTypeByteArray']
|
||||
|
||||
translateCase :: (Node -> Node -> Node -> a) -> a -> Case -> a
|
||||
translateCase translateIfFun dflt Case {..} = case _caseBranches of
|
||||
|
@ -19,6 +19,8 @@ import Juvix.Data.Keyword.All
|
||||
kwBind,
|
||||
kwBottom,
|
||||
kwBuiltin,
|
||||
kwByteArrayFromListByte,
|
||||
kwByteArrayLength,
|
||||
kwCase,
|
||||
kwColon,
|
||||
kwComma,
|
||||
|
@ -38,6 +38,8 @@ data BuiltinOp
|
||||
| OpRandomEcPoint
|
||||
| OpUInt8ToInt
|
||||
| OpUInt8FromInt
|
||||
| OpByteArrayFromListByte
|
||||
| OpByteArrayLength
|
||||
deriving stock (Eq, Generic)
|
||||
|
||||
instance Serialize BuiltinOp
|
||||
@ -94,6 +96,8 @@ builtinOpArgsNum = \case
|
||||
OpRandomEcPoint -> 0
|
||||
OpUInt8ToInt -> 1
|
||||
OpUInt8FromInt -> 1
|
||||
OpByteArrayFromListByte -> 1
|
||||
OpByteArrayLength -> 1
|
||||
|
||||
builtinConstrArgsNum :: BuiltinDataTag -> Int
|
||||
builtinConstrArgsNum = \case
|
||||
@ -139,6 +143,8 @@ builtinIsFoldable = \case
|
||||
OpRandomEcPoint -> False
|
||||
OpUInt8ToInt -> True
|
||||
OpUInt8FromInt -> True
|
||||
OpByteArrayFromListByte -> False
|
||||
OpByteArrayLength -> False
|
||||
|
||||
builtinIsCairo :: BuiltinOp -> Bool
|
||||
builtinIsCairo op = op `elem` builtinsCairo
|
||||
@ -146,6 +152,9 @@ builtinIsCairo op = op `elem` builtinsCairo
|
||||
builtinIsAnoma :: BuiltinOp -> Bool
|
||||
builtinIsAnoma op = op `elem` builtinsAnoma
|
||||
|
||||
builtinIsByteArray :: BuiltinOp -> Bool
|
||||
builtinIsByteArray op = op `elem` builtinsByteArray
|
||||
|
||||
builtinsString :: [BuiltinOp]
|
||||
builtinsString = [OpStrConcat, OpStrToInt, OpShow]
|
||||
|
||||
@ -165,3 +174,6 @@ builtinsAnoma =
|
||||
|
||||
builtinsUInt8 :: [BuiltinOp]
|
||||
builtinsUInt8 = [OpUInt8FromInt, OpUInt8ToInt]
|
||||
|
||||
builtinsByteArray :: [BuiltinOp]
|
||||
builtinsByteArray = [OpByteArrayFromListByte, OpByteArrayLength]
|
||||
|
@ -39,6 +39,7 @@ data ConstantValue
|
||||
| ConstField !FField
|
||||
| ConstString !Text
|
||||
| ConstUInt8 !Word8
|
||||
| ConstByteArray !ByteString
|
||||
deriving stock (Eq, Generic)
|
||||
|
||||
-- | Info about a single binder. Associated with Lambda, Pi, Let, Case or Match.
|
||||
|
@ -15,6 +15,7 @@ data Primitive
|
||||
| PrimBool PrimBoolInfo
|
||||
| PrimString
|
||||
| PrimField
|
||||
| PrimByteArray
|
||||
deriving stock (Eq, Generic)
|
||||
|
||||
primitiveUInt8 :: Primitive
|
||||
|
@ -5,6 +5,7 @@ module Juvix.Compiler.Core.Pretty.Base
|
||||
)
|
||||
where
|
||||
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Data.Map.Strict qualified as Map
|
||||
import Juvix.Compiler.Core.Data.BinderList qualified as BL
|
||||
@ -64,6 +65,8 @@ instance PrettyCode BuiltinOp where
|
||||
OpRandomEcPoint -> return primRandomEcPoint
|
||||
OpUInt8ToInt -> return primUInt8ToInt
|
||||
OpUInt8FromInt -> return primFieldFromInt
|
||||
OpByteArrayFromListByte -> return primByteArrayFromListByte
|
||||
OpByteArrayLength -> return primByteArrayLength
|
||||
|
||||
instance PrettyCode BuiltinDataTag where
|
||||
ppCode = \case
|
||||
@ -81,10 +84,12 @@ instance PrettyCode Tag where
|
||||
|
||||
instance PrettyCode Primitive where
|
||||
ppCode = \case
|
||||
p@(PrimInteger _) | p == primitiveUInt8 -> return $ annotate (AnnKind KNameInductive) (pretty ("UInt8" :: String))
|
||||
PrimInteger _ -> return $ annotate (AnnKind KNameInductive) (pretty ("Int" :: String))
|
||||
PrimField -> return $ annotate (AnnKind KNameInductive) (pretty ("Field" :: String))
|
||||
PrimBool _ -> return $ annotate (AnnKind KNameInductive) (pretty ("Bool" :: String))
|
||||
PrimString -> return $ annotate (AnnKind KNameInductive) (pretty ("String" :: String))
|
||||
PrimByteArray -> return $ annotate (AnnKind KNameInductive) (pretty ("ByteArray" :: String))
|
||||
|
||||
ppName :: NameKind -> Text -> Sem r (Doc Ann)
|
||||
ppName kind name = return $ annotate (AnnKind kind) (pretty name)
|
||||
@ -104,6 +109,7 @@ ppCodeVar' name v = do
|
||||
else return name'
|
||||
|
||||
instance PrettyCode ConstantValue where
|
||||
ppCode :: forall r. (Member (Reader Options) r) => ConstantValue -> Sem r (Doc Ann)
|
||||
ppCode = \case
|
||||
ConstInteger int ->
|
||||
return $ annotate AnnLiteralInteger (pretty int)
|
||||
@ -113,13 +119,31 @@ instance PrettyCode ConstantValue where
|
||||
return $ annotate AnnLiteralInteger (pretty i)
|
||||
ConstString txt ->
|
||||
return $ annotate AnnLiteralString (pretty (show txt :: String))
|
||||
ConstByteArray bs -> do
|
||||
let bytes = ConstUInt8 <$> BS.unpack bs
|
||||
codeBs <- mapM ppCode bytes
|
||||
bytesList <- go codeBs
|
||||
op <- ppCode OpByteArrayFromListByte
|
||||
return (op <+> bytesList)
|
||||
where
|
||||
go :: [Doc Ann] -> Sem r (Doc Ann)
|
||||
go xs = do
|
||||
uint8Ty <- ppCode mkTypeUInt8'
|
||||
case xs of
|
||||
[] -> return (parens (kwBuiltinNil <+> uint8Ty))
|
||||
(d : ds) -> do
|
||||
next <- go ds
|
||||
return (parens (kwBuiltinCons <+> uint8Ty <+> d <+> next))
|
||||
|
||||
instance PrettyCode Word8 where
|
||||
ppCode i = return (pretty i <> "u8")
|
||||
|
||||
instance PrettyCode (Constant' i) where
|
||||
ppCode Constant {..} = case _constantValue of
|
||||
ConstField fld ->
|
||||
return $ annotate AnnLiteralInteger (pretty fld <> "F")
|
||||
ConstUInt8 i ->
|
||||
return $ annotate AnnLiteralInteger (pretty i <> "u8")
|
||||
annotate AnnLiteralInteger <$> ppCode i
|
||||
_ -> ppCode _constantValue
|
||||
|
||||
instance (PrettyCode a, HasAtomicity a) => PrettyCode (App' i a) where
|
||||
@ -548,7 +572,7 @@ instance PrettyCode InfoTable where
|
||||
shouldPrintInductive :: Maybe BuiltinType -> Bool
|
||||
shouldPrintInductive = \case
|
||||
Just (BuiltinTypeInductive i) -> case i of
|
||||
BuiltinList -> True
|
||||
BuiltinList -> False
|
||||
BuiltinMaybe -> False
|
||||
BuiltinPair -> True
|
||||
BuiltinPoseidonState -> True
|
||||
@ -761,6 +785,12 @@ primUInt8FromInt = primitive Str.itou8
|
||||
primFieldToInt :: Doc Ann
|
||||
primFieldToInt = primitive Str.ftoi
|
||||
|
||||
primByteArrayFromListByte :: Doc Ann
|
||||
primByteArrayFromListByte = primitive Str.byteArrayFromListByte
|
||||
|
||||
primByteArrayLength :: Doc Ann
|
||||
primByteArrayLength = primitive Str.byteArrayLength
|
||||
|
||||
primLess :: Doc Ann
|
||||
primLess = primitive Str.less
|
||||
|
||||
@ -868,3 +898,9 @@ kwBottomAscii = keyword Str.bottomAscii
|
||||
|
||||
kwBottom :: Doc Ann
|
||||
kwBottom = keyword Str.bottom
|
||||
|
||||
kwBuiltinCons :: Doc Ann
|
||||
kwBuiltinCons = constructor Str.builtinListCons
|
||||
|
||||
kwBuiltinNil :: Doc Ann
|
||||
kwBuiltinNil = constructor Str.builtinListNil
|
||||
|
@ -71,6 +71,8 @@ checkBuiltins allowUntypedFail = dmapRM go
|
||||
throw $ unsupportedError "cairo" node (getInfoLocation _builtinAppInfo)
|
||||
| _builtinAppOp `elem` builtinsAnoma ->
|
||||
throw $ unsupportedError "anoma" node (getInfoLocation _builtinAppInfo)
|
||||
| _builtinAppOp `elem` builtinsByteArray ->
|
||||
throw $ unsupportedError "bytearray" node (getInfoLocation _builtinAppInfo)
|
||||
| otherwise ->
|
||||
return $ Recur node
|
||||
_ -> return $ Recur node
|
||||
|
@ -12,7 +12,7 @@ checkCairo md = do
|
||||
checkMainType
|
||||
checkNoAxioms md
|
||||
mapAllNodesM checkNoIO md
|
||||
mapAllNodesM (checkBuiltins' (builtinsString ++ builtinsUInt8) [PrimString, primitiveUInt8]) md
|
||||
mapAllNodesM (checkBuiltins' (builtinsString ++ builtinsUInt8 ++ builtinsByteArray) [PrimString, primitiveUInt8, PrimByteArray]) md
|
||||
where
|
||||
checkMainType :: Sem r ()
|
||||
checkMainType =
|
||||
@ -60,6 +60,7 @@ checkCairo md = do
|
||||
PrimBool {} -> True
|
||||
PrimField {} -> True
|
||||
PrimString {} -> False
|
||||
PrimByteArray {} -> False
|
||||
|
||||
isRecordOrList :: TypeConstr -> Bool
|
||||
isRecordOrList TypeConstr {..} = case ii ^. inductiveBuiltin of
|
||||
|
@ -10,4 +10,4 @@ checkExec md = do
|
||||
checkNoAxioms md
|
||||
checkMainExists md
|
||||
checkMainTypeExec md
|
||||
mapAllNodesM (checkBuiltins' (builtinsCairo ++ builtinsAnoma) []) md
|
||||
mapAllNodesM (checkBuiltins' (builtinsCairo ++ builtinsAnoma ++ builtinsByteArray) [PrimByteArray]) md
|
||||
|
@ -35,6 +35,7 @@ computeNodeTypeInfo md = umapL go
|
||||
ConstField {} -> mkTypeField'
|
||||
ConstString {} -> mkTypeString'
|
||||
ConstUInt8 {} -> mkTypeUInt8'
|
||||
ConstByteArray {} -> mkDynamic'
|
||||
NApp {} ->
|
||||
let (fn, args) = unfoldApps' node
|
||||
fty = Info.getNodeType fn
|
||||
@ -85,6 +86,8 @@ computeNodeTypeInfo md = umapL go
|
||||
_ -> error "incorrect random_ec_point builtin application"
|
||||
OpUInt8ToInt -> mkTypeInteger'
|
||||
OpUInt8FromInt -> mkTypeUInt8'
|
||||
OpByteArrayFromListByte -> mkDynamic'
|
||||
OpByteArrayLength -> mkTypeInteger'
|
||||
NCtr Constr {..} ->
|
||||
let ci = lookupConstructorInfo md _constrTag
|
||||
ii = lookupInductiveInfo md (ci ^. constructorInductive)
|
||||
|
@ -20,6 +20,7 @@ convertNode md = umap go
|
||||
Just (BuiltinTypeAxiom BuiltinString) -> mkTypeString'
|
||||
Just (BuiltinTypeAxiom BuiltinField) -> mkTypeField'
|
||||
Just (BuiltinTypeAxiom BuiltinByte) -> mkTypeUInt8'
|
||||
Just (BuiltinTypeAxiom BuiltinByteArray) -> mkTypeByteArray'
|
||||
_ -> node
|
||||
where
|
||||
ii = lookupInductiveInfo md _typeConstrSymbol
|
||||
|
@ -618,6 +618,9 @@ goAxiomInductive a = whenJust (a ^. Internal.axiomBuiltin) builtinInductive
|
||||
Internal.BuiltinByteEq -> return ()
|
||||
Internal.BuiltinByteToNat -> return ()
|
||||
Internal.BuiltinByteFromNat -> return ()
|
||||
Internal.BuiltinByteArray -> registerInductiveAxiom (Just BuiltinByteArray) []
|
||||
Internal.BuiltinByteArrayFromListByte -> return ()
|
||||
Internal.BuiltinByteArrayLength -> return ()
|
||||
|
||||
registerInductiveAxiom :: Maybe BuiltinAxiom -> [(Tag, Text, Type -> Type, Maybe BuiltinConstructor)] -> Sem r ()
|
||||
registerInductiveAxiom ax ctrs = do
|
||||
@ -826,6 +829,11 @@ goAxiomDef a = maybe goAxiomNotBuiltin builtinBody (a ^. Internal.axiomBuiltin)
|
||||
registerAxiomDef (mkLambda' mkTypeUInt8' (mkBuiltinApp' OpUInt8ToInt [mkVar' 0]))
|
||||
Internal.BuiltinByteFromNat ->
|
||||
registerAxiomDef (mkLambda' mkTypeInteger' (mkBuiltinApp' OpUInt8FromInt [mkVar' 0]))
|
||||
Internal.BuiltinByteArray -> return ()
|
||||
Internal.BuiltinByteArrayFromListByte ->
|
||||
registerAxiomDef (mkLambda' mkDynamic' (mkBuiltinApp' OpByteArrayFromListByte [mkVar' 0]))
|
||||
Internal.BuiltinByteArrayLength ->
|
||||
registerAxiomDef (mkLambda' mkTypeInteger' (mkBuiltinApp' OpByteArrayLength [mkVar' 0]))
|
||||
|
||||
axiomType' :: Sem r Type
|
||||
axiomType' = fromTopIndex (goType (a ^. Internal.axiomType))
|
||||
@ -1227,6 +1235,9 @@ goApplication a = do
|
||||
Just Internal.BuiltinByteEq -> app
|
||||
Just Internal.BuiltinByteToNat -> app
|
||||
Just Internal.BuiltinByteFromNat -> app
|
||||
Just Internal.BuiltinByteArray -> app
|
||||
Just Internal.BuiltinByteArrayFromListByte -> app
|
||||
Just Internal.BuiltinByteArrayLength -> app
|
||||
Nothing -> app
|
||||
Internal.ExpressionIden (Internal.IdenFunction n) -> do
|
||||
funInfoBuiltin <- Internal.getFunctionBuiltinInfo n
|
||||
|
@ -79,6 +79,7 @@ parseToplevel = do
|
||||
lift declareBoolBuiltins
|
||||
lift declareNatBuiltins
|
||||
lift declareMaybeBuiltins
|
||||
lift declareListBuiltins
|
||||
space
|
||||
P.endBy statement (kw delimSemicolon)
|
||||
r <- optional expression
|
||||
@ -580,6 +581,8 @@ builtinAppExpr varsNum vars = do
|
||||
<|> (kw kwAnomaVerifyWithMessage $> OpAnomaVerifyWithMessage)
|
||||
<|> (kw kwAnomaSignDetached $> OpAnomaSignDetached)
|
||||
<|> (kw kwAnomaVerifyDetached $> OpAnomaVerifyDetached)
|
||||
<|> (kw kwByteArrayFromListByte $> OpByteArrayFromListByte)
|
||||
<|> (kw kwByteArrayLength $> OpByteArrayLength)
|
||||
args <- P.many (atom varsNum vars)
|
||||
return $ mkBuiltinApp' op args
|
||||
|
||||
@ -1119,6 +1122,8 @@ exprNamed varsNum vars = do
|
||||
"Int" -> return mkTypeInteger'
|
||||
"Field" -> return mkTypeField'
|
||||
"String" -> return mkTypeString'
|
||||
"UInt8" -> return mkTypeUInt8'
|
||||
"ByteArray" -> return mkDynamic'
|
||||
_ ->
|
||||
case HashMap.lookup txt vars of
|
||||
Just k -> do
|
||||
|
@ -112,6 +112,9 @@ fromCore fsize tab =
|
||||
BuiltinByteEq -> False
|
||||
BuiltinByteToNat -> False
|
||||
BuiltinByteFromNat -> False
|
||||
BuiltinByteArray -> False
|
||||
BuiltinByteArrayFromListByte -> False
|
||||
BuiltinByteArrayLength -> False
|
||||
BuiltinTypeInductive i -> case i of
|
||||
BuiltinList -> True
|
||||
BuiltinMaybe -> True
|
||||
|
@ -591,6 +591,9 @@ registerBuiltinAxiom d = \case
|
||||
BuiltinByteEq -> registerByteEq d
|
||||
BuiltinByteToNat -> registerByteToNat d
|
||||
BuiltinByteFromNat -> registerByteFromNat d
|
||||
BuiltinByteArray -> registerByteArray d
|
||||
BuiltinByteArrayFromListByte -> registerByteArrayFromListByte d
|
||||
BuiltinByteArrayLength -> registerByteArrayLength d
|
||||
|
||||
goInductive ::
|
||||
(Members '[Reader EntryPoint, Reader DefaultArgsStack, NameIdGen, Reader Pragmas, Builtins, Error ScoperError, State ConstructorInfos, Reader S.InfoTable] r) =>
|
||||
|
@ -7,6 +7,7 @@ module Juvix.Compiler.Nockma.Evaluator
|
||||
where
|
||||
|
||||
import Crypto.Sign.Ed25519
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Juvix.Compiler.Nockma.Encoding
|
||||
import Juvix.Compiler.Nockma.Encoding qualified as Encoding
|
||||
@ -253,10 +254,36 @@ evalProfile inistack initerm =
|
||||
StdlibCatBytes -> case args' of
|
||||
TCell (TermAtom arg1) (TermAtom arg2) -> goCat arg1 arg2
|
||||
_ -> error "expected a term with two atoms"
|
||||
StdlibFoldBytes -> TermAtom <$> goFoldBytes args'
|
||||
StdlibLengthList -> do
|
||||
let xs = checkTermToList args'
|
||||
let len = integerToNatural (toInteger (length xs))
|
||||
TermAtom . mkEmptyAtom <$> fromNatural len
|
||||
where
|
||||
goCat :: Atom a -> Atom a -> Sem r (Term a)
|
||||
goCat arg1 arg2 = TermAtom . setAtomHint AtomHintString <$> atomConcatenateBytes arg1 arg2
|
||||
|
||||
goFoldBytes :: Term a -> Sem r (Atom a)
|
||||
goFoldBytes c = do
|
||||
bs <- mapM nockNatural (checkTermToListAtom c)
|
||||
byteStringToAtom (BS.pack (fromIntegral <$> bs))
|
||||
|
||||
checkTermToList :: Term a -> [Term a]
|
||||
checkTermToList = \case
|
||||
TermAtom x ->
|
||||
if
|
||||
| x `nockmaEq` nockNil -> []
|
||||
| otherwise -> error "expected a list to be terminated by nil"
|
||||
TermCell c -> c ^. cellLeft : checkTermToList (c ^. cellRight)
|
||||
|
||||
checkTermToListAtom :: Term a -> [Atom a]
|
||||
checkTermToListAtom = map check . checkTermToList
|
||||
where
|
||||
check :: Term a -> Atom a
|
||||
check = \case
|
||||
TermAtom x -> x
|
||||
TermCell {} -> error "expect list element to be an atom"
|
||||
|
||||
signatureLength :: Int
|
||||
signatureLength = 64
|
||||
|
||||
|
@ -26,6 +26,7 @@ stdlibPath = \case
|
||||
StdlibSign -> [nock| [9 10 0 1] |]
|
||||
StdlibSignDetached -> [nock| [9 23 0 1] |]
|
||||
StdlibVerify -> [nock| [9 4 0 1] |]
|
||||
StdlibLengthList -> [nock| [9 1.406 0 31] |]
|
||||
-- Obtained from the urbit dojo using:
|
||||
--
|
||||
-- => anoma !=(~(cat block 3))
|
||||
@ -33,3 +34,44 @@ stdlibPath = \case
|
||||
-- The `3` here is because we want to treat each atom as sequences of 2^3
|
||||
-- bits, i.e bytes.
|
||||
StdlibCatBytes -> [nock| [8 [9 10 0 7] 9 4 10 [6 7 [0 3] 1 3] 0 2] |]
|
||||
-- Obtained from the urbit dojo using:
|
||||
--
|
||||
-- =>(anoma !=(|=([l=(list @)] (foldr l |=([fst=@ snd=@] (add (~(lsh block 3) 1 snd) fst))))))
|
||||
--
|
||||
-- The `3` here is because we want to shift left in byte = 2^3 bit steps.
|
||||
StdlibFoldBytes ->
|
||||
[nock|
|
||||
[ 8
|
||||
[1 0]
|
||||
[ 1
|
||||
8
|
||||
[9 46 0 127]
|
||||
9
|
||||
2
|
||||
10
|
||||
[ 6
|
||||
[0 14]
|
||||
7
|
||||
[0 3]
|
||||
8
|
||||
[1 0 0]
|
||||
[ 1
|
||||
8
|
||||
[9 20 0 1.023]
|
||||
9
|
||||
2
|
||||
10
|
||||
[6 [7 [0 3] 8 [8 [9 10 0 127] 9 90 10 [6 7 [0 3] 1 3] 0 2] 9 2 10 [6 [7 [0 3] 1 1] 0 29] 0 2] 0 28]
|
||||
0
|
||||
2
|
||||
]
|
||||
0
|
||||
1
|
||||
]
|
||||
0
|
||||
2
|
||||
]
|
||||
0
|
||||
1
|
||||
]
|
||||
|]
|
||||
|
@ -21,6 +21,8 @@ instance Pretty StdlibFunction where
|
||||
StdlibSignDetached -> "sign-detached"
|
||||
StdlibVerify -> "verify"
|
||||
StdlibCatBytes -> "cat"
|
||||
StdlibFoldBytes -> "fold-bytes"
|
||||
StdlibLengthList -> "length-list"
|
||||
|
||||
data StdlibFunction
|
||||
= StdlibDec
|
||||
@ -39,6 +41,8 @@ data StdlibFunction
|
||||
| StdlibSignDetached
|
||||
| StdlibVerify
|
||||
| StdlibCatBytes
|
||||
| StdlibFoldBytes
|
||||
| StdlibLengthList
|
||||
deriving stock (Show, Lift, Eq, Bounded, Enum, Generic)
|
||||
|
||||
instance Hashable StdlibFunction
|
||||
|
@ -33,6 +33,7 @@ module Juvix.Compiler.Nockma.Translation.FromTree
|
||||
)
|
||||
where
|
||||
|
||||
import Data.ByteString qualified as BS
|
||||
import Juvix.Compiler.Nockma.Encoding
|
||||
import Juvix.Compiler.Nockma.Language.Path
|
||||
import Juvix.Compiler.Nockma.Pretty
|
||||
@ -360,6 +361,7 @@ compile :: forall r. (Members '[Reader FunctionCtx, Reader CompilerCtx] r) => Tr
|
||||
compile = \case
|
||||
Tree.Binop b -> goBinop b
|
||||
Tree.Unop b -> goUnop b
|
||||
Tree.ByteArray b -> goByteArrayOp b
|
||||
Tree.Cairo {} -> cairoErr
|
||||
Tree.Anoma b -> goAnomaOp b
|
||||
Tree.Constant c -> return (goConstant (c ^. Tree.nodeConstant))
|
||||
@ -441,6 +443,7 @@ compile = \case
|
||||
Tree.ConstVoid -> OpQuote # constVoid
|
||||
Tree.ConstField {} -> fieldErr
|
||||
Tree.ConstUInt8 i -> nockIntegralLiteral i
|
||||
Tree.ConstByteArray bs -> OpQuote # (toNock @Natural (fromIntegral (BS.length bs)) # toNock (byteStringToNatural bs))
|
||||
|
||||
goConstString :: Text -> Term Natural
|
||||
goConstString t =
|
||||
@ -492,6 +495,18 @@ compile = \case
|
||||
Tree.OpAnomaVerifyWithMessage -> return (goAnomaVerifyWithMessage args)
|
||||
Tree.OpAnomaSignDetached -> return (goAnomaSignDetached args)
|
||||
|
||||
goByteArrayOp :: Tree.NodeByteArray -> Sem r (Term Natural)
|
||||
goByteArrayOp Tree.NodeByteArray {..} = do
|
||||
args <- mapM compile _nodeByteArrayArgs
|
||||
return $ case _nodeByteArrayOpcode of
|
||||
Tree.OpByteArrayLength -> goByteArrayLength args
|
||||
Tree.OpByteArrayFromListUInt8 -> callStdlib StdlibLengthList args # callStdlib StdlibFoldBytes args
|
||||
where
|
||||
goByteArrayLength :: [Term Natural] -> Term Natural
|
||||
goByteArrayLength = \case
|
||||
[ba] -> ba >># opAddress "head-of-the-bytestring" [L]
|
||||
_ -> impossible
|
||||
|
||||
goUnop :: Tree.NodeUnop -> Sem r (Term Natural)
|
||||
goUnop Tree.NodeUnop {..} = do
|
||||
arg <- compile _nodeUnopArg
|
||||
|
@ -13,6 +13,7 @@ data TransformationId
|
||||
| FilterUnreachable
|
||||
| Validate
|
||||
| CheckNoAnoma
|
||||
| CheckNoByteArray
|
||||
deriving stock (Data, Bounded, Enum, Show)
|
||||
|
||||
data PipelineId
|
||||
@ -27,7 +28,7 @@ toNockmaTransformations :: [TransformationId]
|
||||
toNockmaTransformations = [Validate, Apply, FilterUnreachable, TempHeight]
|
||||
|
||||
toAsmTransformations :: [TransformationId]
|
||||
toAsmTransformations = [Validate, CheckNoAnoma]
|
||||
toAsmTransformations = [Validate, CheckNoAnoma, CheckNoByteArray]
|
||||
|
||||
toCairoAsmTransformations :: [TransformationId]
|
||||
toCairoAsmTransformations = [Validate, Apply, FilterUnreachable]
|
||||
@ -43,6 +44,7 @@ instance TransformationId' TransformationId where
|
||||
FilterUnreachable -> strFilterUnreachable
|
||||
Validate -> strValidate
|
||||
CheckNoAnoma -> strCheckNoAnoma
|
||||
CheckNoByteArray -> strCheckNoByteArray
|
||||
|
||||
instance PipelineId' TransformationId PipelineId where
|
||||
pipelineText :: PipelineId -> Text
|
||||
|
@ -34,3 +34,6 @@ strValidate = "validate"
|
||||
|
||||
strCheckNoAnoma :: Text
|
||||
strCheckNoAnoma = "check-no-anoma"
|
||||
|
||||
strCheckNoByteArray :: Text
|
||||
strCheckNoByteArray = "check-no-bytearray"
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Juvix.Compiler.Tree.Evaluator where
|
||||
|
||||
import Control.Exception qualified as Exception
|
||||
import Data.ByteString qualified as BS
|
||||
import GHC.IO (unsafePerformIO)
|
||||
import GHC.Show qualified as S
|
||||
import Juvix.Compiler.Core.Data.BinderList qualified as BL
|
||||
@ -37,6 +38,7 @@ hEval hout tab = eval' [] mempty
|
||||
eval' args temps node = case node of
|
||||
Binop x -> goBinop x
|
||||
Unop x -> goUnop x
|
||||
ByteArray x -> goByteArrayOp x
|
||||
Anoma {} -> evalError "unsupported: Anoma builtin"
|
||||
Cairo {} -> evalError "unsupported: Cairo builtin"
|
||||
Constant c -> goConstant c
|
||||
@ -76,6 +78,33 @@ hEval hout tab = eval' [] mempty
|
||||
OpTrace -> goTrace v
|
||||
OpFail -> goFail v
|
||||
|
||||
goByteArrayOp :: NodeByteArray -> Value
|
||||
goByteArrayOp NodeByteArray {..} =
|
||||
case _nodeByteArrayOpcode of
|
||||
OpByteArrayLength -> case _nodeByteArrayArgs of
|
||||
[nodeArg] ->
|
||||
let !arg = eval' args temps nodeArg
|
||||
in case arg of
|
||||
(ValByteArray bs) -> ValInteger (fromIntegral (BS.length bs))
|
||||
_ -> evalError "expected argument to be a ByteString"
|
||||
_ -> evalError "expected exactly one argument"
|
||||
OpByteArrayFromListUInt8 -> case _nodeByteArrayArgs of
|
||||
[nodeArg] ->
|
||||
let !arg = eval' args temps nodeArg
|
||||
!listUInt8 :: [Word8] = checkListUInt8 arg
|
||||
in ValByteArray (BS.pack listUInt8)
|
||||
_ -> evalError "expected exactly one argument"
|
||||
where
|
||||
checkListUInt8 :: Value -> [Word8]
|
||||
checkListUInt8 = \case
|
||||
ValConstr c -> case c ^. constrArgs of
|
||||
-- is nil
|
||||
[] -> []
|
||||
-- is cons
|
||||
[ValUInt8 w, t] -> w : checkListUInt8 t
|
||||
_ -> evalError "expected either a nullary or a binary constructor"
|
||||
_ -> evalError "expected a constructor"
|
||||
|
||||
goFail :: Value -> Value
|
||||
goFail v = evalError ("failure: " <> printValue tab v)
|
||||
|
||||
@ -232,6 +261,7 @@ valueToNode = \case
|
||||
_nodeAllocClosureArgs = map valueToNode _closureArgs
|
||||
}
|
||||
ValUInt8 i -> mkConst $ ConstUInt8 i
|
||||
ValByteArray b -> mkConst $ ConstByteArray b
|
||||
|
||||
hEvalIO :: (MonadIO m) => Handle -> Handle -> InfoTable -> FunctionInfo -> m Value
|
||||
hEvalIO hin hout infoTable funInfo = do
|
||||
|
@ -130,6 +130,7 @@ constantToValue = \case
|
||||
ConstUnit -> ValUnit
|
||||
ConstVoid -> ValVoid
|
||||
ConstUInt8 i -> ValUInt8 i
|
||||
ConstByteArray b -> ValByteArray b
|
||||
|
||||
valueToConstant :: Value -> Constant
|
||||
valueToConstant = \case
|
||||
|
@ -1,6 +1,7 @@
|
||||
module Juvix.Compiler.Tree.EvaluatorEff (eval, hEvalIOEither) where
|
||||
|
||||
import Control.Exception qualified as Exception
|
||||
import Data.ByteString qualified as BS
|
||||
import Juvix.Compiler.Core.Data.BinderList qualified as BL
|
||||
import Juvix.Compiler.Tree.Data.InfoTable
|
||||
import Juvix.Compiler.Tree.Error
|
||||
@ -33,6 +34,7 @@ eval tab = runReader emptyEvalCtx . eval'
|
||||
eval' node = case node of
|
||||
Binop x -> goBinop x
|
||||
Unop x -> goUnop x
|
||||
ByteArray x -> goByteArrayOp x
|
||||
Anoma {} -> evalError "unsupported: Anoma builtins"
|
||||
Cairo {} -> evalError "unsupported: Cairo builtins"
|
||||
Constant c -> return (goConstant c)
|
||||
@ -71,6 +73,33 @@ eval tab = runReader emptyEvalCtx . eval'
|
||||
OpTrace -> goTrace v
|
||||
OpFail -> goFail v
|
||||
|
||||
goByteArrayOp :: NodeByteArray -> Sem r' Value
|
||||
goByteArrayOp NodeByteArray {..} =
|
||||
case _nodeByteArrayOpcode of
|
||||
OpByteArrayLength -> case _nodeByteArrayArgs of
|
||||
[nodeArg] -> do
|
||||
arg <- eval' nodeArg
|
||||
case arg of
|
||||
(ValByteArray bs) -> return $ ValInteger (fromIntegral (BS.length bs))
|
||||
_ -> evalError "expected argument to be a ByteString"
|
||||
_ -> evalError "expected exactly one argument"
|
||||
OpByteArrayFromListUInt8 -> case _nodeByteArrayArgs of
|
||||
[nodeArg] -> do
|
||||
arg <- eval' nodeArg
|
||||
listUInt8 :: [Word8] <- checkListUInt8 arg
|
||||
return $ ValByteArray (BS.pack listUInt8)
|
||||
_ -> evalError "expected exactly one argument"
|
||||
where
|
||||
checkListUInt8 :: Value -> Sem r' [Word8]
|
||||
checkListUInt8 = \case
|
||||
ValConstr c -> case c ^. constrArgs of
|
||||
-- is nil
|
||||
[] -> return []
|
||||
-- is cons
|
||||
[ValUInt8 w, t] -> (w :) <$> checkListUInt8 t
|
||||
_ -> evalError "expected either a nullary or a binary constructor"
|
||||
_ -> evalError "expected a constructor"
|
||||
|
||||
goFail :: Value -> Sem r' Value
|
||||
goFail v = evalError ("failure: " <> printValue tab v)
|
||||
|
||||
|
@ -18,6 +18,7 @@ getNodeInfo :: Node -> NodeInfo
|
||||
getNodeInfo = \case
|
||||
Binop NodeBinop {..} -> _nodeBinopInfo
|
||||
Unop NodeUnop {..} -> _nodeUnopInfo
|
||||
ByteArray NodeByteArray {..} -> _nodeByteArrayInfo
|
||||
Cairo NodeCairo {..} -> _nodeCairoInfo
|
||||
Anoma NodeAnoma {..} -> _nodeAnomaInfo
|
||||
Constant NodeConstant {..} -> _nodeConstantInfo
|
||||
@ -142,6 +143,17 @@ destruct = \case
|
||||
_nodeUnopInfo
|
||||
}
|
||||
}
|
||||
ByteArray NodeByteArray {..} ->
|
||||
NodeDetails
|
||||
{ _nodeChildren = map noTempVar _nodeByteArrayArgs,
|
||||
_nodeReassemble = manyChildren $ \args ->
|
||||
ByteArray
|
||||
NodeByteArray
|
||||
{ _nodeByteArrayArgs = args,
|
||||
_nodeByteArrayOpcode,
|
||||
_nodeByteArrayInfo
|
||||
}
|
||||
}
|
||||
Cairo NodeCairo {..} ->
|
||||
NodeDetails
|
||||
{ _nodeChildren = map noTempVar _nodeCairoArgs,
|
||||
|
@ -4,33 +4,18 @@
|
||||
{-# HLINT ignore "Avoid restricted extensions" #-}
|
||||
{-# HLINT ignore "Avoid restricted flags" #-}
|
||||
|
||||
module Juvix.Compiler.Tree.Extra.Type where
|
||||
module Juvix.Compiler.Tree.Extra.Type
|
||||
( module Juvix.Compiler.Tree.Extra.Type,
|
||||
module Juvix.Compiler.Tree.Extra.Type.Base,
|
||||
)
|
||||
where
|
||||
|
||||
import Juvix.Compiler.Tree.Data.InfoTable.Base
|
||||
import Juvix.Compiler.Tree.Error
|
||||
import Juvix.Compiler.Tree.Extra.Type.Base
|
||||
import Juvix.Compiler.Tree.Language.Base
|
||||
import Juvix.Compiler.Tree.Pretty
|
||||
|
||||
mkTypeInteger :: Type
|
||||
mkTypeInteger = TyInteger (TypeInteger Nothing Nothing)
|
||||
|
||||
mkTypeUInt8 :: Type
|
||||
mkTypeUInt8 = TyInteger (TypeInteger (Just 0) (Just 255))
|
||||
|
||||
mkTypeBool :: Type
|
||||
mkTypeBool = TyBool (TypeBool (BuiltinTag TagTrue) (BuiltinTag TagFalse))
|
||||
|
||||
mkTypeConstr :: Symbol -> Tag -> [Type] -> Type
|
||||
mkTypeConstr ind tag argTypes = TyConstr (TypeConstr ind tag argTypes)
|
||||
|
||||
mkTypeInductive :: Symbol -> Type
|
||||
mkTypeInductive ind = TyInductive (TypeInductive ind)
|
||||
|
||||
mkTypeFun :: [Type] -> Type -> Type
|
||||
mkTypeFun args tgt = case args of
|
||||
[] -> tgt
|
||||
a : args' -> TyFun (TypeFun (a :| args') tgt)
|
||||
|
||||
unfoldType :: Type -> ([Type], Type)
|
||||
unfoldType ty = (typeArgs ty, typeTarget ty)
|
||||
|
||||
@ -80,6 +65,7 @@ isSubtype ty1 ty2 = case (ty1, ty2) of
|
||||
(TyBool {}, TyBool {}) -> True
|
||||
(TyString, TyString) -> True
|
||||
(TyField, TyField) -> True
|
||||
(TyByteArray, TyByteArray) -> True
|
||||
(TyUnit, TyUnit) -> True
|
||||
(TyVoid, TyVoid) -> True
|
||||
(TyInductive {}, TyInductive {}) -> ty1 == ty2
|
||||
@ -93,6 +79,8 @@ isSubtype ty1 ty2 = case (ty1, ty2) of
|
||||
(_, TyString) -> False
|
||||
(TyField, _) -> False
|
||||
(_, TyField) -> False
|
||||
(TyByteArray, _) -> False
|
||||
(_, TyByteArray) -> False
|
||||
(TyBool {}, _) -> False
|
||||
(_, TyBool {}) -> False
|
||||
(TyFun {}, _) -> False
|
||||
@ -149,6 +137,7 @@ unifyTypes ty1 ty2 = case (ty1, ty2) of
|
||||
| ty1 == ty2 -> return ty1
|
||||
(TyString, TyString) -> return TyString
|
||||
(TyField, TyField) -> return TyField
|
||||
(TyByteArray, TyByteArray) -> return TyByteArray
|
||||
(TyUnit, TyUnit) -> return TyUnit
|
||||
(TyVoid, TyVoid) -> return TyVoid
|
||||
(TyInductive {}, TyInductive {})
|
||||
@ -163,6 +152,8 @@ unifyTypes ty1 ty2 = case (ty1, ty2) of
|
||||
(_, TyString) -> err
|
||||
(TyField, _) -> err
|
||||
(_, TyField) -> err
|
||||
(TyByteArray, _) -> err
|
||||
(_, TyByteArray) -> err
|
||||
(TyBool {}, _) -> err
|
||||
(_, TyBool {}) -> err
|
||||
(TyFun {}, _) -> err
|
||||
|
24
src/Juvix/Compiler/Tree/Extra/Type/Base.hs
Normal file
24
src/Juvix/Compiler/Tree/Extra/Type/Base.hs
Normal file
@ -0,0 +1,24 @@
|
||||
module Juvix.Compiler.Tree.Extra.Type.Base where
|
||||
|
||||
import Juvix.Compiler.Tree.Language.Base
|
||||
import Juvix.Compiler.Tree.Language.Type
|
||||
|
||||
mkTypeInteger :: Type
|
||||
mkTypeInteger = TyInteger (TypeInteger Nothing Nothing)
|
||||
|
||||
mkTypeUInt8 :: Type
|
||||
mkTypeUInt8 = TyInteger (TypeInteger (Just 0) (Just 255))
|
||||
|
||||
mkTypeBool :: Type
|
||||
mkTypeBool = TyBool (TypeBool (BuiltinTag TagTrue) (BuiltinTag TagFalse))
|
||||
|
||||
mkTypeConstr :: Symbol -> Tag -> [Type] -> Type
|
||||
mkTypeConstr ind tag argTypes = TyConstr (TypeConstr ind tag argTypes)
|
||||
|
||||
mkTypeInductive :: Symbol -> Type
|
||||
mkTypeInductive ind = TyInductive (TypeInductive ind)
|
||||
|
||||
mkTypeFun :: [Type] -> Type -> Type
|
||||
mkTypeFun args tgt = case args of
|
||||
[] -> tgt
|
||||
a : args' -> TyFun (TypeFun (a :| args') tgt)
|
@ -19,6 +19,8 @@ import Juvix.Data.Keyword.All
|
||||
kwArgsNum,
|
||||
kwAtoi,
|
||||
kwBr,
|
||||
kwByteArrayFromListUInt8,
|
||||
kwByteArrayLength,
|
||||
kwCAlloc,
|
||||
kwCCall,
|
||||
kwCExtend,
|
||||
@ -88,5 +90,7 @@ allKeywords =
|
||||
kwAnomaVerifyWithMessage,
|
||||
kwPoseidon,
|
||||
kwEcOp,
|
||||
kwRandomEcPoint
|
||||
kwRandomEcPoint,
|
||||
kwByteArrayLength,
|
||||
kwByteArrayFromListUInt8
|
||||
]
|
||||
|
@ -18,6 +18,7 @@ data Node
|
||||
| Unop NodeUnop
|
||||
| Cairo NodeCairo
|
||||
| Anoma NodeAnoma
|
||||
| ByteArray NodeByteArray
|
||||
| -- | A constant value.
|
||||
Constant NodeConstant
|
||||
| -- | A memory reference.
|
||||
@ -82,6 +83,12 @@ data NodeUnop = NodeUnop
|
||||
_nodeUnopArg :: Node
|
||||
}
|
||||
|
||||
data NodeByteArray = NodeByteArray
|
||||
{ _nodeByteArrayInfo :: NodeInfo,
|
||||
_nodeByteArrayOpcode :: ByteArrayOp,
|
||||
_nodeByteArrayArgs :: [Node]
|
||||
}
|
||||
|
||||
data NodeCairo = NodeCairo
|
||||
{ _nodeCairoInfo :: NodeInfo,
|
||||
_nodeCairoOpcode :: CairoOp,
|
||||
|
@ -19,6 +19,7 @@ data Constant
|
||||
| ConstUnit
|
||||
| ConstVoid
|
||||
| ConstUInt8 Word8
|
||||
| ConstByteArray ByteString
|
||||
deriving stock (Eq, Generic)
|
||||
|
||||
instance (Hashable Constant)
|
||||
|
@ -66,6 +66,14 @@ data CairoOp
|
||||
OpCairoRandomEcPoint
|
||||
deriving stock (Eq)
|
||||
|
||||
-- | Builtin ByteArray operations
|
||||
data ByteArrayOp
|
||||
= -- | Convert a list of UInt8 to a ByteArray
|
||||
OpByteArrayFromListUInt8
|
||||
| -- | Get the size of a ByteArray
|
||||
OpByteArrayLength
|
||||
deriving stock (Eq)
|
||||
|
||||
cairoOpArgsNum :: CairoOp -> Int
|
||||
cairoOpArgsNum = \case
|
||||
OpCairoPoseidon -> 1
|
||||
|
@ -8,6 +8,7 @@ data Type
|
||||
| TyBool TypeBool
|
||||
| TyString
|
||||
| TyField
|
||||
| TyByteArray
|
||||
| TyUnit
|
||||
| TyVoid
|
||||
| TyInductive TypeInductive
|
||||
@ -81,6 +82,7 @@ instance HasAtomicity Type where
|
||||
TyField -> Atom
|
||||
TyUnit -> Atom
|
||||
TyVoid -> Atom
|
||||
TyByteArray -> Atom
|
||||
TyInductive x -> atomicity x
|
||||
TyConstr x -> atomicity x
|
||||
TyFun x -> atomicity x
|
||||
|
@ -24,6 +24,7 @@ data Value
|
||||
| ValConstr Constr
|
||||
| ValClosure Closure
|
||||
| ValUInt8 Word8
|
||||
| ValByteArray ByteString
|
||||
deriving stock (Eq)
|
||||
|
||||
data Constr = Constr
|
||||
@ -62,3 +63,4 @@ instance HasAtomicity Value where
|
||||
ValConstr c -> atomicity c
|
||||
ValClosure cl -> atomicity cl
|
||||
ValUInt8 {} -> Atom
|
||||
ValByteArray {} -> Atom
|
||||
|
@ -4,12 +4,14 @@ module Juvix.Compiler.Tree.Pretty.Base
|
||||
)
|
||||
where
|
||||
|
||||
import Data.ByteString qualified as BS
|
||||
import Data.Foldable
|
||||
import Data.HashMap.Strict qualified as HashMap
|
||||
import Data.List.NonEmpty qualified as NonEmpty
|
||||
import Juvix.Compiler.Core.Pretty.Base qualified as Core
|
||||
import Juvix.Compiler.Internal.Data.Name
|
||||
import Juvix.Compiler.Tree.Data.InfoTable
|
||||
import Juvix.Compiler.Tree.Extra.Type.Base
|
||||
import Juvix.Compiler.Tree.Language
|
||||
import Juvix.Compiler.Tree.Language.Value
|
||||
import Juvix.Compiler.Tree.Pretty.Extra
|
||||
@ -101,6 +103,7 @@ instance PrettyCode Value where
|
||||
ppCode cl
|
||||
ValUInt8 i ->
|
||||
return $ integer i
|
||||
ValByteArray bs -> ppCode bs
|
||||
|
||||
instance PrettyCode TypeInductive where
|
||||
ppCode :: (Member (Reader Options) r) => TypeInductive -> Sem r (Doc Ann)
|
||||
@ -139,10 +142,14 @@ instance PrettyCode Type where
|
||||
ppCode = \case
|
||||
TyDynamic ->
|
||||
return $ annotate (AnnKind KNameInductive) Str.mul
|
||||
TyInteger {} ->
|
||||
return $ annotate (AnnKind KNameInductive) Str.integer
|
||||
t@(TyInteger {})
|
||||
| t == mkTypeUInt8 ->
|
||||
return $ annotate (AnnKind KNameInductive) Str.uint8
|
||||
TyInteger {} -> return $ annotate (AnnKind KNameInductive) Str.integer
|
||||
TyField {} ->
|
||||
return $ annotate (AnnKind KNameInductive) Str.field
|
||||
TyByteArray {} ->
|
||||
return $ annotate (AnnKind KNameInductive) Str.byteArray
|
||||
TyBool {} ->
|
||||
return $ annotate (AnnKind KNameInductive) Str.bool
|
||||
TyString ->
|
||||
@ -200,7 +207,24 @@ instance PrettyCode Constant where
|
||||
ConstVoid {} ->
|
||||
return $ annotate (AnnKind KNameConstructor) Str.void
|
||||
ConstUInt8 v ->
|
||||
return $ annotate AnnLiteralInteger (pretty v)
|
||||
return $ annotate AnnLiteralInteger (pretty v <> "u8")
|
||||
ConstByteArray v -> do
|
||||
ctorOp <- ppCode OpByteArrayFromListUInt8
|
||||
bs <- ppCode v
|
||||
return (ctorOp <> parens bs)
|
||||
|
||||
instance PrettyCode ByteString where
|
||||
ppCode bs = do
|
||||
ppBytes <- mapM ppCode (ConstUInt8 <$> BS.unpack bs)
|
||||
return (toListCtors ppBytes)
|
||||
where
|
||||
toListCtors :: [Doc Ann] -> Doc Ann
|
||||
toListCtors = \case
|
||||
[] -> nodeAllocCtor Str.nil []
|
||||
(x : xs) -> nodeAllocCtor Str.cons [x, toListCtors xs]
|
||||
|
||||
nodeAllocCtor :: Text -> [Doc Ann] -> Doc Ann
|
||||
nodeAllocCtor n args = primitive Str.instrAlloc <> brackets (pretty n) <> parens (ppCodeArgs' args)
|
||||
|
||||
instance PrettyCode BoolOp where
|
||||
ppCode op = return $ primitive $ case op of
|
||||
@ -246,6 +270,12 @@ instance PrettyCode UnaryOp where
|
||||
OpIntToUInt8 -> Str.instrIntToUInt8
|
||||
OpUInt8ToInt -> Str.instrUInt8ToInt
|
||||
|
||||
instance PrettyCode ByteArrayOp where
|
||||
ppCode =
|
||||
return . \case
|
||||
OpByteArrayFromListUInt8 -> Str.instrByteArrayFromListUInt8
|
||||
OpByteArrayLength -> Str.instrByteArrayLength
|
||||
|
||||
instance PrettyCode CairoOp where
|
||||
ppCode op = return $ primitive $ case op of
|
||||
OpCairoPoseidon -> Str.instrPoseidon
|
||||
@ -286,6 +316,12 @@ instance PrettyCode NodeAnoma where
|
||||
args <- ppCodeArgs _nodeAnomaArgs
|
||||
return (op <> parens args)
|
||||
|
||||
instance PrettyCode NodeByteArray where
|
||||
ppCode NodeByteArray {..} = do
|
||||
op <- ppCode _nodeByteArrayOpcode
|
||||
args <- ppCodeArgs _nodeByteArrayArgs
|
||||
return (op <> parens args)
|
||||
|
||||
instance PrettyCode NodeConstant where
|
||||
ppCode NodeConstant {..} = ppCode _nodeConstant
|
||||
|
||||
@ -295,7 +331,10 @@ instance PrettyCode NodeMemRef where
|
||||
ppCodeArgs :: (Member (Reader Options) r) => [Node] -> Sem r (Doc Ann)
|
||||
ppCodeArgs args = do
|
||||
args' <- mapM ppCode args
|
||||
return $ hsep $ punctuate comma args'
|
||||
return $ ppCodeArgs' args'
|
||||
|
||||
ppCodeArgs' :: [Doc Ann] -> Doc Ann
|
||||
ppCodeArgs' args = hsep $ punctuate comma args
|
||||
|
||||
instance PrettyCode NodeAllocConstr where
|
||||
ppCode NodeAllocConstr {..} = do
|
||||
@ -378,6 +417,7 @@ instance PrettyCode Node where
|
||||
ppCode = \case
|
||||
Binop x -> ppCode x
|
||||
Unop x -> ppCode x
|
||||
ByteArray x -> ppCode x
|
||||
Anoma x -> ppCode x
|
||||
Cairo x -> ppCode x
|
||||
Constant x -> ppCode x
|
||||
|
@ -11,6 +11,7 @@ import Juvix.Compiler.Tree.Error
|
||||
import Juvix.Compiler.Tree.Transformation.Apply
|
||||
import Juvix.Compiler.Tree.Transformation.Base
|
||||
import Juvix.Compiler.Tree.Transformation.CheckNoAnoma
|
||||
import Juvix.Compiler.Tree.Transformation.CheckNoByteArray
|
||||
import Juvix.Compiler.Tree.Transformation.FilterUnreachable
|
||||
import Juvix.Compiler.Tree.Transformation.IdentityTrans
|
||||
import Juvix.Compiler.Tree.Transformation.TempHeight
|
||||
@ -29,3 +30,4 @@ applyTransformations ts tbl = foldM (flip appTrans) tbl ts
|
||||
FilterUnreachable -> return . filterUnreachable
|
||||
Validate -> mapError (JuvixError @TreeError) . validate
|
||||
CheckNoAnoma -> \tbl' -> mapError (JuvixError @TreeError) (checkNoAnoma tbl') $> tbl'
|
||||
CheckNoByteArray -> \tbl' -> mapError (JuvixError @TreeError) (checkNoByteArray tbl') $> tbl'
|
||||
|
24
src/Juvix/Compiler/Tree/Transformation/CheckNoByteArray.hs
Normal file
24
src/Juvix/Compiler/Tree/Transformation/CheckNoByteArray.hs
Normal file
@ -0,0 +1,24 @@
|
||||
module Juvix.Compiler.Tree.Transformation.CheckNoByteArray where
|
||||
|
||||
import Juvix.Compiler.Tree.Data.InfoTable
|
||||
import Juvix.Compiler.Tree.Error
|
||||
import Juvix.Compiler.Tree.Extra.Recursors
|
||||
import Juvix.Compiler.Tree.Transformation.Base
|
||||
|
||||
checkNoByteArray :: forall r. (Member (Error TreeError) r) => InfoTable -> Sem r ()
|
||||
checkNoByteArray = walkT checkNode
|
||||
where
|
||||
checkNode :: Symbol -> Node -> Sem r ()
|
||||
checkNode _ = \case
|
||||
ByteArray NodeByteArray {..} -> case _nodeByteArrayOpcode of
|
||||
OpByteArrayLength -> unsupportedErr "OpByteArrayLength"
|
||||
OpByteArrayFromListUInt8 -> unsupportedErr "OpByteArrayFromListUInt8"
|
||||
where
|
||||
unsupportedErr :: Text -> Sem r ()
|
||||
unsupportedErr opName =
|
||||
throw
|
||||
TreeError
|
||||
{ _treeErrorMsg = opName <> " is unsupported",
|
||||
_treeErrorLoc = _nodeByteArrayInfo ^. nodeInfoLocation
|
||||
}
|
||||
_ -> return ()
|
@ -15,6 +15,7 @@ inferType tab funInfo = goInfer mempty
|
||||
goInfer bl = \case
|
||||
Binop x -> goBinop bl x
|
||||
Unop x -> goUnop bl x
|
||||
ByteArray x -> goByteArray bl x
|
||||
Cairo x -> goCairo bl x
|
||||
Anoma x -> goAnoma bl x
|
||||
Constant x -> goConst bl x
|
||||
@ -85,6 +86,11 @@ inferType tab funInfo = goInfer mempty
|
||||
OpUInt8ToInt -> checkUnop mkTypeUInt8 mkTypeInteger
|
||||
OpIntToUInt8 -> checkUnop mkTypeInteger mkTypeUInt8
|
||||
|
||||
goByteArray :: BinderList Type -> NodeByteArray -> Sem r Type
|
||||
goByteArray bl NodeByteArray {..} = do
|
||||
mapM_ (\arg -> checkType bl arg TyDynamic) _nodeByteArrayArgs
|
||||
return TyDynamic
|
||||
|
||||
goCairo :: BinderList Type -> NodeCairo -> Sem r Type
|
||||
goCairo bl NodeCairo {..} = do
|
||||
mapM_ (\arg -> checkType bl arg TyDynamic) _nodeCairoArgs
|
||||
@ -104,6 +110,7 @@ inferType tab funInfo = goInfer mempty
|
||||
ConstUnit {} -> return TyUnit
|
||||
ConstVoid {} -> return TyVoid
|
||||
ConstUInt8 {} -> return mkTypeUInt8
|
||||
ConstByteArray {} -> return TyByteArray
|
||||
|
||||
goMemRef :: BinderList Type -> NodeMemRef -> Sem r Type
|
||||
goMemRef bl NodeMemRef {..} = case _nodeMemRef of
|
||||
|
@ -87,6 +87,8 @@ genCode infoTable fi =
|
||||
mkConst (ConstField fld)
|
||||
Core.Constant _ (Core.ConstUInt8 i) ->
|
||||
mkConst (ConstUInt8 i)
|
||||
Core.Constant _ (Core.ConstByteArray bs) ->
|
||||
mkConst (ConstByteArray bs)
|
||||
|
||||
goApps :: Int -> BinderList MemRef -> Core.Apps -> Node
|
||||
goApps tempSize refs Core.Apps {..} =
|
||||
@ -140,6 +142,13 @@ genCode infoTable fi =
|
||||
|
||||
goBuiltinApp :: Int -> BinderList MemRef -> Core.BuiltinApp -> Node
|
||||
goBuiltinApp tempSize refs Core.BuiltinApp {..}
|
||||
| Core.builtinIsByteArray _builtinAppOp =
|
||||
ByteArray $
|
||||
NodeByteArray
|
||||
{ _nodeByteArrayInfo = mempty,
|
||||
_nodeByteArrayOpcode = genByteArrayOp _builtinAppOp,
|
||||
_nodeByteArrayArgs = args
|
||||
}
|
||||
| Core.builtinIsCairo _builtinAppOp =
|
||||
Cairo $
|
||||
NodeCairo
|
||||
@ -308,6 +317,12 @@ genCode infoTable fi =
|
||||
Core.OpUInt8ToInt -> PrimUnop OpUInt8ToInt
|
||||
_ -> impossible
|
||||
|
||||
genByteArrayOp :: Core.BuiltinOp -> ByteArrayOp
|
||||
genByteArrayOp = \case
|
||||
Core.OpByteArrayFromListByte -> OpByteArrayFromListUInt8
|
||||
Core.OpByteArrayLength -> OpByteArrayLength
|
||||
_ -> impossible
|
||||
|
||||
genCairoOp :: Core.BuiltinOp -> CairoOp
|
||||
genCairoOp = \case
|
||||
Core.OpPoseidonHash -> OpCairoPoseidon
|
||||
@ -361,6 +376,8 @@ convertPrimitiveType = \case
|
||||
TyString
|
||||
Core.PrimField ->
|
||||
TyField
|
||||
Core.PrimByteArray ->
|
||||
TyByteArray
|
||||
|
||||
-- | `convertNestedType` ensures that the conversion of a type with Dynamic in the
|
||||
-- target is curried. The result of `convertType 0 ty` is always uncurried.
|
||||
|
@ -53,6 +53,7 @@ parseNode ::
|
||||
parseNode =
|
||||
(Binop <$> parseBinop)
|
||||
<|> (Unop <$> parseUnop)
|
||||
<|> (ByteArray <$> parseByteArray)
|
||||
<|> (Anoma <$> parseAnoma)
|
||||
<|> (Cairo <$> parseCairo)
|
||||
<|> (Constant <$> parseConst)
|
||||
@ -119,6 +120,23 @@ parseUnaryOp kwd op = do
|
||||
arg <- parens parseNode
|
||||
return $ NodeUnop (NodeInfo (Just loc)) op arg
|
||||
|
||||
parseByteArray ::
|
||||
(Members '[Reader ParserSig, InfoTableBuilder, State LocalParams] r) =>
|
||||
ParsecS r NodeByteArray
|
||||
parseByteArray =
|
||||
parseByteArrayOp kwByteArrayFromListUInt8 OpByteArrayFromListUInt8
|
||||
<|> parseByteArrayOp kwByteArrayLength OpByteArrayLength
|
||||
|
||||
parseByteArrayOp ::
|
||||
(Members '[Reader ParserSig, InfoTableBuilder, State LocalParams] r) =>
|
||||
Keyword ->
|
||||
ByteArrayOp ->
|
||||
ParsecS r NodeByteArray
|
||||
parseByteArrayOp kwd op = do
|
||||
loc <- onlyInterval (kw kwd)
|
||||
args <- parseArgs
|
||||
return $ NodeByteArray (NodeInfo (Just loc)) op args
|
||||
|
||||
parseAnoma ::
|
||||
(Members '[Reader ParserSig, InfoTableBuilder, State LocalParams] r) =>
|
||||
ParsecS r NodeAnoma
|
||||
|
@ -309,6 +309,7 @@ typeNamed = do
|
||||
"bool" -> return mkTypeBool
|
||||
"string" -> return TyString
|
||||
"unit" -> return TyUnit
|
||||
"uint8" -> return mkTypeUInt8
|
||||
_ -> do
|
||||
idt <- lift $ getIdent' @t @e txt
|
||||
case idt of
|
||||
@ -316,13 +317,18 @@ typeNamed = do
|
||||
_ -> parseFailure off ("not a type: " ++ fromText txt)
|
||||
|
||||
constant :: ParsecS r Constant
|
||||
constant = fieldValue <|> integerValue <|> boolValue <|> stringValue <|> unitValue <|> voidValue
|
||||
constant = fieldValue <|> uint8Value <|> integerValue <|> boolValue <|> stringValue <|> unitValue <|> voidValue
|
||||
|
||||
fieldValue :: ParsecS r Constant
|
||||
fieldValue = P.try $ do
|
||||
(i, _) <- field
|
||||
return $ ConstField (fieldFromInteger defaultFieldSize i)
|
||||
|
||||
uint8Value :: ParsecS r Constant
|
||||
uint8Value = P.try $ do
|
||||
(i, _) <- uint8
|
||||
return $ ConstUInt8 (fromInteger i)
|
||||
|
||||
integerValue :: ParsecS r Constant
|
||||
integerValue = do
|
||||
i <- (^. withLocParam) <$> integer
|
||||
|
@ -31,6 +31,9 @@ number = number' integer
|
||||
field :: ParsecS r (Integer, Interval)
|
||||
field = lexemeInterval field'
|
||||
|
||||
uint8 :: ParsecS r (Integer, Interval)
|
||||
uint8 = lexemeInterval uint8'
|
||||
|
||||
string :: ParsecS r (Text, Interval)
|
||||
string = lexemeInterval string'
|
||||
|
||||
|
@ -79,6 +79,9 @@ primitive = annotate (AnnKind KNameAxiom) . pretty
|
||||
keyword :: Text -> Doc Ann
|
||||
keyword = annotate AnnKeyword . pretty
|
||||
|
||||
constructor :: Text -> Doc Ann
|
||||
constructor = annotate (AnnKind KNameConstructor) . pretty
|
||||
|
||||
kwNotMutual :: Doc Ann
|
||||
kwNotMutual = keyword Str.notMutual
|
||||
|
||||
|
@ -277,6 +277,9 @@ kwPrealloc = asciiKw Str.prealloc
|
||||
kwArgsNum :: Keyword
|
||||
kwArgsNum = asciiKw Str.instrArgsNum
|
||||
|
||||
kwByteArrayFromListUInt8 :: Keyword
|
||||
kwByteArrayFromListUInt8 = asciiKw Str.instrByteArrayFromListUInt8
|
||||
|
||||
kwPoseidon :: Keyword
|
||||
kwPoseidon = asciiKw Str.instrPoseidon
|
||||
|
||||
@ -463,6 +466,12 @@ kwAnomaSignDetached = asciiKw Str.anomaSignDetached
|
||||
kwAnomaVerifyWithMessage :: Keyword
|
||||
kwAnomaVerifyWithMessage = asciiKw Str.anomaVerifyWithMessage
|
||||
|
||||
kwByteArrayFromListByte :: Keyword
|
||||
kwByteArrayFromListByte = asciiKw Str.byteArrayFromListByte
|
||||
|
||||
kwByteArrayLength :: Keyword
|
||||
kwByteArrayLength = asciiKw Str.byteArrayLength
|
||||
|
||||
delimBraceL :: Keyword
|
||||
delimBraceL = mkDelim Str.braceL
|
||||
|
||||
|
@ -185,6 +185,15 @@ byteToNat = "byte-to-nat"
|
||||
byteFromNat :: (IsString s) => s
|
||||
byteFromNat = "byte-from-nat"
|
||||
|
||||
byteArray :: (IsString s) => s
|
||||
byteArray = "bytearray"
|
||||
|
||||
byteArrayFromListByte :: (IsString s) => s
|
||||
byteArrayFromListByte = "bytearray-from-list-byte"
|
||||
|
||||
byteArrayLength :: (IsString s) => s
|
||||
byteArrayLength = "bytearray-length"
|
||||
|
||||
nat :: (IsString s) => s
|
||||
nat = "nat"
|
||||
|
||||
@ -728,6 +737,9 @@ fun_ = "function"
|
||||
integer :: (IsString s) => s
|
||||
integer = "integer"
|
||||
|
||||
uint8 :: (IsString s) => s
|
||||
uint8 = "uint8"
|
||||
|
||||
bool :: (IsString s) => s
|
||||
bool = "bool"
|
||||
|
||||
@ -794,6 +806,12 @@ instrUInt8ToInt = "u8toi"
|
||||
instrIntToUInt8 :: (IsString s) => s
|
||||
instrIntToUInt8 = "itou8"
|
||||
|
||||
instrByteArrayFromListUInt8 :: (IsString s) => s
|
||||
instrByteArrayFromListUInt8 = "bytearray-from-list-uint8"
|
||||
|
||||
instrByteArrayLength :: (IsString s) => s
|
||||
instrByteArrayLength = "bytearray-length"
|
||||
|
||||
instrShow :: (IsString s) => s
|
||||
instrShow = "show"
|
||||
|
||||
@ -923,6 +941,12 @@ nil = "nil"
|
||||
cons :: (IsString s) => s
|
||||
cons = "cons"
|
||||
|
||||
builtinListCons :: (IsString s) => s
|
||||
builtinListCons = "builtinListCons"
|
||||
|
||||
builtinListNil :: (IsString s) => s
|
||||
builtinListNil = "builtinListNil"
|
||||
|
||||
nothing :: (IsString s) => s
|
||||
nothing = "nothing"
|
||||
|
||||
|
@ -612,5 +612,22 @@ allTests =
|
||||
[nock| 3 |],
|
||||
[nock| 240 |],
|
||||
[nock| [1 238 3 2 nil] |]
|
||||
],
|
||||
mkAnomaCallTest
|
||||
"Test082: ByteArray"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test082.juvix")
|
||||
[]
|
||||
$ checkOutput
|
||||
[ [nock| 0 |],
|
||||
[nock| [0 0] |],
|
||||
[nock| 3 |],
|
||||
[nock| [3 0] |],
|
||||
[nock| 4 |],
|
||||
[nock| [4 1] |],
|
||||
[nock| 2 |],
|
||||
[nock| [2 258] |],
|
||||
[nock| 1 |],
|
||||
[nock| [1 0] |]
|
||||
]
|
||||
]
|
||||
|
@ -8,7 +8,10 @@ allTests :: TestTree
|
||||
allTests = testGroup "JuvixCore to JuvixAsm positive tests" (map liftTest (Eval.filterOutTests ignoredTests Eval.compilableTests))
|
||||
|
||||
ignoredTests :: [String]
|
||||
ignoredTests = ["Test062: Anoma"]
|
||||
ignoredTests =
|
||||
[ "Test062: Anoma",
|
||||
"Test064: ByteArray"
|
||||
]
|
||||
|
||||
liftTest :: Eval.PosTest -> TestTree
|
||||
liftTest _testEval =
|
||||
|
@ -7,7 +7,7 @@ import Core.Eval.Positive qualified as Eval
|
||||
allTests :: TestTree
|
||||
allTests = testGroup "JuvixCore compilation tests" (map liftTest (Eval.filterOutTests ignoredTests Eval.compilableTests))
|
||||
|
||||
-- Arbitrary precision integers and fields not yet supported
|
||||
-- Arbitrary precision integers, fields, Anoma ops, and bytearrayss not yet supported
|
||||
ignoredTests :: [String]
|
||||
ignoredTests =
|
||||
[ "Test011: Tail recursion: Fibonacci numbers in linear time",
|
||||
@ -17,7 +17,8 @@ ignoredTests =
|
||||
"Test036: Big numbers",
|
||||
"Test040: LetRec - fib, fact",
|
||||
"Test061: Fields",
|
||||
"Test062: Anoma"
|
||||
"Test062: Anoma",
|
||||
"Test064: ByteArray"
|
||||
]
|
||||
|
||||
liftTest :: Eval.PosTest -> TestTree
|
||||
|
@ -352,5 +352,15 @@ tests =
|
||||
"Test062: Anoma"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test062.jvc")
|
||||
$(mkRelFile "out/test062.out")
|
||||
$(mkRelFile "out/test062.out"),
|
||||
PosTest
|
||||
"Test063: UInt8"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test063.jvc")
|
||||
$(mkRelFile "out/test063.out"),
|
||||
PosTest
|
||||
"Test064: ByteArray"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test064.jvc")
|
||||
$(mkRelFile "out/test064.out")
|
||||
]
|
||||
|
@ -49,7 +49,7 @@ testDescr Tree.PosTest {..} =
|
||||
|
||||
-- | Tests which require Nockma-specific expected output files
|
||||
testsConstr :: [Int]
|
||||
testsConstr = [9, 28, 35]
|
||||
testsConstr = [9, 28, 35, 40]
|
||||
|
||||
testsNegativeInteger :: [Int]
|
||||
testsNegativeInteger = [16]
|
||||
|
@ -269,7 +269,16 @@ juvixCallingConventionTests =
|
||||
lenR :: Term Natural = nockIntegralLiteral (length r)
|
||||
tupR = OpQuote # foldTerms (toNock <$> r)
|
||||
in compilerTest "appendToTuple (left empty, right-nonempty)" (appendToTuple (OpQuote # nockNilTagged "test-appendtotuple") (nockNatLiteral 0) tupR lenR) (eqNock res),
|
||||
compilerTest "stdlib cat" (callStdlib StdlibCatBytes [nockNatLiteral 2, nockNatLiteral 1]) (eqNock [nock| 258 |])
|
||||
compilerTest "stdlib cat" (callStdlib StdlibCatBytes [nockNatLiteral 2, nockNatLiteral 1]) (eqNock [nock| 258 |]),
|
||||
compilerTest "fold bytes empty" (callStdlib StdlibFoldBytes [OpQuote # makeList []]) (eqNock [nock| 0 |]),
|
||||
compilerTest "fold bytes [1, 0, 0] == 1" (callStdlib StdlibFoldBytes [OpQuote # makeList (toNock @Natural <$> [1, 0, 0])]) (eqNock [nock| 1 |]),
|
||||
compilerTest "fold bytes single byte" (callStdlib StdlibFoldBytes [OpQuote # makeList (toNock @Natural <$> [123])]) (eqNock [nock| 123 |]),
|
||||
compilerTest "fold bytes [0, 1] == 256" (callStdlib StdlibFoldBytes [OpQuote # makeList (toNock @Natural <$> [0, 1])]) (eqNock [nock| 256 |]),
|
||||
compilerTest "fold bytes [5, 1] == 261" (callStdlib StdlibFoldBytes [OpQuote # makeList (toNock @Natural <$> [5, 1])]) (eqNock [nock| 261 |]),
|
||||
compilerTest "fold bytes [0, 1, 0] == 256" (callStdlib StdlibFoldBytes [OpQuote # makeList (toNock @Natural <$> [0, 1, 0])]) (eqNock [nock| 256 |]),
|
||||
compilerTest "length [] == 0" (callStdlib StdlibLengthList [OpQuote # makeList []]) (eqNock [nock| 0 |]),
|
||||
compilerTest "length [10] == 1" (callStdlib StdlibLengthList [OpQuote # makeList [[nock| 10 |]]]) (eqNock [nock| 1 |]),
|
||||
compilerTest "length [[1 2, 3], 0] == 2" (callStdlib StdlibLengthList [OpQuote # makeList [[nock| [1 2 3] |], [nock| 0 |]]]) (eqNock [nock| 2 |])
|
||||
]
|
||||
|
||||
unitTests :: [Test]
|
||||
|
@ -15,8 +15,11 @@ testDescr Eval.PosTest {..} =
|
||||
_testAssertion = Steps $ treeAsmAssertion file' expected'
|
||||
}
|
||||
|
||||
ignoredTests :: [String]
|
||||
ignoredTests = ["Test040: ByteArray"]
|
||||
|
||||
allTests :: TestTree
|
||||
allTests =
|
||||
testGroup
|
||||
"JuvixTree to JuvixAsm positive tests"
|
||||
(map (mkTest . testDescr) Eval.tests)
|
||||
(map (mkTest . testDescr) (Eval.filterOutTests ignoredTests Eval.tests))
|
||||
|
@ -229,5 +229,15 @@ tests =
|
||||
"Test038: Apply & argsnum"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test038.jvt")
|
||||
$(mkRelFile "out/test038.out")
|
||||
$(mkRelFile "out/test038.out"),
|
||||
PosTest
|
||||
"Test039: UInt8"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test039.jvt")
|
||||
$(mkRelFile "out/test039.out"),
|
||||
PosTest
|
||||
"Test040: ByteArray"
|
||||
$(mkRelDir ".")
|
||||
$(mkRelFile "test040.jvt")
|
||||
$(mkRelFile "out/test040.out")
|
||||
]
|
||||
|
35
tests/Anoma/Compilation/positive/test082.juvix
Normal file
35
tests/Anoma/Compilation/positive/test082.juvix
Normal file
@ -0,0 +1,35 @@
|
||||
module test082;
|
||||
|
||||
import Stdlib.Prelude open;
|
||||
import Stdlib.Debug.Trace open;
|
||||
|
||||
builtin bytearray
|
||||
axiom ByteArray : Type;
|
||||
|
||||
builtin bytearray-from-list-byte
|
||||
axiom mkByteArray : List Byte -> ByteArray;
|
||||
|
||||
builtin bytearray-length
|
||||
axiom size : ByteArray -> Nat;
|
||||
|
||||
bs0 : ByteArray := mkByteArray [];
|
||||
|
||||
bs1 : ByteArray := mkByteArray [0x0; 0x0; 0x0];
|
||||
|
||||
bs2 : ByteArray := mkByteArray [0x1; 0x0; 0x0; 0x0];
|
||||
|
||||
bs3 : ByteArray := mkByteArray [0x2; 0x1];
|
||||
|
||||
bs4 : ByteArray := mkByteArray [0x100];
|
||||
|
||||
main : ByteArray :=
|
||||
trace (size bs0)
|
||||
>-> trace bs0
|
||||
>-> trace (size bs1)
|
||||
>-> trace bs1
|
||||
>-> trace (size bs2)
|
||||
>-> trace bs2
|
||||
>-> trace (size bs3)
|
||||
>-> trace bs3
|
||||
>-> trace (size bs4)
|
||||
>-> bs4;
|
2
tests/Core/positive/out/test064.out
Normal file
2
tests/Core/positive/out/test064.out
Normal file
@ -0,0 +1,2 @@
|
||||
bytearray-from-list-byte (builtinListCons UInt8 1 (builtinListCons UInt8 2 (builtinListNil UInt8)))
|
||||
2
|
@ -1,5 +1,5 @@
|
||||
-- UInt8
|
||||
|
||||
def f := \x x;
|
||||
def f : UInt8 -> UInt8 := \x x;
|
||||
|
||||
f 257u8
|
||||
|
6
tests/Core/positive/test064.jvc
Normal file
6
tests/Core/positive/test064.jvc
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
def writeLn := \x write x >> write "\n";
|
||||
|
||||
def bs : ByteArray := bytearray-from-list-byte (builtinListCons UInt8 257u8 (builtinListCons UInt8 2u8 (builtinListNil UInt8)));
|
||||
|
||||
writeLn bs >> writeLn (bytearray-length bs)
|
1
tests/Tree/positive/out/test039.out
Normal file
1
tests/Tree/positive/out/test039.out
Normal file
@ -0,0 +1 @@
|
||||
1
|
2
tests/Tree/positive/out/test040.nockma.out
Normal file
2
tests/Tree/positive/out/test040.nockma.out
Normal file
@ -0,0 +1,2 @@
|
||||
2
|
||||
[2 258]
|
2
tests/Tree/positive/out/test040.out
Normal file
2
tests/Tree/positive/out/test040.out
Normal file
@ -0,0 +1,2 @@
|
||||
2
|
||||
alloc[cons](2u8, alloc[cons](1u8, alloc[nil]()))
|
11
tests/Tree/positive/test039.jvt
Normal file
11
tests/Tree/positive/test039.jvt
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
function id(uint8) : uint8;
|
||||
function main() : *
|
||||
|
||||
function id(uint8) : uint8 {
|
||||
arg[0]
|
||||
}
|
||||
|
||||
function main() : * {
|
||||
call[id](257u8)
|
||||
}
|
12
tests/Tree/positive/test040.jvt
Normal file
12
tests/Tree/positive/test040.jvt
Normal file
@ -0,0 +1,12 @@
|
||||
-- ByteArray
|
||||
|
||||
type list {
|
||||
nil : list;
|
||||
cons : * -> list -> list;
|
||||
}
|
||||
|
||||
function main() : * {
|
||||
save(bytearray-from-list-uint8(alloc[cons](258u8, alloc[cons](1u8, alloc[nil]())))) {
|
||||
seq(trace(bytearray-length(tmp[0])), tmp[0])
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user