cwebber pushed a commit to branch compile-to-js-merge
in repository guile.
commit 479294fc056b5c0e8cb0ca20a1bdf760f02898fb
Author: Ian Price <[email protected]>
AuthorDate: Wed Jun 28 15:03:03 2017 +0100
Implement Winding & Unwinding
* module/language/js-il/runtime.js
(wind, unwind): Implement.
(callcc): Wind when invoking continuation.
---
module/language/js-il/runtime.js | 71 ++++++++++++++++++++++++++++++++++++----
1 file changed, 65 insertions(+), 6 deletions(-)
diff --git a/module/language/js-il/runtime.js b/module/language/js-il/runtime.js
index 5a2afa2..5fc10c2 100644
--- a/module/language/js-il/runtime.js
+++ b/module/language/js-il/runtime.js
@@ -380,7 +380,7 @@ var abort_to_prompt = function(self, k, prompt) {
kont = new scheme.Closure(f, 0);
};
- unwind(idx);
+ unwind(scheme.dynstack, idx); // FIXME:
var handler = frame.handler;
args.unshift(kont);
@@ -396,8 +396,17 @@ var call_with_values = function (self, k, producer,
consumer) {
};
var callcc = function (self, k, closure) {
+ var dynstack = scheme.dynstack.slice();
+
var f = function (self, k2) {
var args = Array.prototype.slice.call(arguments, 2);
+
+ var i = shared_stack_length(dynstack, scheme.dynstack);
+
+ unwind(scheme.dynstack, i);
+ wind(dynstack, i);
+ scheme.dynstack = dynstack;
+
return k.apply(k,args);
};
return closure.fun(closure, k, new scheme.Closure(f, 0));
@@ -461,8 +470,17 @@ scheme.primitives["fluid-ref"] = function (fluid) {
scheme.primitives["variable?"] = not_implemented_yet;
// Dynamic Wind
-scheme.primitives["wind"] = not_implemented_yet;
-scheme.primitives["unwind"] = not_implemented_yet;
+scheme.primitives["wind"] = function(enter, leave) {
+ var frame = new scheme.frame.DynWind(enter, leave);
+ scheme.dynstack.unshift(frame);
+};
+
+scheme.primitives["unwind"] = function () {
+ var frame = scheme.dynstack.shift();
+ if (!(frame instanceof scheme.frame.DynWind)) {
+ throw "not a dynamic wind frame";
+ };
+};
// Misc
scheme.primitives["prompt"] = function(escape_only, tag, handler){
@@ -470,9 +488,45 @@ scheme.primitives["prompt"] = function(escape_only, tag,
handler){
scheme.dynstack.unshift(frame);
};
-var unwind = function (idx) {
- // TODO: call winders
- scheme.dynstack = scheme.dynstack.slice(idx+1);
+var shared_stack_length = function (dynstack1, dynstack2) {
+ // Assumes that if it matches at i then it matches for all x<i,
+ // which will be fine given that we don't reuse frames
+ var size1 = dynstack1.length;
+ var size2 = dynstack2.length;
+ var last = Math.min(size1, size2);
+
+ var i = last-1;
+ for (; i >= 0; i--) {
+ if (dynstack1[i] === dynstack2[i]) {
+ break;
+ }
+ };
+
+ return i + 1;
+};
+
+var wind = function (dynstack, idx) {
+ for (var i = idx; i < dynstack.length; i++) {
+ var frame = dynstack[i];
+ if (frame instanceof scheme.frame.DynWind) {
+ // TODO: how to handle continuations and errors in this?
+ frame.wind.fun(frame.wind, scheme.initial_cont);
+ } else {
+ throw "unsupported frame type -- wind";
+ }
+ }
+};
+
+var unwind = function (dynstack, idx) {
+ for (var i = dynstack.length - 1; i >= idx; i--) {
+ var frame = dynstack[i];
+ if (frame instanceof scheme.frame.DynWind) {
+ // TODO: how to handle continuations and errors in this?
+ frame.unwind.fun(frame.unwind, scheme.initial_cont);
+ } else {
+ throw "unsupported frame type -- unwind";
+ }
+ }
};
var find_prompt = function(prompt) {
@@ -509,6 +563,11 @@ scheme.frame.Fluid = function(fluid, old_value) {
this.old_value = old_value;
};
+scheme.frame.DynWind = function(wind, unwind) {
+ this.wind = wind;
+ this.unwind = unwind;
+};
+
// Module Cache
scheme.module_cache["guile"] = scheme.env;