1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-26 09:04:18 +03:00

The assert builtin (#3014)

* Requires #3015
This commit is contained in:
Łukasz Czajka 2024-09-12 09:29:57 +02:00 committed by GitHub
parent 8e204634b8
commit 26ea94b977
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 309 additions and 28 deletions

View File

@ -70,10 +70,6 @@ calculateInterest : Nat -> Nat -> Nat -> Nat
incrAmount (a : Nat) : Nat := div (a * rate) 10000; incrAmount (a : Nat) : Nat := div (a * rate) 10000;
in iterate (min 100 periods) incrAmount amount; in iterate (min 100 periods) incrAmount amount;
--- Asserts some ;Bool; condition.
assert : {A : Type} -> Bool -> A -> A
| c a := ite c a (failwith "assertion failed");
--- Returns a new ;Token;. Arguments are: --- Returns a new ;Token;. Arguments are:
--- ---
--- `owner`: The address of the account to issue the token to --- `owner`: The address of the account to issue the token to
@ -82,7 +78,7 @@ assert : {A : Type} -> Bool -> A -> A
--- ---
--- `caller`: Who is creating the transaction. It must be the bank. --- `caller`: Who is creating the transaction. It must be the bank.
issue : Address -> Address -> Nat -> Token issue : Address -> Address -> Nat -> Token
| caller owner amount := assert (caller == bankAddress) (mkToken owner 0 amount); | caller owner amount := assert (caller == bankAddress) >-> mkToken owner 0 amount;
--- Deposits some amount of money into the bank. --- Deposits some amount of money into the bank.
deposit (bal : Balances) (token : Token) (amount : Nat) : Token := deposit (bal : Balances) (token : Token) (amount : Nat) : Token :=
@ -102,11 +98,10 @@ withdraw
(rate : Nat) (rate : Nat)
(periods : Nat) (periods : Nat)
: Token := : Token :=
assert assert (caller == bankAddress)
(caller == bankAddress) >-> let
(let hash : Field := hashAddress recipient;
hash : Field := hashAddress recipient; total : Nat := calculateInterest amount rate periods;
total : Nat := calculateInterest amount rate periods; token : Token := mkToken recipient 0 total;
token : Token := mkToken recipient 0 total; bal' : Balances := decrement hash amount bal;
bal' : Balances := decrement hash amount bal; in runOnChain (commitBalances bal') token;
in runOnChain (commitBalances bal') token);

@ -1 +1 @@
Subproject commit 615a02c8107076ca9661c5234d41792be91a5104 Subproject commit 6010ad32f80498432b9a14752a0b7b50e9b36763

View File

@ -104,6 +104,7 @@ closure_label:
#define JUVIX_INT_TO_UINT8(var0, var1) \ #define JUVIX_INT_TO_UINT8(var0, var1) \
(var0 = make_smallint((word_t)((uint8_t)(get_unboxed_int(var1) & 0xFF)))) (var0 = make_smallint((word_t)((uint8_t)(get_unboxed_int(var1) & 0xFF))))
#define JUVIX_ASSERT(val) (assert(is_true(val)))
#define JUVIX_TRACE(val) (io_trace(val)) #define JUVIX_TRACE(val) (io_trace(val))
#define JUVIX_DUMP (stacktrace_dump()) #define JUVIX_DUMP (stacktrace_dump())
#define JUVIX_FAILURE(val) \ #define JUVIX_FAILURE(val) \

View File

@ -92,6 +92,8 @@ recurse' sig = go True
throw $ throw $
AsmError loc "popping empty value stack" AsmError loc "popping empty value stack"
return (popValueStack 1 mem) return (popValueStack 1 mem)
Assert ->
return mem
Trace -> Trace ->
return mem return mem
Dump -> Dump ->
@ -412,6 +414,8 @@ recurseS' sig = go True
return (stackInfoPushValueStack 1 si) return (stackInfoPushValueStack 1 si)
Pop -> do Pop -> do
return (stackInfoPopValueStack 1 si) return (stackInfoPopValueStack 1 si)
Assert ->
return si
Trace -> Trace ->
return si return si
Dump -> Dump ->

View File

@ -82,6 +82,11 @@ runCodeR infoTable funInfo = goCode (funInfo ^. functionCode) >> popLastValueSta
goCode cont goCode cont
Pop -> Pop ->
popValueStack >> goCode cont popValueStack >> goCode cont
Assert -> do
v <- topValueStack
unless (v == ValBool True) $
runtimeError "assertion failed"
goCode cont
Trace -> do Trace -> do
v <- topValueStack v <- topValueStack
logMessage (printValue infoTable v) logMessage (printValue infoTable v)

View File

@ -49,6 +49,9 @@ data Instruction
Push Value Push Value
| -- | Pop the stack. JVA opcode: 'pop'. | -- | Pop the stack. JVA opcode: 'pop'.
Pop Pop
| -- | Assert a boolean on top of the stack. Does not pop the stack. JVA
-- opcode: 'assert'.
Assert
| -- | Print a debug log of the object on top of the stack. Does not pop the | -- | Print a debug log of the object on top of the stack. Does not pop the
-- stack. JVA opcode: 'trace'. -- stack. JVA opcode: 'trace'.
Trace Trace

View File

@ -98,6 +98,7 @@ instance PrettyCode Instruction where
Cairo op -> Tree.ppCode op Cairo op -> Tree.ppCode op
Push val -> (primitive Str.instrPush <+>) <$> ppCode val Push val -> (primitive Str.instrPush <+>) <$> ppCode val
Pop -> return $ primitive Str.instrPop Pop -> return $ primitive Str.instrPop
Assert -> return $ primitive Str.instrAssert
Trace -> return $ primitive Str.instrTrace Trace -> return $ primitive Str.instrTrace
Dump -> return $ primitive Str.instrDump Dump -> return $ primitive Str.instrDump
Failure -> return $ primitive Str.instrFailure Failure -> return $ primitive Str.instrFailure

View File

@ -91,6 +91,8 @@ command = do
mkInstr' loc . Push <$> value mkInstr' loc . Push <$> value
"pop" -> "pop" ->
return $ mkInstr' loc Pop return $ mkInstr' loc Pop
"assert" ->
return $ mkInstr' loc Assert
"trace" -> "trace" ->
return $ mkInstr' loc Trace return $ mkInstr' loc Trace
"dump" -> "dump" ->

View File

@ -233,6 +233,7 @@ genCode fi =
genUnOp :: Tree.UnaryOpcode -> Command genUnOp :: Tree.UnaryOpcode -> Command
genUnOp op = case op of genUnOp op = case op of
Tree.PrimUnop op' -> mkUnop op' Tree.PrimUnop op' -> mkUnop op'
Tree.OpAssert -> mkInstr Assert
Tree.OpTrace -> mkInstr Trace Tree.OpTrace -> mkInstr Trace
Tree.OpFail -> mkInstr Failure Tree.OpFail -> mkInstr Failure

View File

@ -227,6 +227,8 @@ fromRegInstr bNoStack info = \case
unsupported "Cairo builtin" unsupported "Cairo builtin"
Reg.Assign Reg.InstrAssign {..} -> Reg.Assign Reg.InstrAssign {..} ->
return $ stmtsAssign (fromVarRef _instrAssignResult) (fromValue _instrAssignValue) return $ stmtsAssign (fromVarRef _instrAssignResult) (fromValue _instrAssignValue)
Reg.Assert Reg.InstrAssert {..} ->
return [StatementExpr $ macroCall "JUVIX_ASSERT" [fromValue _instrAssertValue]]
Reg.Trace Reg.InstrTrace {..} -> Reg.Trace Reg.InstrTrace {..} ->
return [StatementExpr $ macroCall "JUVIX_TRACE" [fromValue _instrTraceValue]] return [StatementExpr $ macroCall "JUVIX_TRACE" [fromValue _instrTraceValue]]
Reg.Dump -> Reg.Dump ->

View File

@ -43,6 +43,7 @@ fromCasm instrs0 =
Casm.Return -> goReturn Casm.Return -> goReturn
Casm.Alloc x -> goAlloc x Casm.Alloc x -> goAlloc x
Casm.Hint x -> goHint x Casm.Hint x -> goHint x
Casm.Assert x -> goAssert x
Casm.Trace {} -> [] Casm.Trace {} -> []
Casm.Label {} -> [] Casm.Label {} -> []
Casm.Nop -> [] Casm.Nop -> []
@ -230,6 +231,14 @@ fromCasm instrs0 =
. set instrApUpdate ApUpdateAdd . set instrApUpdate ApUpdateAdd
$ defaultInstruction $ defaultInstruction
goAssert :: Casm.InstrAssert -> [Element]
goAssert Casm.InstrAssert {..} =
toElems
. updateOps False (Casm.Val (Casm.Imm 0))
. updateDst _instrAssertValue
. set instrOpcode AssertEq
$ defaultInstruction
goHint :: Casm.Hint -> [Element] goHint :: Casm.Hint -> [Element]
goHint = \case goHint = \case
Casm.HintInput var -> [ElementHint (Hint ("Input(" <> var <> ")"))] Casm.HintInput var -> [ElementHint (Hint ("Input(" <> var <> ")"))]

View File

@ -130,6 +130,8 @@ fromRegInstr info = \case
unsupported "Cairo builtin" unsupported "Cairo builtin"
Reg.Assign Reg.InstrAssign {..} -> Reg.Assign Reg.InstrAssign {..} ->
stmtsAssign (mkVarRef _instrAssignResult) (fromValue _instrAssignValue) stmtsAssign (mkVarRef _instrAssignResult) (fromValue _instrAssignValue)
Reg.Assert {} ->
unsupported "assert"
Reg.Trace {} -> Reg.Trace {} ->
unsupported "trace" unsupported "trace"
Reg.Dump -> Reg.Dump ->

View File

@ -0,0 +1,24 @@
module Juvix.Compiler.Builtins.Assert where
import Juvix.Compiler.Internal.Builtins
import Juvix.Compiler.Internal.Extra
import Juvix.Prelude
checkAssert :: (Members '[Reader BuiltinsTable, Error ScoperError, NameIdGen] r) => FunctionDef -> Sem r ()
checkAssert f = do
bool_ <- getBuiltinNameScoper (getLoc f) BuiltinBool
let assert_ = f ^. funDefName
l = getLoc f
varx <- freshVar l "x"
let x = toExpression varx
assertClauses :: [(Expression, Expression)]
assertClauses = [(assert_ @@ x, x)]
checkBuiltinFunctionInfo
FunInfo
{ _funInfoDef = f,
_funInfoBuiltin = BuiltinAssert,
_funInfoSignature = bool_ --> bool_,
_funInfoClauses = assertClauses,
_funInfoFreeVars = [varx],
_funInfoFreeTypeVars = []
}

View File

@ -64,6 +64,7 @@ hRunCode hout inputInfo (LabelInfo labelInfo) instrs0 = runST goCode
Call x -> goCall x pc ap fp mem Call x -> goCall x pc ap fp mem
Return -> goReturn pc ap fp mem Return -> goReturn pc ap fp mem
Alloc x -> goAlloc x pc ap fp mem Alloc x -> goAlloc x pc ap fp mem
Assert x -> goAssert x pc ap fp mem
Trace x -> goTrace x pc ap fp mem Trace x -> goTrace x pc ap fp mem
Hint x -> goHint x pc ap fp mem Hint x -> goHint x pc ap fp mem
Label {} -> go (pc + 1) ap fp mem Label {} -> go (pc + 1) ap fp mem
@ -244,6 +245,13 @@ hRunCode hout inputInfo (LabelInfo labelInfo) instrs0 = runST goCode
v <- readRValue ap fp mem _instrAllocSize v <- readRValue ap fp mem _instrAllocSize
go (pc + 1) (ap + fromInteger (fieldToInteger v)) fp mem go (pc + 1) (ap + fromInteger (fieldToInteger v)) fp mem
goAssert :: InstrAssert -> Address -> Address -> Address -> Memory s -> ST s FField
goAssert InstrAssert {..} pc ap fp mem = do
v <- readMemRef ap fp mem _instrAssertValue
when (fieldToInteger v /= 0) $
throwRunError "assertion failed"
go (pc + 1) ap fp mem
goTrace :: InstrTrace -> Address -> Address -> Address -> Memory s -> ST s FField goTrace :: InstrTrace -> Address -> Address -> Address -> Memory s -> ST s FField
goTrace InstrTrace {..} pc ap fp mem = do goTrace InstrTrace {..} pc ap fp mem = do
v <- readRValue ap fp mem _instrTraceValue v <- readRValue ap fp mem _instrTraceValue

View File

@ -11,6 +11,7 @@ import Juvix.Data.Keyword.All
kwAbs, kwAbs,
kwAp, kwAp,
kwApPlusPlus, kwApPlusPlus,
kwAssert,
kwCall, kwCall,
kwColon, kwColon,
kwDiv, kwDiv,
@ -45,6 +46,7 @@ allKeywords =
kwAbs, kwAbs,
kwAp, kwAp,
kwApPlusPlus, kwApPlusPlus,
kwAssert,
kwCall, kwCall,
kwColon, kwColon,
kwDiv, kwDiv,

View File

@ -90,6 +90,7 @@ data Instruction
| Call InstrCall | Call InstrCall
| Return | Return
| Alloc InstrAlloc | Alloc InstrAlloc
| Assert InstrAssert
| Trace InstrTrace | Trace InstrTrace
| Hint Hint | Hint Hint
| Label LabelRef | Label LabelRef
@ -132,6 +133,10 @@ newtype InstrAlloc = InstrAlloc
{ _instrAllocSize :: RValue { _instrAllocSize :: RValue
} }
newtype InstrAssert = InstrAssert
{ _instrAssertValue :: MemRef
}
newtype InstrTrace = InstrTrace newtype InstrTrace = InstrTrace
{ _instrTraceValue :: RValue { _instrTraceValue :: RValue
} }
@ -148,4 +153,5 @@ makeLenses ''InstrJump
makeLenses ''InstrJumpIf makeLenses ''InstrJumpIf
makeLenses ''InstrCall makeLenses ''InstrCall
makeLenses ''InstrAlloc makeLenses ''InstrAlloc
makeLenses ''InstrAssert
makeLenses ''InstrTrace makeLenses ''InstrTrace

View File

@ -171,6 +171,11 @@ instance PrettyCode InstrAlloc where
s <- ppCode _instrAllocSize s <- ppCode _instrAllocSize
return $ Str.ap <+> Str.plusequal <+> s return $ Str.ap <+> Str.plusequal <+> s
instance PrettyCode InstrAssert where
ppCode InstrAssert {..} = do
v <- ppCode _instrAssertValue
return $ Str.assert_ <+> v
instance PrettyCode InstrTrace where instance PrettyCode InstrTrace where
ppCode InstrTrace {..} = do ppCode InstrTrace {..} = do
v <- ppCode _instrTraceValue v <- ppCode _instrTraceValue
@ -185,6 +190,7 @@ instance PrettyCode Instruction where
Call x -> ppCode x Call x -> ppCode x
Return -> return Str.ret Return -> return Str.ret
Alloc x -> ppCode x Alloc x -> ppCode x
Assert x -> ppCode x
Trace x -> ppCode x Trace x -> ppCode x
Hint x -> ppCode x Hint x -> ppCode x
Label x -> (<> colon) <$> ppCode x Label x -> (<> colon) <$> ppCode x

View File

@ -286,6 +286,7 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
Reg.Assign x -> goAssign x Reg.Assign x -> goAssign x
Reg.Alloc x -> goAlloc x Reg.Alloc x -> goAlloc x
Reg.AllocClosure x -> goAllocClosure x Reg.AllocClosure x -> goAllocClosure x
Reg.Assert x -> goAssert x
Reg.Trace x -> goTrace x Reg.Trace x -> goTrace x
Reg.Dump -> unsupported "dump" Reg.Dump -> unsupported "dump"
Reg.Failure x -> goFail x Reg.Failure x -> goFail x
@ -512,6 +513,18 @@ fromReg tab = mkResult $ run $ runLabelInfoBuilderWithNextId (Reg.getNextSymbolI
storedArgsNum = length _instrAllocClosureArgs storedArgsNum = length _instrAllocClosureArgs
leftArgsNum = _instrAllocClosureExpectedArgsNum - storedArgsNum leftArgsNum = _instrAllocClosureExpectedArgsNum - storedArgsNum
goAssert :: Reg.InstrAssert -> Sem r ()
goAssert Reg.InstrAssert {..} = do
v <- goValue _instrAssertValue
case v of
Imm c
| c == 0 -> return ()
| otherwise ->
output' 0 $ mkAssign (MemRef Ap 0) (Binop $ BinopValue FieldAdd (MemRef Ap 0) (Imm 1))
Ref r ->
output' 0 $ Assert (InstrAssert r)
Lab {} -> unsupported "assert label"
goTrace :: Reg.InstrTrace -> Sem r () goTrace :: Reg.InstrTrace -> Sem r ()
goTrace Reg.InstrTrace {..} = do goTrace Reg.InstrTrace {..} = do
v <- mkRValue _instrTraceValue v <- mkRValue _instrTraceValue

View File

@ -74,6 +74,7 @@ instruction =
<|> parseJump <|> parseJump
<|> parseCall <|> parseCall
<|> parseReturn <|> parseReturn
<|> parseAssert
<|> parseTrace <|> parseTrace
<|> parseAssign <|> parseAssign
@ -249,6 +250,12 @@ parseReturn = do
kw kwRet kw kwRet
return Return return Return
parseAssert :: ParsecS r Instruction
parseAssert = do
kw kwAssert
r <- parseMemRef
return $ Assert $ InstrAssert {_instrAssertValue = r}
parseTrace :: (Member LabelInfoBuilder r) => ParsecS r Instruction parseTrace :: (Member LabelInfoBuilder r) => ParsecS r Instruction
parseTrace = do parseTrace = do
kw kwTrace kw kwTrace

View File

@ -18,6 +18,7 @@ validate labi instrs = mapM_ go instrs
Call x -> goCall x Call x -> goCall x
Return -> return () Return -> return ()
Alloc x -> goAlloc x Alloc x -> goAlloc x
Assert x -> goAssert x
Trace x -> goTrace x Trace x -> goTrace x
Hint {} -> return () Hint {} -> return ()
Label {} -> return () Label {} -> return ()
@ -66,3 +67,6 @@ validate labi instrs = mapM_ go instrs
goTrace :: InstrTrace -> Either CasmError () goTrace :: InstrTrace -> Either CasmError ()
goTrace InstrTrace {..} = goRValue _instrTraceValue goTrace InstrTrace {..} = goRValue _instrTraceValue
goAssert :: InstrAssert -> Either CasmError ()
goAssert InstrAssert {} = return ()

View File

@ -125,7 +125,8 @@ instance Serialize BuiltinConstructor
instance NFData BuiltinConstructor instance NFData BuiltinConstructor
data BuiltinFunction data BuiltinFunction
= BuiltinNatPlus = BuiltinAssert
| BuiltinNatPlus
| BuiltinNatSub | BuiltinNatSub
| BuiltinNatMul | BuiltinNatMul
| BuiltinNatUDiv | BuiltinNatUDiv
@ -163,6 +164,7 @@ instance NFData BuiltinFunction
instance Pretty BuiltinFunction where instance Pretty BuiltinFunction where
pretty = \case pretty = \case
BuiltinAssert -> Str.assert
BuiltinNatPlus -> Str.natPlus BuiltinNatPlus -> Str.natPlus
BuiltinNatSub -> Str.natSub BuiltinNatSub -> Str.natSub
BuiltinNatMul -> Str.natMul BuiltinNatMul -> Str.natMul
@ -368,6 +370,7 @@ isNatBuiltin = \case
BuiltinNatLt -> True BuiltinNatLt -> True
BuiltinNatEq -> True BuiltinNatEq -> True
-- --
BuiltinAssert -> False
BuiltinBoolIf -> False BuiltinBoolIf -> False
BuiltinBoolOr -> False BuiltinBoolOr -> False
BuiltinBoolAnd -> False BuiltinBoolAnd -> False
@ -403,6 +406,7 @@ isIntBuiltin = \case
BuiltinIntLe -> True BuiltinIntLe -> True
BuiltinIntLt -> True BuiltinIntLt -> True
-- --
BuiltinAssert -> False
BuiltinNatPlus -> False BuiltinNatPlus -> False
BuiltinNatSub -> False BuiltinNatSub -> False
BuiltinNatMul -> False BuiltinNatMul -> False
@ -425,6 +429,7 @@ isCastBuiltin = \case
BuiltinFromNat -> True BuiltinFromNat -> True
BuiltinFromInt -> True BuiltinFromInt -> True
-- --
BuiltinAssert -> False
BuiltinIntEq -> False BuiltinIntEq -> False
BuiltinIntPlus -> False BuiltinIntPlus -> False
BuiltinIntSubNat -> False BuiltinIntSubNat -> False
@ -496,6 +501,7 @@ isIgnoredBuiltin f
-- Monad -- Monad
BuiltinMonadBind -> False BuiltinMonadBind -> False
-- Ignored -- Ignored
BuiltinAssert -> True
BuiltinBoolIf -> True BuiltinBoolIf -> True
BuiltinBoolOr -> True BuiltinBoolOr -> True
BuiltinBoolAnd -> True BuiltinBoolAnd -> True

View File

@ -217,6 +217,7 @@ geval opts herr tab env0 = eval' env0
OpSeq -> seqOp OpSeq -> seqOp
OpFail -> failOp OpFail -> failOp
OpTrace -> traceOp OpTrace -> traceOp
OpAssert -> assertOp
OpAnomaGet -> anomaGetOp OpAnomaGet -> anomaGetOp
OpAnomaEncode -> anomaEncodeOp OpAnomaEncode -> anomaEncodeOp
OpAnomaDecode -> anomaDecodeOp OpAnomaDecode -> anomaDecodeOp
@ -367,6 +368,21 @@ geval opts herr tab env0 = eval' env0
unsafePerformIO (hPutStrLn herr (printNode v) >> return v) unsafePerformIO (hPutStrLn herr (printNode v) >> return v)
{-# INLINE traceOp #-} {-# INLINE traceOp #-}
assertOp :: [Node] -> Node
assertOp = unary $ \val ->
let !v = eval' env val
in if
| opts ^. evalOptionsSilent ->
v
| otherwise ->
case v of
NCtr Constr {..}
| _constrTag == BuiltinTag TagTrue ->
v
_ ->
Exception.throw (EvalError ("assertion failed: " <> printNode val) Nothing)
{-# INLINE assertOp #-}
anomaGetOp :: [Node] -> Node anomaGetOp :: [Node] -> Node
anomaGetOp = unary $ \arg -> anomaGetOp = unary $ \arg ->
if if

View File

@ -188,6 +188,7 @@ containsDebugOperations = ufold (\x xs -> x || or xs) isDebugOp
OpTrace -> True OpTrace -> True
OpFail -> True OpFail -> True
OpSeq -> True OpSeq -> True
OpAssert -> False
OpAnomaByteArrayFromAnomaContents -> False OpAnomaByteArrayFromAnomaContents -> False
OpAnomaByteArrayToAnomaContents -> False OpAnomaByteArrayToAnomaContents -> False
OpAnomaDecode -> False OpAnomaDecode -> False
@ -466,6 +467,7 @@ builtinOpArgTypes = \case
OpShow -> [mkDynamic'] OpShow -> [mkDynamic']
OpStrConcat -> [mkTypeString', mkTypeString'] OpStrConcat -> [mkTypeString', mkTypeString']
OpStrToInt -> [mkTypeString'] OpStrToInt -> [mkTypeString']
OpAssert -> [mkTypeBool']
OpSeq -> [mkDynamic', mkDynamic'] OpSeq -> [mkDynamic', mkDynamic']
OpTrace -> [mkDynamic'] OpTrace -> [mkDynamic']
OpFail -> [mkTypeString'] OpFail -> [mkTypeString']

View File

@ -15,6 +15,7 @@ import Juvix.Data.Keyword.All
kwAnomaVerifyDetached, kwAnomaVerifyDetached,
kwAnomaVerifyWithMessage, kwAnomaVerifyWithMessage,
kwAny, kwAny,
kwAssert,
kwAssign, kwAssign,
kwBindOperator, kwBindOperator,
kwBottom, kwBottom,
@ -72,6 +73,7 @@ allKeywordStrings = keywordsStrings allKeywords
allKeywords :: [Keyword] allKeywords :: [Keyword]
allKeywords = allKeywords =
[ delimSemicolon, [ delimSemicolon,
kwAssert,
kwAssign, kwAssign,
kwBottom, kwBottom,
kwBuiltin, kwBuiltin,

View File

@ -24,6 +24,7 @@ data BuiltinOp
| OpStrConcat | OpStrConcat
| OpStrToInt | OpStrToInt
| OpSeq | OpSeq
| OpAssert
| OpTrace | OpTrace
| OpFail | OpFail
| OpAnomaGet | OpAnomaGet
@ -84,6 +85,7 @@ builtinOpArgsNum = \case
OpStrConcat -> 2 OpStrConcat -> 2
OpStrToInt -> 1 OpStrToInt -> 1
OpSeq -> 2 OpSeq -> 2
OpAssert -> 1
OpTrace -> 1 OpTrace -> 1
OpFail -> 1 OpFail -> 1
OpAnomaGet -> 1 OpAnomaGet -> 1
@ -133,6 +135,7 @@ builtinIsFoldable = \case
OpStrConcat -> True OpStrConcat -> True
OpStrToInt -> True OpStrToInt -> True
OpSeq -> False OpSeq -> False
OpAssert -> False
OpTrace -> False OpTrace -> False
OpFail -> False OpFail -> False
OpAnomaGet -> False OpAnomaGet -> False

View File

@ -50,6 +50,7 @@ instance PrettyCode BuiltinOp where
OpShow -> return primShow OpShow -> return primShow
OpStrConcat -> return primStrConcat OpStrConcat -> return primStrConcat
OpStrToInt -> return primStrToInt OpStrToInt -> return primStrToInt
OpAssert -> return primAssert
OpSeq -> return primSeq OpSeq -> return primSeq
OpTrace -> return primTrace OpTrace -> return primTrace
OpFail -> return primFail OpFail -> return primFail
@ -867,6 +868,9 @@ kwPi = keyword Str.piUnicode
kwDef :: Doc Ann kwDef :: Doc Ann
kwDef = keyword Str.def kwDef = keyword Str.def
primAssert :: Doc Ann
primAssert = primitive Str.assert_
primSeq :: Doc Ann primSeq :: Doc Ann
primSeq = primitive Str.seqq_ primSeq = primitive Str.seqq_

View File

@ -64,6 +64,9 @@ computeNodeTypeInfo md = umapL go
OpSeq -> case _builtinAppArgs of OpSeq -> case _builtinAppArgs of
[_, arg2] -> Info.getNodeType arg2 [_, arg2] -> Info.getNodeType arg2
_ -> error "incorrect seq builtin application" _ -> error "incorrect seq builtin application"
OpAssert -> case _builtinAppArgs of
[arg] -> Info.getNodeType arg
_ -> error "incorrect assert builtin application"
OpTrace -> case _builtinAppArgs of OpTrace -> case _builtinAppArgs of
[arg] -> Info.getNodeType arg [arg] -> Info.getNodeType arg
_ -> error "incorrect trace builtin application" _ -> error "incorrect trace builtin application"

View File

@ -1309,6 +1309,11 @@ goApplication a = do
(_ : _ : arg1 : arg2 : xs) -> (_ : _ : arg1 : arg2 : xs) ->
return (mkApps' (mkBuiltinApp' OpSeq [arg1, arg2]) xs) return (mkApps' (mkBuiltinApp' OpSeq [arg1, arg2]) xs)
_ -> error "internal to core: seq must be called with 2 arguments" _ -> error "internal to core: seq must be called with 2 arguments"
Just Internal.BuiltinAssert -> do
as <- exprArgs
case as of
(x : xs) -> return (mkApps' (mkBuiltinApp' OpAssert [x]) xs)
_ -> error "internal to core: assert must be called with 1 argument"
_ -> app _ -> app
_ -> app _ -> app

View File

@ -569,6 +569,7 @@ builtinAppExpr varsNum vars = do
<|> (kw kwShow $> OpShow) <|> (kw kwShow $> OpShow)
<|> (kw kwStrConcat $> OpStrConcat) <|> (kw kwStrConcat $> OpStrConcat)
<|> (kw kwStrToInt $> OpStrToInt) <|> (kw kwStrToInt $> OpStrToInt)
<|> (kw kwAssert $> OpAssert)
<|> (kw kwSeqq $> OpSeq) <|> (kw kwSeqq $> OpSeq)
<|> (kw kwTrace $> OpTrace) <|> (kw kwTrace $> OpTrace)
<|> (kw kwFail $> OpFail) <|> (kw kwFail $> OpFail)

View File

@ -28,6 +28,7 @@ fromCore fsize tab =
shouldKeepFunction :: BuiltinFunction -> Bool shouldKeepFunction :: BuiltinFunction -> Bool
shouldKeepFunction = \case shouldKeepFunction = \case
BuiltinAssert -> False
BuiltinNatPlus -> False BuiltinNatPlus -> False
BuiltinNatSub -> False BuiltinNatSub -> False
BuiltinNatMul -> False BuiltinNatMul -> False

View File

@ -14,6 +14,7 @@ import Data.HashSet qualified as HashSet
import Data.IntMap.Strict qualified as IntMap import Data.IntMap.Strict qualified as IntMap
import Data.List.NonEmpty qualified as NonEmpty import Data.List.NonEmpty qualified as NonEmpty
import Juvix.Compiler.Builtins import Juvix.Compiler.Builtins
import Juvix.Compiler.Builtins.Assert
import Juvix.Compiler.Builtins.Pair import Juvix.Compiler.Builtins.Pair
import Juvix.Compiler.Concrete.Data.ScopedName qualified as S import Juvix.Compiler.Concrete.Data.ScopedName qualified as S
import Juvix.Compiler.Concrete.Extra qualified as Concrete import Juvix.Compiler.Concrete.Extra qualified as Concrete
@ -537,6 +538,7 @@ checkBuiltinFunction ::
BuiltinFunction -> BuiltinFunction ->
Sem r () Sem r ()
checkBuiltinFunction d f = localBuiltins $ case f of checkBuiltinFunction d f = localBuiltins $ case f of
BuiltinAssert -> checkAssert d
BuiltinNatPlus -> checkNatPlus d BuiltinNatPlus -> checkNatPlus d
BuiltinNatSub -> checkNatSub d BuiltinNatSub -> checkNatSub d
BuiltinNatMul -> checkNatMul d BuiltinNatMul -> checkNatMul d

View File

@ -517,6 +517,9 @@ compile = \case
arg <- compile _nodeUnopArg arg <- compile _nodeUnopArg
case _nodeUnopOpcode of case _nodeUnopOpcode of
Tree.PrimUnop op -> return $ goPrimUnop op arg Tree.PrimUnop op -> return $ goPrimUnop op arg
Tree.OpAssert ->
-- TODO: remove duplication of `arg` here
return (branch arg arg crash)
Tree.OpFail -> return crash Tree.OpFail -> return crash
Tree.OpTrace -> goTrace arg Tree.OpTrace -> goTrace arg
@ -525,6 +528,7 @@ compile = \case
Tree.OpShow -> stringsErr "show" Tree.OpShow -> stringsErr "show"
Tree.OpStrToInt -> stringsErr "strToInt" Tree.OpStrToInt -> stringsErr "strToInt"
Tree.OpArgsNum -> Tree.OpArgsNum ->
-- TODO: remove duplication of `arg` here!!!
let getF f = getClosureField f arg let getF f = getClosureField f arg
in sub (getF ClosureTotalArgsNum) (getF ClosureArgsNum) in sub (getF ClosureTotalArgsNum) (getF ClosureArgsNum)
Tree.OpIntToField -> fieldErr Tree.OpIntToField -> fieldErr
@ -651,6 +655,7 @@ compile = \case
enabled <- asks (^. compilerOptions . compilerOptionsEnableTrace) enabled <- asks (^. compilerOptions . compilerOptionsEnableTrace)
return $ return $
if if
-- TODO: remove duplication of `arg` here
| enabled -> OpTrace # arg # arg | enabled -> OpTrace # arg # arg
| otherwise -> arg | otherwise -> arg

View File

@ -53,6 +53,7 @@ overValueRefs'' f = \case
If x -> If <$> goIf x If x -> If <$> goIf x
Branch x -> Branch <$> goBranch x Branch x -> Branch <$> goBranch x
Case x -> Case <$> goCase x Case x -> Case <$> goCase x
Assert x -> Assert <$> goAssert x
Trace x -> Trace <$> goTrace x Trace x -> Trace <$> goTrace x
Dump -> return Dump Dump -> return Dump
Failure x -> Failure <$> goFailure x Failure x -> Failure <$> goFailure x
@ -174,6 +175,9 @@ overValueRefs'' f = \case
goCase :: InstrCase -> m InstrCase goCase :: InstrCase -> m InstrCase
goCase = overM instrCaseValue goValue goCase = overM instrCaseValue goValue
goAssert :: InstrAssert -> m InstrAssert
goAssert = overM instrAssertValue goValue
goTrace :: InstrTrace -> m InstrTrace goTrace :: InstrTrace -> m InstrTrace
goTrace = overM instrTraceValue goValue goTrace = overM instrTraceValue goValue

View File

@ -79,6 +79,7 @@ getValueRefs = \case
Assign x -> goAssign x Assign x -> goAssign x
Alloc x -> goAlloc x Alloc x -> goAlloc x
AllocClosure x -> goAllocClosure x AllocClosure x -> goAllocClosure x
Assert x -> goAssert x
Trace x -> goTrace x Trace x -> goTrace x
Dump -> [] Dump -> []
Failure x -> goFailure x Failure x -> goFailure x
@ -103,6 +104,9 @@ getValueRefs = \case
goAllocClosure :: InstrAllocClosure -> [VarRef] goAllocClosure :: InstrAllocClosure -> [VarRef]
goAllocClosure InstrAllocClosure {..} = concatMap getValueRefs'' _instrAllocClosureArgs goAllocClosure InstrAllocClosure {..} = concatMap getValueRefs'' _instrAllocClosureArgs
goAssert :: InstrAssert -> [VarRef]
goAssert InstrAssert {..} = getValueRefs'' _instrAssertValue
goTrace :: InstrTrace -> [VarRef] goTrace :: InstrTrace -> [VarRef]
goTrace InstrTrace {..} = getValueRefs'' _instrTraceValue goTrace InstrTrace {..} = getValueRefs'' _instrTraceValue

View File

@ -21,6 +21,7 @@ computeMaxStackHeight lims = maximum . map go
Unop {} -> 0 Unop {} -> 0
Cairo {} -> 0 Cairo {} -> 0
Assign {} -> 0 Assign {} -> 0
Assert {} -> 0
Trace {} -> 0 Trace {} -> 0
Dump -> 0 Dump -> 0
Failure {} -> 0 Failure {} -> 0
@ -73,6 +74,7 @@ computeMaxCallClosuresArgsNum = maximum . map go
Unop {} -> 0 Unop {} -> 0
Cairo {} -> 0 Cairo {} -> 0
Assign {} -> 0 Assign {} -> 0
Assert {} -> 0
Trace {} -> 0 Trace {} -> 0
Dump -> 0 Dump -> 0
Failure {} -> 0 Failure {} -> 0
@ -121,6 +123,8 @@ computeStringMap strs = snd . run . execState (HashMap.size strs, strs) . mapM g
mapM_ goVal _instrCairoArgs mapM_ goVal _instrCairoArgs
Assign InstrAssign {..} -> Assign InstrAssign {..} ->
goVal _instrAssignValue goVal _instrAssignValue
Assert InstrAssert {..} ->
goVal _instrAssertValue
Trace InstrTrace {..} -> Trace InstrTrace {..} ->
goVal _instrTraceValue goVal _instrTraceValue
Dump -> return () Dump -> return ()
@ -180,6 +184,7 @@ computeLocalVarsNum = maximum . map go
Unop InstrUnop {..} -> goVarRef _instrUnopResult Unop InstrUnop {..} -> goVarRef _instrUnopResult
Cairo InstrCairo {..} -> goVarRef _instrCairoResult Cairo InstrCairo {..} -> goVarRef _instrCairoResult
Assign InstrAssign {..} -> goVarRef _instrAssignResult Assign InstrAssign {..} -> goVarRef _instrAssignResult
Assert {} -> 0
Trace {} -> 0 Trace {} -> 0
Dump -> 0 Dump -> 0
Failure {} -> 0 Failure {} -> 0

View File

@ -48,6 +48,7 @@ runFunction hout infoTable args0 info0 = do
Unop x -> goUnop args tmps instrs x Unop x -> goUnop args tmps instrs x
Cairo {} -> throwRunError "unsupported: Cairo builtin" Nothing Cairo {} -> throwRunError "unsupported: Cairo builtin" Nothing
Assign x -> goAssign args tmps instrs x Assign x -> goAssign args tmps instrs x
Assert x -> goAssert args tmps instrs x
Trace x -> goTrace args tmps instrs x Trace x -> goTrace args tmps instrs x
Dump -> goDump args tmps instrs Dump -> goDump args tmps instrs
Failure x -> goFailure args tmps instrs x Failure x -> goFailure args tmps instrs x
@ -130,6 +131,15 @@ runFunction hout infoTable args0 info0 = do
writeVarRef args tmps _instrAssignResult val writeVarRef args tmps _instrAssignResult val
go args tmps instrs go args tmps instrs
goAssert :: Args -> Vars s -> Code -> InstrAssert -> ST s Val
goAssert args tmps instrs InstrAssert {..} = do
val <- readValue args tmps _instrAssertValue
case val of
ValBool True ->
go args tmps instrs
_ ->
throwRunError "assertion failed" Nothing
goTrace :: Args -> Vars s -> Code -> InstrTrace -> ST s Val goTrace :: Args -> Vars s -> Code -> InstrTrace -> ST s Val
goTrace args tmps instrs InstrTrace {..} = do goTrace args tmps instrs InstrTrace {..} = do
val <- readValue args tmps _instrTraceValue val <- readValue args tmps _instrTraceValue

View File

@ -10,6 +10,7 @@ import Juvix.Data.Keyword.All
( kwAdd_, ( kwAdd_,
kwAlloc, kwAlloc,
kwArgsNum, kwArgsNum,
kwAssert,
kwAtoi, kwAtoi,
kwBr, kwBr,
kwCAlloc, kwCAlloc,
@ -74,6 +75,7 @@ allKeywords =
kwIf, kwIf,
kwShow, kwShow,
kwAtoi, kwAtoi,
kwAssert,
kwTrace, kwTrace,
kwDump, kwDump,
kwPrealloc, kwPrealloc,

View File

@ -25,7 +25,8 @@ data Instruction
| Branch InstrBranch | Branch InstrBranch
| Case InstrCase | Case InstrCase
| ---- | ----
Trace InstrTrace Assert InstrAssert
| Trace InstrTrace
| Dump | Dump
| Failure InstrFailure | Failure InstrFailure
| Prealloc InstrPrealloc | Prealloc InstrPrealloc

View File

@ -20,6 +20,7 @@ data Instruction
| Assign InstrAssign | Assign InstrAssign
| Alloc InstrAlloc | Alloc InstrAlloc
| AllocClosure InstrAllocClosure | AllocClosure InstrAllocClosure
| Assert InstrAssert
| Trace InstrTrace | Trace InstrTrace
| Dump | Dump
| Failure InstrFailure | Failure InstrFailure

View File

@ -80,6 +80,11 @@ data InstrAssign = InstrAssign
} }
deriving stock (Eq) deriving stock (Eq)
newtype InstrAssert = InstrAssert
{ _instrAssertValue :: Value
}
deriving stock (Eq)
newtype InstrTrace = InstrTrace newtype InstrTrace = InstrTrace
{ _instrTraceValue :: Value { _instrTraceValue :: Value
} }
@ -184,6 +189,7 @@ makeLenses ''InstrBinop
makeLenses ''InstrUnop makeLenses ''InstrUnop
makeLenses ''InstrCairo makeLenses ''InstrCairo
makeLenses ''InstrAssign makeLenses ''InstrAssign
makeLenses ''InstrAssert
makeLenses ''InstrTrace makeLenses ''InstrTrace
makeLenses ''InstrFailure makeLenses ''InstrFailure
makeLenses ''InstrAlloc makeLenses ''InstrAlloc

View File

@ -75,6 +75,11 @@ instance PrettyCode InstrAssign where
val <- ppCode _instrAssignValue val <- ppCode _instrAssignValue
return $ res <+> primitive Str.equal <+> val return $ res <+> primitive Str.equal <+> val
instance PrettyCode InstrAssert where
ppCode InstrAssert {..} = do
val <- ppCode _instrAssertValue
return $ primitive Str.assert_ <+> val
instance PrettyCode InstrTrace where instance PrettyCode InstrTrace where
ppCode InstrTrace {..} = do ppCode InstrTrace {..} = do
val <- ppCode _instrTraceValue val <- ppCode _instrTraceValue
@ -271,6 +276,7 @@ instance PrettyCode Instruction where
Unop x -> ppCode x Unop x -> ppCode x
Cairo x -> ppCode x Cairo x -> ppCode x
Assign x -> ppCode x Assign x -> ppCode x
Assert x -> ppCode x
Trace x -> ppCode x Trace x -> ppCode x
Dump -> return $ primitive Str.dump Dump -> return $ primitive Str.dump
Failure x -> ppCode x Failure x -> ppCode x

View File

@ -30,6 +30,7 @@ fromReg = over infoFunctions (fmap (over functionCode goCode))
Reg.Case x -> mkBlock (Case (fmap goCode x)) Reg.Case x -> mkBlock (Case (fmap goCode x))
Reg.CallClosures {} -> impossible Reg.CallClosures {} -> impossible
Reg.TailCallClosures {} -> impossible Reg.TailCallClosures {} -> impossible
Reg.Assert x -> over blockBody (Assert x :) (goCode is)
Reg.Trace x -> over blockBody (Trace x :) (goCode is) Reg.Trace x -> over blockBody (Trace x :) (goCode is)
Reg.Dump -> over blockBody (Dump :) (goCode is) Reg.Dump -> over blockBody (Dump :) (goCode is)
Reg.Failure x -> over blockBody (Failure x :) (goCode is) Reg.Failure x -> over blockBody (Failure x :) (goCode is)

View File

@ -69,6 +69,7 @@ fromAsmInstr funInfo tab si Asm.CmdInstr {..} =
Asm.Cairo op -> return $ mkCairo op Asm.Cairo op -> return $ mkCairo op
Asm.Push val -> return $ mkAssign (mkVarRef VarGroupLocal (ntmps + n + 1)) (mkValue val) Asm.Push val -> return $ mkAssign (mkVarRef VarGroupLocal (ntmps + n + 1)) (mkValue val)
Asm.Pop -> return Nop Asm.Pop -> return Nop
Asm.Assert -> return $ Assert $ InstrAssert (VRef $ mkVarRef VarGroupLocal (ntmps + n))
Asm.Trace -> return $ Trace $ InstrTrace (VRef $ mkVarRef VarGroupLocal (ntmps + n)) Asm.Trace -> return $ Trace $ InstrTrace (VRef $ mkVarRef VarGroupLocal (ntmps + n))
Asm.Dump -> return Dump Asm.Dump -> return Dump
Asm.Failure -> return $ Failure $ InstrFailure (VRef $ mkVarRef VarGroupLocal (ntmps + n)) Asm.Failure -> return $ Failure $ InstrFailure (VRef $ mkVarRef VarGroupLocal (ntmps + n))

View File

@ -53,6 +53,7 @@ instruction ::
ParsecS r Instruction ParsecS r Instruction
instruction = instruction =
(instrNop >> return Nop) (instrNop >> return Nop)
<|> (Assert <$> instrAssert)
<|> (Trace <$> instrTrace) <|> (Trace <$> instrTrace)
<|> (instrDump >> return Dump) <|> (instrDump >> return Dump)
<|> (Failure <$> instrFailure) <|> (Failure <$> instrFailure)
@ -195,6 +196,17 @@ instrTrace = do
{ _instrTraceValue = val { _instrTraceValue = val
} }
instrAssert ::
(Members '[Reader ParserSig, InfoTableBuilder, State LocalParams] r) =>
ParsecS r InstrAssert
instrAssert = do
kw kwAssert
val <- value
return
InstrAssert
{ _instrAssertValue = val
}
instrDump :: ParsecS r () instrDump :: ParsecS r ()
instrDump = kw kwDump instrDump = kw kwDump

View File

@ -75,6 +75,7 @@ hEval hout tab = eval' [] mempty
let !v = eval' args temps _nodeUnopArg let !v = eval' args temps _nodeUnopArg
in case _nodeUnopOpcode of in case _nodeUnopOpcode of
PrimUnop op -> eitherToError $ evalUnop tab op v PrimUnop op -> eitherToError $ evalUnop tab op v
OpAssert -> goAssert v
OpTrace -> goTrace v OpTrace -> goTrace v
OpFail -> goFail v OpFail -> goFail v
@ -105,6 +106,11 @@ hEval hout tab = eval' [] mempty
_ -> evalError "expected either a nullary or a binary constructor" _ -> evalError "expected either a nullary or a binary constructor"
_ -> evalError "expected a constructor" _ -> evalError "expected a constructor"
goAssert :: Value -> Value
goAssert = \case
ValBool True -> ValBool True
_ -> evalError "assertion failed"
goFail :: Value -> Value goFail :: Value -> Value
goFail v = evalError ("failure: " <> printValue tab v) goFail v = evalError ("failure: " <> printValue tab v)

View File

@ -70,6 +70,7 @@ eval tab = runReader emptyEvalCtx . eval'
v <- eval' _nodeUnopArg v <- eval' _nodeUnopArg
case _nodeUnopOpcode of case _nodeUnopOpcode of
PrimUnop op -> eitherToError $ evalUnop tab op v PrimUnop op -> eitherToError $ evalUnop tab op v
OpAssert -> goAssert v
OpTrace -> goTrace v OpTrace -> goTrace v
OpFail -> goFail v OpFail -> goFail v
@ -100,6 +101,12 @@ eval tab = runReader emptyEvalCtx . eval'
_ -> evalError "expected either a nullary or a binary constructor" _ -> evalError "expected either a nullary or a binary constructor"
_ -> evalError "expected a constructor" _ -> evalError "expected a constructor"
goAssert :: Value -> Sem r' Value
goAssert = \case
ValBool True -> return $ ValBool True
ValBool False -> evalError "assertion failed"
v -> evalError ("expected a boolean: " <> printValue tab v)
goFail :: Value -> Sem r' Value goFail :: Value -> Sem r' Value
goFail v = evalError ("failure: " <> printValue tab v) goFail v = evalError ("failure: " <> printValue tab v)

View File

@ -17,6 +17,7 @@ import Juvix.Data.Keyword.All
kwAnomaVerifyDetached, kwAnomaVerifyDetached,
kwAnomaVerifyWithMessage, kwAnomaVerifyWithMessage,
kwArgsNum, kwArgsNum,
kwAssert,
kwAtoi, kwAtoi,
kwBr, kwBr,
kwByteArrayFromListUInt8, kwByteArrayFromListUInt8,
@ -70,6 +71,7 @@ allKeywords =
kwStrcat, kwStrcat,
kwShow, kwShow,
kwAtoi, kwAtoi,
kwAssert,
kwTrace, kwTrace,
kwFail, kwFail,
kwArgsNum, kwArgsNum,

View File

@ -65,6 +65,8 @@ data BinaryOpcode
data UnaryOpcode data UnaryOpcode
= PrimUnop UnaryOp = PrimUnop UnaryOp
| -- | Assert a boolean and return it
OpAssert
| -- | Print a debug log of the argument and return it. | -- | Print a debug log of the argument and return it.
OpTrace OpTrace
| -- | Interrupt execution with a runtime error printing the argument. | -- | Interrupt execution with a runtime error printing the argument.

View File

@ -297,6 +297,7 @@ instance PrettyCode AnomaOp where
instance PrettyCode UnaryOpcode where instance PrettyCode UnaryOpcode where
ppCode = \case ppCode = \case
PrimUnop x -> ppCode x PrimUnop x -> ppCode x
OpAssert -> return $ primitive Str.instrAssert
OpTrace -> return $ primitive Str.instrTrace OpTrace -> return $ primitive Str.instrTrace
OpFail -> return $ primitive Str.instrFailure OpFail -> return $ primitive Str.instrFailure

View File

@ -65,6 +65,7 @@ inferType tab funInfo = goInfer mempty
goUnop :: BinderList Type -> NodeUnop -> Sem r Type goUnop :: BinderList Type -> NodeUnop -> Sem r Type
goUnop bl NodeUnop {..} = case _nodeUnopOpcode of goUnop bl NodeUnop {..} = case _nodeUnopOpcode of
PrimUnop x -> checkPrimUnop x PrimUnop x -> checkPrimUnop x
OpAssert -> goInfer bl _nodeUnopArg
OpTrace -> goInfer bl _nodeUnopArg OpTrace -> goInfer bl _nodeUnopArg
OpFail -> checkUnop TyDynamic TyDynamic OpFail -> checkUnop TyDynamic TyDynamic
where where

View File

@ -92,6 +92,7 @@ goFunction infoTab fi = do
Asm.Push (Asm.Constant c) -> return (mkConst c) Asm.Push (Asm.Constant c) -> return (mkConst c)
Asm.Push (Asm.Ref r) -> return (mkMemRef r) Asm.Push (Asm.Ref r) -> return (mkMemRef r)
Asm.Pop -> goPop Asm.Pop -> goPop
Asm.Assert -> goAssert
Asm.Trace -> goTrace Asm.Trace -> goTrace
Asm.Dump -> unsupported (_cmdInstrInfo ^. Asm.commandInfoLocation) Asm.Dump -> unsupported (_cmdInstrInfo ^. Asm.commandInfoLocation)
Asm.Failure -> goUnop OpFail Asm.Failure -> goUnop OpFail
@ -244,8 +245,8 @@ goFunction infoTab fi = do
_nodeBinopArg2 = arg2 _nodeBinopArg2 = arg2
} }
goTrace :: Sem r Node goSeqOp :: UnaryOpcode -> Sem r Node
goTrace = do goSeqOp op = do
arg <- goCode arg <- goCode
off <- asks (^. tempSize) off <- asks (^. tempSize)
let ref = mkMemRef $ DRef $ mkTempRef $ OffsetRef off Nothing let ref = mkMemRef $ DRef $ mkTempRef $ OffsetRef off Nothing
@ -264,13 +265,19 @@ goFunction infoTab fi = do
Unop Unop
NodeUnop NodeUnop
{ _nodeUnopInfo = mempty, { _nodeUnopInfo = mempty,
_nodeUnopOpcode = OpTrace, _nodeUnopOpcode = op,
_nodeUnopArg = ref _nodeUnopArg = ref
}, },
_nodeBinopArg2 = ref _nodeBinopArg2 = ref
} }
} }
goAssert :: Sem r Node
goAssert = goSeqOp OpAssert
goTrace :: Sem r Node
goTrace = goSeqOp OpTrace
goArgs :: Int -> Sem r [Node] goArgs :: Int -> Sem r [Node]
goArgs n = mapM (const goCode) [1 .. n] goArgs n = mapM (const goCode) [1 .. n]

View File

@ -163,6 +163,16 @@ genCode infoTable fi =
_nodeAnomaOpcode = genAnomaOp _builtinAppOp, _nodeAnomaOpcode = genAnomaOp _builtinAppOp,
_nodeAnomaArgs = args _nodeAnomaArgs = args
} }
| _builtinAppOp == Core.OpAssert =
case args of
[arg] ->
Unop $
NodeUnop
{ _nodeUnopInfo = mempty,
_nodeUnopOpcode = OpAssert,
_nodeUnopArg = arg
}
_ -> impossible
| otherwise = | otherwise =
case args of case args of
[arg] -> [arg] ->

View File

@ -106,6 +106,7 @@ parseUnop ::
parseUnop = parseUnop =
parseUnaryOp kwShow (PrimUnop OpShow) parseUnaryOp kwShow (PrimUnop OpShow)
<|> parseUnaryOp kwAtoi (PrimUnop OpStrToInt) <|> parseUnaryOp kwAtoi (PrimUnop OpStrToInt)
<|> parseUnaryOp kwAssert OpAssert
<|> parseUnaryOp kwTrace OpTrace <|> parseUnaryOp kwTrace OpTrace
<|> parseUnaryOp kwFail OpFail <|> parseUnaryOp kwFail OpFail
<|> parseUnaryOp kwArgsNum (PrimUnop OpArgsNum) <|> parseUnaryOp kwArgsNum (PrimUnop OpArgsNum)

View File

@ -265,6 +265,9 @@ kwSeqq = asciiKw Str.seqq_
kwSSeq :: Keyword kwSSeq :: Keyword
kwSSeq = asciiKw Str.sseq_ kwSSeq = asciiKw Str.sseq_
kwAssert :: Keyword
kwAssert = asciiKw Str.assert_
kwTrace :: Keyword kwTrace :: Keyword
kwTrace = asciiKw Str.trace_ kwTrace = asciiKw Str.trace_

View File

@ -260,6 +260,9 @@ ioSequence = "IO-sequence"
ioReadline :: (IsString s) => s ioReadline :: (IsString s) => s
ioReadline = "IO-readline" ioReadline = "IO-readline"
assert :: (IsString s) => s
assert = "assert"
natPrint :: (IsString s) => s natPrint :: (IsString s) => s
natPrint = "nat-print" natPrint = "nat-print"
@ -482,6 +485,9 @@ sseq_ = "seq"
eq :: (IsString s) => s eq :: (IsString s) => s
eq = "eq" eq = "eq"
assert_ :: (IsString s) => s
assert_ = "assert"
trace_ :: (IsString s) => s trace_ :: (IsString s) => s
trace_ = "trace" trace_ = "trace"
@ -845,6 +851,9 @@ instrPusht = "pusht"
instrPopt :: (IsString s) => s instrPopt :: (IsString s) => s
instrPopt = "popt" instrPopt = "popt"
instrAssert :: (IsString s) => s
instrAssert = "assert"
instrTrace :: (IsString s) => s instrTrace :: (IsString s) => s
instrTrace = "trace" instrTrace = "trace"

View File

@ -557,5 +557,13 @@ tests =
$(mkRelDir ".") $(mkRelDir ".")
$(mkRelFile "test077.juvix") $(mkRelFile "test077.juvix")
(Just $(mkRelFile "in/test077.json")) (Just $(mkRelFile "in/test077.json"))
$(mkRelFile "out/test077.out") $(mkRelFile "out/test077.out"),
posTest
"Test078: Assertions"
True
True
$(mkRelDir ".")
$(mkRelFile "test078.juvix")
Nothing
$(mkRelFile "out/test078.out")
] ]

View File

@ -178,5 +178,13 @@ tests =
$(mkRelDir ".") $(mkRelDir ".")
$(mkRelFile "test017.casm") $(mkRelFile "test017.casm")
$(mkRelFile "out/test017.out") $(mkRelFile "out/test017.out")
Nothing,
PosTest
"Test018: Assertions"
True
True
$(mkRelDir ".")
$(mkRelFile "test018.casm")
$(mkRelFile "out/test018.out")
Nothing Nothing
] ]

View File

@ -0,0 +1 @@
482630520

View File

@ -40,11 +40,3 @@ main
| else := Resource.fld0 input; | else := Resource.fld0 input;
y := Resource.fld1 input y := Resource.fld1 input
}; };
{-
main
(input : Resource)
(path : List (Pair Field Bool))
: Field :=
count path;
-}

View File

@ -0,0 +1,11 @@
module test078;
import Stdlib.Prelude open;
fact' (acc : Nat) : Nat → Nat
| zero := acc
| (suc x) := assert (acc /= 0) >-> fact' (acc * suc x) x;
fact : Nat → Nat := fact' 1;
main : Nat := assert (fact 10 == 10 * fact 9) >-> fact 5 + fact 10 + fact 12;

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,13 @@
-- assertions
start:
[ap] = 10
[ap + 1] = 1
ap += 2
loop:
[ap] = [ap - 2] - 1
[ap + 1] = [ap - 1] * [ap - 2]
ap += 2
jmp loop if [ap - 2] != 0
[ap] = [ap - 1] - 3628800; ap++
assert [ap - 1]