An additional component on kernel [[ObjectExpr]]s: the "<code>as</code>" clause, syntactically preceding the "<code>implements</code>", behaves like it but with the additional effect of making its value be the guard for the binding of the object name (without coercing the object). That is, <code>def x as Y {}</code> audits x with Y, and also causes the binding to be <code>("x", makeFinalSlot(<x>), FinalSlot[Y])</code>.

An additional component on kernel [[ObjectExpr]]s: the "<code>as</code>" clause, syntactically preceding the "<code>implements</code>", behaves like it but with the additional effect of making its value be the guard for the binding of the object name (without coercing the object). That is, <code>def x as Y {}</code> audits x with Y, and also causes the binding to be <code>("x", makeFinalSlot(<x>), FinalSlot[Y])</code>.

-

Bindings may be reified in E programs using the prefix &amp;&amp; operator. (This is necessary to support nonkernel <code>[[meta.getState]]()</code>.) "&amp;&amp;" is a single token and operator, not two prefix operators. As an expression, it is BindingExpr(NounExpr); as a pattern it is BindingPattern(NounExpr). The pattern does not take a guard like [[SlotPattern]] does.

+

Bindings may be reified in E programs using the prefix &amp;&amp; operator. (This is necessary to support nonkernel <code>[[meta.getState]]()</code>, and beneficial to the extends-syntax "<code>super</code>".) "&amp;&amp;" is a single token and operator, not two prefix operators. As an expression, it is BindingExpr(NounExpr); as a pattern it is BindingPattern(NounExpr). The pattern does not take a guard like [[SlotPattern]] does.

Because bindings are Selfless, the evaluator need not make any effort to preserve their identities.

Because bindings are Selfless, the evaluator need not make any effort to preserve their identities.

Revision as of 04:17, 8 November 2008

This is a new design for auditing in E. It is currently provided in E-on-CL. It is an alternative to the unshadowable-names/synEnv system currently implemented in E-on-Java, and the give-the-auditor-access-to-everything previously used by E-on-CL.

Contents

Basic implementation

In environments, nouns are associated with "bindings" instead of slots. A binding is an object which holds a slot and a guard, and alleges that that slot was returned from that guard (except for object expressions; see below).

Note that FinalPatterns and VarPatterns must get FinalSlot and VarSlot guards; e.g. def x :int := 1 results in the binding object makeCoercedSlot(FinalSlot[int], makeFinalSlot(1), null) (except that implementations may optimize it to not require constructing an intermediate FinalSlot if the guard coerces).

If a pattern does not have a guard, then any is used. Examples: def x := y has a binding guard of FinalSlot[any], and def &x := y has a binding guard of any.

Auditions have one relevant method, getGuard/1. Given a noun (string), it returns the guard of the matching binding. If the noun is not one of the free variables of the audition's object expression, or if the audit has already terminated, then an exception is thrown.

An additional component on kernel ObjectExprs: the "as" clause, syntactically preceding the "implements", behaves like it but with the additional effect of making its value be the guard for the binding of the object name (without coercing the object). That is, def x as Y {} audits x with Y, and also causes the binding to be ("x", makeFinalSlot(<x>), FinalSlot[Y]).

Bindings may be reified in E programs using the prefix && operator. (This is necessary to support nonkernel meta.getState(), and beneficial to the extends-syntax "super".) "&&" is a single token and operator, not two prefix operators. As an expression, it is BindingExpr(NounExpr); as a pattern it is BindingPattern(NounExpr). The pattern does not take a guard like SlotPattern does.

Because bindings are Selfless, the evaluator need not make any effort to preserve their identities.

All bindings in the safeScope expose their values in their guards; that is, they are ("foo", bar, FinalSlot[Same[bar]]).

CoercedSlots are PassByConstruction; their uncall is makeCoercedSlot.attempt(guard, value). This performs guard.coerce(value, ...); if the guard fails, or returns a reference which is not the same as the original value, then the resulting CoercedSlot has LostApproval[guard] instead of the original guard. LostApproval is equivalent to any, and is used merely to report what the original guard was and why it is missing. (XXX LostApproval is not implemented in E-on-CL)

Implications for auditors

Implications for guards

To support multiple independently-written auditors on the same object, it must be possible to have single guards which satisfy multiple auditors' criteria. It is also desirable that programmers need not write code to match exactly an auditor's view of what is necessary. Therefore, we add the optional operation rangeSupersetOf/1 to guards.

to rangeSupersetOf(other :Guard) :nullOk[boolean]

If X.rangeSupersetOf(Y) returns true, X is claiming that every value returned by Y (as a guard) would have been returned by X under some circumstances; that is, the 'range' of X is a 'superset of' the range of Y. For example, int.rangeSupersetOf(1..10) should be true, as should DeepFrozen.rangeSupersetOf(int).

Returning false indicates that X is not a range superset of Y; returning null indicates that X doesn't know.