|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Untamed: Evaluates and matches Kernel-E expressions and patterns explicitly, so that this evaluation can happen, for example, remotely.
Evaluators also support the E syntactic sugar
meta.eval(evaluator, expr) and meta <- eval(evaluator, expr)as a convenience for evaluating the expression in the lexical scope of the caller.
E is an expression/pattern language. This means that execution proceeds by evaluating expressions in a lexical scope, and matching patterns in a lexical scope against a specimen (an arbitrary value which the pattern may match). Expressions and patterns may recursively contain both expressions and patterns. The result of matching a pattern against a specimen is not just an answer -- "Did the specimen match?" -- but also bindings of values (typically extracted from the specimen) to variables named in the pattern. Indeed, this is the only form of variable definition in E.
An E program is an fully ordered left-to-right tree of expressions and patterns, with a set of nested scope boxes statically imposed on this tree by particular types of expressions and patterns. When a pattern defines a variable, this name is in scope left to right from the point of definition until the end of its containing scope box.
Putting it all together, a node (an expression or pattern) has two scope-based interfaces to the outside world:
bindingsIn are the those variables used freely by the
node -- those that it uses but doesn't define, and that therefore
must be in scope where the node starts. We exempt from bindingsIn
the
NonShadowable
elements of the safeScope.
bindingsOut are those variables defined by the node that are still in scope following the node, and that may be needed by code to the right of the node within the same enclosing scope box. In a static compilation context, this should only include variables that actually are used by a node to the right of the present node.
The syntactic sugar
meta.eval(evaluator, expr)expands into a call to evaluator to evaluate the provided expression in the lexical context of this sugar. Assuming the evaluator evaluates the expression according to the normal rules, then the expression evaluation should have the same effects it normally would have had. The Deslotifying transformation of the E compiler must turn all the variables in and out of expr into final variables, as explained above. For example,
var x := 3 def y := 7 ... x ... x := 4 ... y ... ... meta.eval(visualizingEvaluator, x ** y =~ pow) ... ... pow ... expands to def x__Slot := settable.makeSlot(3) def y := 7 ... x__Slot ... (x__Slot.setValue(4)) ... y ... def [pow, pow__Resolver] := Ref.promise() ... visualizingEvaluator.eval(e`x__Slot.getValue() ** y =~ pow`, ["x__Slot" => x__Slot, "y" => y], true, ["pow" => pow_Resolver]) ... ... pow ...If the "meta.eval(...)" occurs in a context where the value it evaluates to is statically seen as unneeded, the "true" above would instead be "false".
If pow were defined as var pow, it would be transformed into the final variable pow__Slot.
Similarly
meta <- eval(evaluator, expr)expands into an eventual send to evaluator to eventually evaluate the provided expression in the lexical context of this sugar. For example
meta <- eval(remoteEvaluator, def powOverThere(x) :any { x**2 }) def y := powOverThere <- (3) expands to def [powOverThere, powOverThere__Resolver] := Ref.promise() remoteEvaluator <- eval(e`def powOverThere(x) :any { x**2 }`, [].asMap(), false, ["powOverThere" => powOverThere__Resolver]) def y := powOverThere <- (3)The powOverThere function is defined on the remote machine or whatever, but is locally named "powOverThere". If this machine is VatA and the remote machine is VatC, we could now hand powOverThere to an object on VatB, who would then obtain a reference directly connected to VatC. If VatA then goes off-line, VatB would still be able to use powOverThere on VatC.
With the eventual form, the expression evaluates in the current lexical scope, just as if it were being implicitly evaluated, but it evaluates at a later time in its own turn, and potentially in another vat. If this appears in a context where its value might be used, it evaluates to a promise for the outcome of evaluating the expression, and the third argument of the expansion would be "true". Because of the delay, any Ejectors from the containing context will already be used up, so the expression cannot perform a non-local escape to an escape clause that has already exited (ie, Ejectors are dynamic-extent continuations).
If the evaluation is remote, then all bindings in and out will be as transformed by passage through the Pluribus. The non-obvious implication of this is that any use or assignment of any variable transformed by Deslotifying will fail if the resulting Slot is PassByProxy (the default). When using "meta <- eval(...)" to do remote evaluation, all in and out variables must either be final, or use Slot types that are PassByCopy or PassByConstruction (like the lamportSlot).
Method Summary | |
Object |
eval(EExpr eExpr,
ConstMap bindingsIn,
boolean forValue,
ConstMap bindingsOut)
Enabled: Evaluates an E expression in a provided lexical scope. |
Object[] |
evalToSingleton(EExpr eExpr,
ConstMap bindingsIn,
boolean forValue,
ConstMap bindingsOut)
Enabled: Just like eval(), except that, when evaluating for a value, evalToSingleton() returns a singleton list containing the value. |
boolean |
matchBind(Pattern pattern,
ConstMap bindingsIn,
boolean forTest,
ConstMap bindingsOut,
Object specimen)
Enabled: Matches pattern against specimen, either failing or producing bindings. |
Method Detail |
public Object eval(EExpr eExpr, ConstMap bindingsIn, boolean forValue, ConstMap bindingsOut) throws Throwable
When invoked asynchronously ("<-"), the invoker of eval() cannot distinguish between eval() evaluating to a broken reference as a value, vs eval() throwing a problem. use evalToSingleton() when you want to avoid this ambiguity. (Note: This ambiguity will often be desired. The "meta <- eval(...)" purposely produces this ambiguity.)
eExpr
- The expression to be evaluated.bindingsIn
- Provides bindings for those variables
used freely in eExpr, other than those defined in the
safe scope (like "true").forValue
- Says whether anyone cares about the value this
eExpr evaluates to. If false, eval() should evaluate for
effect only and return null.bindingsOut
- Provides a mapping from variable names to
Resolvers for those variable names that eExpr defines, and that
some expression in the successor scope uses.
Throwable
- If eExpr exits non-locally, then eval()
performs the same non-local exit. The two kinds of non-local
exit are throwing a problem (Throwable) and Ejecting. Ejecting
only works when the Ejector is still good, which can only
happen when eval() is invoked synchronously.public Object[] evalToSingleton(EExpr eExpr, ConstMap bindingsIn, boolean forValue, ConstMap bindingsOut) throws Throwable
This way an asynchronous invoker ("<-") can distinguish between a successful evaluation to a broken reference as a value vs a thrown problem.
Throwable
public boolean matchBind(Pattern pattern, ConstMap bindingsIn, boolean forTest, ConstMap bindingsOut, Object specimen) throws Throwable
Unlike eval(), no syntactic sugar is currently defined for matchBind().
pattern
- The pattern to be matched against the specimen.bindingsIn
- Provides bindings for those variables
used freely in pattern, other than those defined in the
safe scope (like "true").forTest
- Says whether this should indicate failure by
returning false. If forTest, then on failure all the
bindingsOut must be broken with a problem report explaining the
reason for match failure. If forTest is false, then the
problem report is thrown on failure, and bindingsOut should be ignored.bindingsOut
- Provides a mapping from variable names to
Resolvers for those variable names that pattern defines, and
that some expression or pattern in the successor scope uses.
The values of these 'out' variables are typically values
extracted from specimen by matching.specimen
- The object to be matched against the pattern.
Throwable
- If pattern exits non-locally, then
matchBind() performs the same non-local exit. The two
kinds of non-local exit are throwing a problem (Throwable) and
Ejecting. Also, if forTest is false and the match fails,
matchBind() throws a problem explaining the failure.
|
|||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |