Skip to content

Commit

Permalink
Make missing storage key an evaluation error
Browse files Browse the repository at this point in the history
  • Loading branch information
paulcadman committed Mar 3, 2024
1 parent 2f93c67 commit 08ecfe3
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/Juvix/Compiler/Nockma/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -326,5 +326,5 @@ eval inistack initerm =
goOpScry = do
Cell' typeFormula subFormula _ <- withCrumb (crumb crumbDecodeFirst) (asCell (c ^. operatorCellTerm))
void (evalArg crumbEvalFirst stack typeFormula)
subResult <- evalArg crumbEvalSecond stack subFormula
HashMap.lookupDefault impossible subResult <$> asks (^. storageKeyValueData)
key <- evalArg crumbEvalSecond stack subFormula
fromMaybeM (throwKeyNotInStorage key) (HashMap.lookup key <$> asks (^. storageKeyValueData))
33 changes: 33 additions & 0 deletions src/Juvix/Compiler/Nockma/Evaluator/Error.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
module Juvix.Compiler.Nockma.Evaluator.Error
( module Juvix.Compiler.Nockma.Evaluator.Error,
module Juvix.Compiler.Nockma.Evaluator.Crumbs,
module Juvix.Compiler.Nockma.Evaluator.Storage,
)
where

import Data.HashMap.Strict qualified as HashMap
import Juvix.Compiler.Nockma.Evaluator.Crumbs
import Juvix.Compiler.Nockma.Evaluator.Storage
import Juvix.Compiler.Nockma.Language
import Juvix.Compiler.Nockma.Pretty.Base
import Juvix.Prelude hiding (Atom, Path)
Expand All @@ -17,6 +20,7 @@ data NockEvalError a
ErrNoStack NoStack
| -- TODO perhaps this should be a repl error type
ErrAssignmentNotFound Text
| ErrKeyNotInStorage (KeyNotInStorage a)

newtype GenericNockEvalError = GenericNockEvalError
{ _genericNockEvalErrorMessage :: AnsiText
Expand All @@ -41,6 +45,11 @@ data InvalidPath a = InvalidPath
_invalidPathPath :: Path
}

data KeyNotInStorage a = KeyNotInStorage
{ _keyNotInStorageKey :: Term a,
_keyNotInStorageStorage :: Storage a
}

data NoStack = NoStack

throwInvalidPath :: (Members '[Error (NockEvalError a), Reader EvalCtx] r) => Term a -> Path -> Sem r x
Expand Down Expand Up @@ -74,6 +83,16 @@ throwExpectedAtom a = do
_expectedAtomCell = a
}

throwKeyNotInStorage :: (Members '[Reader (Storage a), Error (NockEvalError a)] r) => Term a -> Sem r x
throwKeyNotInStorage k = do
s <- ask
throw $
ErrKeyNotInStorage
KeyNotInStorage
{ _keyNotInStorageKey = k,
_keyNotInStorageStorage = s
}

instance PrettyCode NoStack where
ppCode _ = return "Missing stack"

Expand All @@ -98,10 +117,24 @@ instance (PrettyCode a, NockNatural a) => PrettyCode (ExpectedCell a) where
let cell = annotate AnnImportant "cell"
return (ctx <> "Expected a" <+> cell <+> "but got:" <> line <> atm)

instance (PrettyCode a, NockNatural a) => PrettyCode (KeyNotInStorage a) where
ppCode :: forall r. (Member (Reader Options) r) => KeyNotInStorage a -> Sem r (Doc Ann)
ppCode KeyNotInStorage {..} = do
tm <- ppCode _keyNotInStorageKey
hashMapKvs <- vsep <$> (mapM combineKeyValue (HashMap.toList (_keyNotInStorageStorage ^. storageKeyValueData)))
return ("The key" <+> tm <+> "is not found in the storage." <> line <> "Storage contains the following key value pairs:" <> line <> hashMapKvs)
where
combineKeyValue :: (Term a, Term a) -> Sem r (Doc Ann)
combineKeyValue (t1, t2) = do
pt1 <- ppCode t1
pt2 <- ppCode t2
return (pt1 <+> ":=" <+> pt2)

instance (PrettyCode a, NockNatural a) => PrettyCode (NockEvalError a) where
ppCode = \case
ErrInvalidPath e -> ppCode e
ErrExpectedAtom e -> ppCode e
ErrExpectedCell e -> ppCode e
ErrNoStack e -> ppCode e
ErrAssignmentNotFound e -> return (pretty e)
ErrKeyNotInStorage e -> ppCode e
1 change: 1 addition & 0 deletions test/Anoma/Compilation/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mkAnomaCallTest' enableDebug _testName relRoot mainFile args _testCheck =
let _testProgramFormula = anomaCall args
_testEvalOptions = defaultEvalOptions
_testProgramStorage :: Storage Natural = emptyStorage
_testAssertEvalError :: Maybe (NockEvalError Natural -> Assertion) = Nothing
return Test {..}

withRootCopy :: (Prelude.Path Abs Dir -> IO a) -> IO a
Expand Down
28 changes: 23 additions & 5 deletions test/Nockma/Eval/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Check = Sem '[Reader [Term Natural], Reader (Term Natural), EmbedIO]

data Test = Test
{ _testEvalOptions :: EvalOptions,
_testAssertEvalError :: Maybe (NockEvalError Natural -> Assertion),
_testProgramStorage :: Storage Natural,
_testName :: Text,
_testProgramSubject :: Term Natural,
Expand All @@ -36,9 +37,13 @@ mkNockmaAssertion Test {..} = do

case evalResult of
Left natErr -> assertFailure ("Evaluation error: " <> show natErr)
Right r -> case r of
Left evalErr -> assertFailure ("Evaluation error: " <> unpack (ppTrace evalErr))
Right res -> runM (runReader res (runReader traces _testCheck))
Right r -> case _testAssertEvalError of
Nothing -> case r of
Left evalErr -> assertFailure ("Evaluation error: " <> unpack (ppTrace evalErr))
Right res -> runM (runReader res (runReader traces _testCheck))
Just checkErrFn -> case r of
Left evalErr -> checkErrFn evalErr
Right {} -> assertFailure "expected error"

allTests :: TestTree
allTests =
Expand Down Expand Up @@ -95,8 +100,19 @@ compilerTest n mainFun _testCheck _evalInterceptStdlibCalls =
Cell _testProgramSubject _testProgramFormula = runCompilerWithJuvix opts mempty [] f
_testEvalOptions = EvalOptions {..}
_testProgramStorage :: Storage Natural = emptyStorage
_testAssertEvalError :: Maybe (NockEvalError Natural -> Assertion) = Nothing
in Test {..}

withAssertErrKeyNotInStorage :: Test -> Test
withAssertErrKeyNotInStorage Test {..} =
let _testAssertEvalError :: Maybe (NockEvalError Natural -> Assertion) = Just f
in Test {..}
where
f :: NockEvalError Natural -> Assertion
f = \case
ErrKeyNotInStorage {} -> return ()
_ -> assertFailure "Expected ErrKeyNotInStorage error"

anomaTest :: Text -> Term Natural -> [Term Natural] -> Check () -> Bool -> Test
anomaTest n mainFun args _testCheck _evalInterceptStdlibCalls =
let f =
Expand All @@ -116,10 +132,11 @@ anomaTest n mainFun args _testCheck _evalInterceptStdlibCalls =
_testProgramFormula = anomaCall args
_testProgramStorage :: Storage Natural = emptyStorage
_testEvalOptions = EvalOptions {..}
_testAssertEvalError :: Maybe (NockEvalError Natural -> Assertion) = Nothing
in Test {..}

testWithStorage :: [(Term Natural, Term Natural)] -> Text -> Term Natural -> Term Natural -> Check () -> Test
testWithStorage s = Test defaultEvalOptions (Storage (HashMap.fromList s))
testWithStorage s = Test defaultEvalOptions Nothing (Storage (HashMap.fromList s))

test :: Text -> Term Natural -> Term Natural -> Check () -> Test
test = testWithStorage []
Expand Down Expand Up @@ -167,5 +184,6 @@ unitTests =
test "call" [nock| [quote 1] |] [nock| [call [S [@ S]]] |] (eqNock [nock| 1 |]),
test "replace" [nock| [0 1] |] [nock| [replace [[L [quote 1]] [@ S]]] |] (eqNock [nock| [1 1] |]),
test "hint" [nock| [0 1] |] [nock| [hint [nil [trace [quote 2] [quote 3]]] [quote 1]] |] (eqTraces [[nock| 2 |]] >> eqNock [nock| 1 |]),
testWithStorage [([nock| 111 |], [nock| 222 |])] "scry" [nock| nil |] [nock| [scry [quote nil] [quote 111]] |] (eqNock [nock| 222 |])
testWithStorage [([nock| 111 |], [nock| 222 |])] "scry" [nock| nil |] [nock| [scry [quote nil] [quote 111]] |] (eqNock [nock| 222 |]),
withAssertErrKeyNotInStorage $ testWithStorage [([nock| 333 |], [nock| 222 |]), ([nock| 3 |], [nock| 222 |])] "scry" [nock| nil |] [nock| [scry [quote nil] [quote 111]] |] (eqNock [nock| 222 |])
]

0 comments on commit 08ecfe3

Please sign in to comment.