Runtime contract guard kernel

This commit is contained in:
2026-09-01 14:13:42 -05:00
parent b822e7e713
commit d54ad558a8
7 changed files with 454 additions and 79 deletions

View File

@@ -39,10 +39,10 @@ snd p = matchPair takeSecond p
where takeSecond a b = b
resultIsOk result =
matchResult (err rest : false) (val rest : true) result
matchResult (errR rest : false) (val rest : true) result
resultIsErr result =
matchResult (err rest : true) (val rest : false) result
matchResult (errR rest : true) (val rest : false) result
not? = matchBool false true
and? = matchBool id (_ : false)
@@ -638,25 +638,52 @@ zipWith = f xs ys : y zipWith_ f xs ys
-- The second argument is the conventional "rest" slot. On success a contract
-- returns the checked value wrapped in the standard ok shape; on failure it
-- returns a diagnostic wrapped in the standard err shape.
--
-- The contract kernel is a globally configurable function selected by the
-- runner. It decides whether to accept the contract result, replace it, log
-- it, or transform the diagnostic. The default kernel is the identity on the
-- contract Result.
--
-- The runner may rebind 'kernel' to a different kernel before evaluating
-- user code (e.g. via --contract-kernel).
-- ---------------------------------------------------------------------------
contractOk = (value : (rest : ok value rest))
contractErr = (msg : (rest : err msg rest))
check contract value =
withContract contract value
(x : x)
(msg : msg)
-- Apply a contract with the conventional rest slot and return the raw Result.
checkContract = (contract value : contract value t)
-- Apply a contract and continue with either the onOk or onFail branch.
withContract = (contract value onOk onFail :
-- Default contract kernel. Return the contract Result unchanged.
defaultKernel = (contract value result :
matchResult
(msg _ : onFail msg)
(checked _ : onOk checked)
(contract value t))
(msg rest : err msg rest)
(v rest : ok v rest)
result)
-- The active kernel. The runner may rebind this name to a different kernel
-- before evaluating user code (e.g. via --contract-kernel). Internally,
-- withContract dispatches through this binding, so rebinding 'kernel' changes
-- the behaviour of every contract boundary in the program.
kernel = defaultKernel
-- Skip-everything kernel. Resume with the original value on failure.
skipKernel = (contract value result :
matchResult
(msg rest : ok value rest)
(v rest : ok v rest)
result)
-- Apply a contract and pass the raw Result to the kernel.
withContract = (contract value :
kernel contract value (contract value t))
-- Apply a contract and return the checked value or the diagnostic message.
check contract value =
matchResult
(msg _ : msg)
(v _ : v)
(withContract contract value)
-- Apply a contract and return the raw Result (kernel is bypassed).
checkContract = (contract value : contract value t)
-- ---------------------------------------------------------------------------
-- Basic contracts
@@ -774,29 +801,34 @@ pairOf = (c1 c2 p rest :
fnContract = (argC resC f rest :
contractOk
(x : (rest1 :
withContract argC x
(x' :
withContract resC (f x')
(y : contractOk y rest1)
(msg : contractErr msg rest1))
(msg : contractErr msg rest1)))
matchResult
(msg _ : contractErr msg rest1)
(x' _ :
matchResult
(msg _ : contractErr msg rest1)
(y _ : contractOk y rest1)
(withContract resC (f x')))
(withContract argC x)))
rest)
fn2 = (arg1C arg2C resC f rest :
contractOk
(x : (rest1 :
withContract arg1C x
(x' :
matchResult
(msg _ : contractErr msg rest1)
(x' _ :
contractOk
(y : (rest2 :
withContract arg2C y
(y' :
withContract resC (f x' y')
(z : contractOk z rest2)
(msg : contractErr msg rest2))
(msg : contractErr msg rest2)))
matchResult
(msg _ : contractErr msg rest2)
(y' _ :
matchResult
(msg _ : contractErr msg rest2)
(z _ : contractOk z rest2)
(withContract resC (f x' y')))
(withContract arg2C y)))
rest1)
(msg : contractErr msg rest1)))
(withContract arg1C x)))
rest)
-- ---------------------------------------------------------------------------