# Copyright 2007 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ pragma.syntax("0.9") def deSubgraphKit := def makeCycleBreaker := def makeProxy := def makeBrand := def mapL(f, l) { def out := [].diverge() for x in l { out.push(f(x)) } return out.snapshot() } def makeSharedRefLink implements ExitViaHere { # implements DeepFrozen to run(Passable, MyPassByConstruction, asBootRef) { def sharedRefLink def [proxySealer, proxyUnsealer] := makeBrand("shared-ref link") def proxyBrand := proxySealer.getBrand() def passesFlex := [].asMap().diverge() var lastPassId := -1 def builderTemps := [].diverge() var nextTemp := 0 var outgoingTag := -1 def flushPasses() { passesFlex.removeAll() lastPassId := -1 builderTemps.replace(0, builderTemps.size(), [], 0, 0) nextTemp := 0 outgoingTag := -1 } def sharer {} # just a marker def pbcUncaller { to optUncall(r) { if (r =~ p :MyPassByConstruction && r == p) { return p.__optUncall() } } } def shareNotCopyUncaller { to optUncall(r) { if (r =~ p :Passable && p =~ q :Data && r == q) { def passId := (lastPassId += 1) passesFlex.put(passId, ["share", p], true) return [sharer, "run", [passId]] } } } def proxyUncaller { to optUncall(r) { def passId := (lastPassId += 1) def kind := Ref.isResolved(r).pick("proxy", "promise") def bootRef := if (Ref.optSealedDispatch(r, proxyBrand) =~ box :notNull) { proxyUnsealer.unseal(box) } else { asBootRef(r) } passesFlex.put(passId, [kind, bootRef], true) return [sharer, "run", [passId]] } } def recognizer := deSubgraphKit.makeRecognizer( [shareNotCopyUncaller, pbcUncaller, proxyUncaller], makeCycleBreaker.byInverting([=> sharer])) def builderForRecognizer { to getNodeType() { return any } to getRootType() { return any } to buildRoot(x) { return x } to buildLiteral(x) { return ["share", x] } to buildIbid(tempIndex) { return builderTemps[tempIndex] } to buildImport(=="sharer") { return sharer } to buildPromise() { def promIndex := nextTemp nextTemp += 2 def [prom,res] := Ref.promise() builderTemps[promIndex] := prom builderTemps[promIndex+1] := res return promIndex } to buildDefrec(resIndex, rValue) { builderTemps[resIndex].resolve(rValue) return rValue } to buildCall(rec, verb, args) { if (__equalizer.sameYet(sharer, rec)) { def [[=="share", id]] := args return passesFlex[id] } else { return ["call", outgoingTag += 1, rec, verb, args] } } } def recog(localRef) { return recognizer.recognize(localRef, builderForRecognizer) } def build(desc) { def seen := [].asMap().diverge() def subbuild(desc) { escape e { return seen.fetch(desc, e) } def result seen[desc] := result bind result := switch (desc) { match [=="share", r] { r } match [=="proxy", bootRef] { sharedRefLink.proxy(bootRef, false) } match [=="promise", bootRef] { sharedRefLink.proxy(bootRef, true) } match [=="call", tag, r, v :String, a :List] { # tag exists only for uniqueness in structure try { E.call(subbuild(r), v, mapL(subbuild, a)) } catch p { # XXX review: is PBC arriving as broken the right thing? or # should we fail the entire received message instead, and # resolve its response to broken? Ref.broken(p) } } } return result } return subbuild(desc) } return bind sharedRefLink := {def sharedRefLink { to proxy(bootRef :Passable, isPromise :boolean) { escape nonlocal { return bootRef.unwrap(nonlocal) } def handler { to handleSend(verb :String, args :List) { bootRef <- ([verb, mapL(recog, args), recog(def result)]) flushPasses() return result } to handleSendOnly(verb :String, args :List) { bootRef <- ([verb, mapL(recog, args)]) flushPasses() } to handleOptSealedDispatch(brand) { if (brand == proxyBrand) { return proxySealer.seal(bootRef) } } } def resolutionBox def proxy := makeProxy(handler, resolutionBox, !isPromise) if (isPromise) { handler.handleSendOnly("__whenMoreResolved", [def moreResolvedReactor(resolution) { bind resolutionBox := &resolution }]) } return proxy } to receive(recipient, message) { switch (message) { match [verb, argDescs, resolverDesc] { E.sendOnly(build(resolverDesc), "resolve", [E.send(recipient, verb, mapL(build, argDescs))]) } match [verb, argDescs] { E.sendOnly(recipient, verb, mapL(build, argDescs)) } } } }} } }