Safe Serialization Under Mutual Suspicion/"Reversing" Evaluation

From Erights

(Difference between revisions)
Jump to: navigation, search
(saved with code highlighting and colouring)
(spans and few newlines removed. 'pragma.syntax("0.8")' added)
Line 12: Line 12:
<code>
<code>
<pre>
<pre>
-
        <span class="keyword">def</span> <span class="defobj">deSubgraphKit</span> {
+
pragma.syntax("0.8")
-
    <span class="keyword">to</span> <span class="defobj">makeBuilder</span>(<span class="defvar">scope</span>) :near {
+
-
        <span class="comment"># The index of the next temp variable</span>
+
def deSubgraphKit {
 +
    to makeBuilder(scope) :near {
-
         <span class="keyword">var</span> <span class="defvar">nextTemp</span> := 0
+
         # The index of the next temp variable
-
         <span class="comment"># The frame of temp variables</span>
+
         var nextTemp := 0
-
        <span class="keyword">def</span> <span class="defvar">temps</span> := [].diverge()
+
-
         <span class="comment"># The type returned by &quot;internal&quot; productions and passed as arguments to represent</span>
+
         # The frame of temp variables
 +
        def temps := [].diverge()
-
         <span class="comment"># built subtrees.</span>
+
         # The type returned by &quot;internal&quot; productions and passed as arguments to represent
-
        <span class="keyword">def</span> <span class="defvar">Node</span> := any
+
-
         <span class="comment"># The type returned by the builder as a whole.</span>
+
         # built subtrees.
-
         <span class="keyword">def</span> <span class="defvar">Root</span> := any
+
         def Node := any
-
         <span class="comment"># DEBuilderOf is a parameterized type constructor.</span><span class="comment"></span>
+
         # The type returned by the builder as a whole.
 +
        def Root := any
-
         <span class="keyword">def</span> <span class="defobj">deSubgraphBuilder</span> implements DEBuilderOf(Node, Root) {
+
         # DEBuilderOf is a parameterized type constructor.
-
            <span class="keyword">to</span> <span class="defverb">getNodeType</span>() :near { Node }
+
-
            <span class="keyword">to</span> <span class="defverb">getRootType</span>() :near { Root }
+
-
            <span class="comment">/** Called at the end with the reconstructed root to obtain the value to return. */</span>
+
        def deSubgraphBuilder implements DEBuilderOf(Node, Root) {
-
             <span class="keyword">to</span> <span class="defverb">buildRoot</span>(<span class="defvar">root</span> :Node)       :Root  { root }
+
             to getNodeType() :near { Node }
 +
            to getRootType() :near { Root }
-
             <span class="comment">/** A literal evaluates to its value. */</span>
+
             /** Called at the end with the reconstructed root to obtain the value to return. */
 +
            to buildRoot(root :Node)        :Root  { root }
-
             <span class="keyword">to</span> <span class="defverb">buildLiteral</span>(<span class="defvar">value</span>)          :Node  { value }
+
             /** A literal evaluates to its value. */
 +
            to buildLiteral(value)          :Node  { value }
-
             <span class="comment">/** A free variable's name is looked up in the scope. */</span>
+
             /** A free variable's name is looked up in the scope. */
-
             <span class="keyword">to</span> <span class="defverb">buildImport</span>(<span class="defvar">varName</span> :String) :Node  { scope[varName] }
+
             to buildImport(varName :String) :Node  { scope[varName] }
-
             <span class="comment">/** A temporary variable's index is looked up in the temps frame. */</span>
+
             /** A temporary variable's index is looked up in the temps frame. */
 +
            to buildIbid(tempIndex :int)    :Node  { temps[tempIndex] }
-
             <span class="keyword">to</span> <span class="defverb">buildIbid</span>(<span class="defvar">tempIndex</span> :int)    :Node  { temps[tempIndex] }
+
             /** Perform the  described call. */
-
 
+
             to buildCall(rec :Node, verb :String, args :Node[]) :Node {
-
            <span class="comment">/** Perform the  described call. */</span>
+
                 # E.call(..) is E's reflective invocation construct. For example, E.call(2, &quot;add&quot;, [3])
-
             <span class="keyword">to</span> <span class="defverb">buildCall</span>(<span class="defvar">rec</span> :Node, <span class="defvar">verb</span> :String, <span class="defvar">args</span> :Node[]) :Node {
+
                 # performs the same call as 2.add(3).
-
                 <span class="comment"># E.call(..) is E's reflective invocation construct. For example, E.call(2, &quot;add&quot;, [3])</span>
+
-
 
+
-
                 <span class="comment"># performs the same call as 2.add(3).</span>
+
                 <u>E.call(rec, verb, args)</u>
                 <u>E.call(rec, verb, args)</u>
             }
             }
-
             <span class="comment">/**</span>
+
             /**
-
            <span class="comment"> * Called prior to building the right-hand side of a defexpr, to allocate and bind the</span>
+
            * Called prior to building the right-hand side of a defexpr, to allocate and bind the
-
            <span class="comment"> * next two temp variables to a promise and its resolver.</span>
+
            * next two temp variables to a promise and its resolver.
-
            <span class="comment"> * </span>
+
            *  
-
            <span class="comment"> * @return the index of the temp holding the promise. The temp holding the</span>
+
            * @return the index of the temp holding the promise. The temp holding the
-
            <span class="comment"> *              resolver is understood to be this plus one.</span>
+
            *              resolver is understood to be this plus one.
-
            <span class="comment"> */</span>
+
            */
-
             <span class="keyword">to</span> <span class="defverb">buildPromise</span>() :int {
+
             to buildPromise() :int {
-
                 <span class="keyword">def</span> <span class="defvar">promIndex</span> := nextTemp
+
                 def promIndex := nextTemp
                 nextTemp += 2
                 nextTemp += 2
-
                 <span class="keyword">def</span> [<span class="defvar">prom</span>,<span class="defvar">res</span>] := Ref.promise()
+
                 def [prom,res] := Ref.promise()
                 temps[promIndex] := prom
                 temps[promIndex] := prom
                 temps[promIndex+1] := res
                 temps[promIndex+1] := res
Line 75: Line 74:
             }
             }
-
             <span class="comment">/**</span>
+
             /**
-
 
+
            * Called once the right-hand side of a defexpr is built, use the resolver to resolve
-
            <span class="comment"> * Called once the right-hand side of a defexpr is built, use the resolver to resolve</span>
+
            * the value of the promise.
-
            <span class="comment"> * the value of the promise.</span>
+
            *  
-
            <span class="comment"> * </span>
+
            * @return the value of the right-hand side.
-
            <span class="comment"> * @return the value of the right-hand side.</span>
+
            */
-
            <span class="comment"> */</span>
+
-
             <span class="keyword">to</span> <span class="defverb">buildDefrec</span>(<span class="defvar">resIndex</span> :int, <span class="defvar">rValue</span> :Node) :Node {
+
             to buildDefrec(resIndex :int, rValue :Node) :Node {
                 temps[resIndex].resolve(rValue)
                 temps[resIndex].resolve(rValue)
                 rValue
                 rValue
             }
             }
-
             <span class="comment"># ... buildDefine is an optimization of buildDefrec for known non-cyclic cases.</span>
+
             # ... buildDefine is an optimization of buildDefrec for known non-cyclic cases.
         }
         }
     }
     }
-
     <span class="comment"># ... other useful tools </span>
+
     # ... other useful tools  
}
}

Revision as of 06:36, 29 January 2008

As we've seen, we make serializers, unserializers, and other transformers like expression simplifiers by composing a recognizer with a builder. The interface between the two is the DEBuilder API, explained in Appendix A: The Data-E Manual. Since most of the API is a straightforward reflection of the Data-E grammar productions, if you wish, you may safely skip these details and proceed here by example.

Evaluating Data-E

The semantics of Data-E are defined by the semantics of its evaluation as an E program. We could unserialize using the full E evaluator. However, this is inefficient both as an implementation and as an explanation. Instead, here is the Data-E evaluator as a builder, implementing exactly this subset of E's semantics.

pragma.syntax("0.8")

def deSubgraphKit {
    to makeBuilder(scope) :near {

        # The index of the next temp variable

        var nextTemp := 0

        # The frame of temp variables
        def temps := [].diverge()

        # The type returned by "internal" productions and passed as arguments to represent

        # built subtrees.
        def Node := any

        # The type returned by the builder as a whole.
        def Root := any

        # DEBuilderOf is a parameterized type constructor.

        def deSubgraphBuilder implements DEBuilderOf(Node, Root) {
            to getNodeType() :near { Node }
            to getRootType() :near { Root }

            /** Called at the end with the reconstructed root to obtain the value to return. */
            to buildRoot(root :Node)        :Root  { root }

            /** A literal evaluates to its value. */
            to buildLiteral(value)          :Node  { value }

            /** A free variable's name is looked up in the scope. */
            to buildImport(varName :String) :Node  { scope[varName] }

            /** A temporary variable's index is looked up in the temps frame. */
            to buildIbid(tempIndex :int)    :Node  { temps[tempIndex] }

            /** Perform the  described call. */
            to buildCall(rec :Node, verb :String, args :Node[]) :Node {
                # E.call(..) is E's reflective invocation construct. For example, E.call(2, "add", [3])
                # performs the same call as 2.add(3).
                <u>E.call(rec, verb, args)</u>
            }

            /**
             * Called prior to building the right-hand side of a defexpr, to allocate and bind the
             * next two temp variables to a promise and its resolver.

             * 
             * @return the index of the temp holding the promise. The temp holding the
             *               resolver is understood to be this plus one.
             */
            to buildPromise() :int {
                def promIndex := nextTemp
                nextTemp += 2
                def [prom,res] := Ref.promise()
                temps[promIndex] := prom
                temps[promIndex+1] := res
                promIndex
            }

            /**
             * Called once the right-hand side of a defexpr is built, use the resolver to resolve
             * the value of the promise.
             * 
             * @return the value of the right-hand side.
             */

            to buildDefrec(resIndex :int, rValue :Node) :Node {
                temps[resIndex].resolve(rValue)
                rValue
            }

            # ... buildDefine is an optimization of buildDefrec for known non-cyclic cases.
        }
    }
    # ... other useful tools 

}


Part 2: "Reversing" Evaluation

Personal tools
more tools