1
1
mirror of https://github.com/github/semantic.git synced 2024-12-20 21:31:48 +03:00

Handle LoopControl local to Evaluatable.

This commit is contained in:
Rob Rix 2018-05-06 14:12:41 -04:00
parent 8b679d0f80
commit 848543010d
3 changed files with 10 additions and 16 deletions

View File

@ -27,8 +27,7 @@ deriving instance (Show (Cell location value), Show location, Show term, Show va
-- | Effects necessary for evaluating (whether concrete or abstract).
type EvaluatingEffects location term value
= '[ LoopControl value
, Fail -- Failure with an error message
= '[ Fail -- Failure with an error message
, Fresh -- For allocating new addresses and/or type variables.
, Reader (Environment location value) -- Default environment used as a fallback in lookupEnv
, State (Environment location value)
@ -39,7 +38,7 @@ type EvaluatingEffects location term value
]
evaluating :: Show value => Evaluator location term value (EvaluatingEffects location term value) result -> (Either String result, EvaluatingState location term value)
evaluating :: Evaluator location term value (EvaluatingEffects location term value) result -> (Either String result, EvaluatingState location term value)
evaluating
= (\ (((((result, env), heap), modules), exports), jumps) -> (result, EvaluatingState env heap modules exports jumps))
. Eff.run
@ -52,10 +51,4 @@ evaluating
. handleReader lowerBound -- Reader (Environment location value)
. raiseHandler
( flip runFresh' 0
. runFail
-- NB: We should never have a 'Return', 'Break', or 'Continue' at this point in execution; the scope being returned from/broken from/continued should have intercepted the effect. This handler will therefore only be invoked if we issue a 'Return', 'Break', or 'Continue' outside of such a scope, and unfortunately if this happens it will handle it by resuming the scope being returned from. While it would be _slightly_ more correct to instead exit with the value being returned, we arent able to do that here since 'Interpreter's type is parametric in the value being returned—we dont know that were returning a @value@ (because we very well may not be). On the balance, I felt the strange behaviour in error cases is worth the improved behaviour in the common case—we get to lose a layer of 'Either' in the result for each.
-- In general, its expected that none of the following effects will remain by the time 'interpret' is called—they should have been handled by local 'interpose's—but if they do, well at least trace.
. Eff.interpret (\ control -> case control of
Break value -> traceM ("Evaluating.interpret: resuming uncaught break with " <> show value) $> value
Continue value -> traceM ("Evaluating.interpret: resuming uncaught continue with " <> show value) $> value))
-- TODO: Replace 'traceM's with e.g. 'Telemetry'.
. runFail)

View File

@ -324,7 +324,7 @@ evaluatePackageWith :: ( Evaluatable (Base term)
, State (Environment location value)
] effects
, Recursive term
, termEffects ~ (Return value ': EvalClosure term value ': moduleEffects)
, termEffects ~ (LoopControl value ': Return value ': EvalClosure term value ': moduleEffects)
, moduleEffects ~ (Reader ModuleInfo ': EvalModule term value ': packageBodyEffects)
, packageBodyEffects ~ (Reader LoadStack ': Reader (ModuleTable [Module term]) ': packageEffects)
, packageEffects ~ (Reader PackageInfo ': effects)
@ -344,7 +344,7 @@ evaluatePackageBodyWith :: forall location term value effects termEffects module
, State (Environment location value)
] effects
, Recursive term
, termEffects ~ (Return value ': EvalClosure term value ': moduleEffects)
, termEffects ~ (LoopControl value ': Return value ': EvalClosure term value ': moduleEffects)
, moduleEffects ~ (Reader ModuleInfo ': EvalModule term value ': packageBodyEffects)
, packageBodyEffects ~ (Reader LoadStack ': Reader (ModuleTable [Module term]) ': effects)
)
@ -370,9 +370,10 @@ evaluatePackageBodyWith perModule perTerm body
evalTerm
= handleEvalClosures
. runReturn
. runLoopControl
. foldSubterms (perTerm eval)
evaluateEntryPoint m sym = handleReader (ModuleInfo m) . handleEvalClosures . runReturn $ do
evaluateEntryPoint m sym = handleReader (ModuleInfo m) . handleEvalClosures . runReturn . runLoopControl $ do
v <- maybe unit (pure . snd) <$> require m
maybe v ((`call` []) <=< variable) sym

View File

@ -32,7 +32,7 @@ import qualified Language.Python.Assignment as Python
import qualified Language.Ruby.Assignment as Ruby
justEvaluating
= evaluating @(Value Precise)
= evaluating
. failingOnLoadErrors
. erroring @(ValueError Precise (Value Precise))
. erroring @(Unspecialized (Value Precise))
@ -41,7 +41,7 @@ justEvaluating
. erroring @(AddressError Precise (Value Precise))
evaluatingWithHoles
= evaluating @(Value Precise)
= evaluating
. failingOnLoadErrors
. resumingBadSyntax @(Value Precise)
. resumingBadValues @(Value Precise)
@ -51,7 +51,7 @@ evaluatingWithHoles
-- The order is significant here: caching has to run before typeChecking, or else well nondeterministically produce TypeErrors as part of the result set. While this is probably actually correct, it will require us to have an Ord instance for TypeError, which we dont have yet.
checking
= evaluating @(Type Monovariant)
= evaluating
. providingLiveSet
. failingOnLoadErrors
. erroring @(Unspecialized (Type Monovariant))