spec: multiple values — values/call-with-values/let-values/define-values
25 tests pass on both JS and OCaml hosts. Uses dict marker
{:_values true :_list [...]} for 0/2+ values; 1 value passes
through directly. step-sf-define extended to desugar shorthand
(define (name params) body) forms on both hosts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-04-26T19:02:22Z";
|
||||
var SX_VERSION = "2026-05-01T07:58:35Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -780,6 +780,7 @@
|
||||
if (isLambda(f)) return trampoline(callLambda(f, args, lambdaClosure(f)));
|
||||
return f.apply(null, args);
|
||||
};
|
||||
PRIMITIVES["apply"] = apply;
|
||||
|
||||
// Additional primitive aliases used by adapter/engine transpiled code
|
||||
var split = PRIMITIVES["split"];
|
||||
@@ -2007,6 +2008,58 @@ PRIMITIVES["qq-expand"] = qqExpand;
|
||||
})(); };
|
||||
PRIMITIVES["sf-letrec"] = sfLetrec;
|
||||
|
||||
// call-with-values
|
||||
var callWithValues = function(producer, consumer) { return (function() {
|
||||
var result = apply(producer, []);
|
||||
return (isSxTruthy((isSxTruthy(isDict(result)) && get(result, "_values", false))) ? apply(consumer, get(result, "_list")) : apply(consumer, [result]));
|
||||
})(); };
|
||||
PRIMITIVES["call-with-values"] = callWithValues;
|
||||
|
||||
// sf-let-values
|
||||
var sfLetValues = function(args, env) { return (function() {
|
||||
var clauses = first(args);
|
||||
var body = rest(args);
|
||||
var local = envExtend(env);
|
||||
{ var _c = clauses; for (var _i = 0; _i < _c.length; _i++) { var clause = _c[_i]; (function() {
|
||||
var names = first(clause);
|
||||
var valExpr = nth(clause, 1);
|
||||
return (function() {
|
||||
var result = trampoline(evalExpr(valExpr, local));
|
||||
return (function() {
|
||||
var vs = (isSxTruthy((isSxTruthy(isDict(result)) && get(result, "_values", false))) ? get(result, "_list") : [result]);
|
||||
return forEachIndexed(function(idx, name) { return envBind(local, symbolName(name), nth(vs, idx)); }, names);
|
||||
})();
|
||||
})();
|
||||
})(); } }
|
||||
return (function() {
|
||||
var lastVal = NIL;
|
||||
{ var _c = body; for (var _i = 0; _i < _c.length; _i++) { var e = _c[_i]; lastVal = trampoline(evalExpr(e, local)); } }
|
||||
return lastVal;
|
||||
})();
|
||||
})(); };
|
||||
PRIMITIVES["sf-let-values"] = sfLetValues;
|
||||
|
||||
// sf-define-values
|
||||
var sfDefineValues = function(args, env) { return (function() {
|
||||
var names = first(args);
|
||||
var valExpr = nth(args, 1);
|
||||
return (function() {
|
||||
var result = trampoline(evalExpr(valExpr, env));
|
||||
return (function() {
|
||||
var vs = (isSxTruthy((isSxTruthy(isDict(result)) && get(result, "_values", false))) ? get(result, "_list") : [result]);
|
||||
forEachIndexed(function(idx, name) { return envBind(env, symbolName(name), nth(vs, idx)); }, names);
|
||||
return NIL;
|
||||
})();
|
||||
})();
|
||||
})(); };
|
||||
PRIMITIVES["sf-define-values"] = sfDefineValues;
|
||||
|
||||
// (register-special-form! ...)
|
||||
registerSpecialForm("define-values", sfDefineValues);
|
||||
|
||||
// (register-special-form! ...)
|
||||
registerSpecialForm("let-values", sfLetValues);
|
||||
|
||||
// step-sf-letrec
|
||||
var stepSfLetrec = function(args, env, kont) { return (function() {
|
||||
var thk = sfLetrec(args, env);
|
||||
@@ -2200,6 +2253,10 @@ PRIMITIVES["step-eval-list"] = stepEvalList;
|
||||
})(); };
|
||||
PRIMITIVES["sf-define-type"] = sfDefineType;
|
||||
|
||||
// values
|
||||
var values = function() { var vs = Array.prototype.slice.call(arguments, 0); return (isSxTruthy(sxEq(len(vs), 1)) ? first(vs) : {"_values": true, "_list": vs}); };
|
||||
PRIMITIVES["values"] = values;
|
||||
|
||||
// (register-special-form! ...)
|
||||
registerSpecialForm("define-type", sfDefineType);
|
||||
|
||||
@@ -2692,11 +2749,19 @@ PRIMITIVES["step-sf-let"] = stepSfLet;
|
||||
|
||||
// step-sf-define
|
||||
var stepSfDefine = function(args, env, kont) { return (function() {
|
||||
var nameSym = first(args);
|
||||
var hasEffects = (isSxTruthy((len(args) >= 4)) && isSxTruthy(sxEq(typeOf(nth(args, 1)), "keyword")) && sxEq(keywordName(nth(args, 1)), "effects"));
|
||||
var valIdx = (isSxTruthy((isSxTruthy((len(args) >= 4)) && isSxTruthy(sxEq(typeOf(nth(args, 1)), "keyword")) && sxEq(keywordName(nth(args, 1)), "effects"))) ? 3 : 1);
|
||||
var effectList = (isSxTruthy((isSxTruthy((len(args) >= 4)) && isSxTruthy(sxEq(typeOf(nth(args, 1)), "keyword")) && sxEq(keywordName(nth(args, 1)), "effects"))) ? nth(args, 2) : NIL);
|
||||
return makeCekState(nth(args, valIdx), env, kontPush(makeDefineFrame(symbolName(nameSym), env, hasEffects, effectList), kont));
|
||||
var resolvedArgs = (isSxTruthy(sxEq(typeOf(first(args)), "list")) ? (function() {
|
||||
var fnName = first(first(args));
|
||||
var params = rest(first(args));
|
||||
var bodyParts = rest(args);
|
||||
return [fnName, concat([makeSymbol("fn")], [params], bodyParts)];
|
||||
})() : args);
|
||||
return (function() {
|
||||
var nameSym = first(resolvedArgs);
|
||||
var hasEffects = (isSxTruthy((len(resolvedArgs) >= 4)) && isSxTruthy(sxEq(typeOf(nth(resolvedArgs, 1)), "keyword")) && sxEq(keywordName(nth(resolvedArgs, 1)), "effects"));
|
||||
var valIdx = (isSxTruthy((isSxTruthy((len(resolvedArgs) >= 4)) && isSxTruthy(sxEq(typeOf(nth(resolvedArgs, 1)), "keyword")) && sxEq(keywordName(nth(resolvedArgs, 1)), "effects"))) ? 3 : 1);
|
||||
var effectList = (isSxTruthy((isSxTruthy((len(resolvedArgs) >= 4)) && isSxTruthy(sxEq(typeOf(nth(resolvedArgs, 1)), "keyword")) && sxEq(keywordName(nth(resolvedArgs, 1)), "effects"))) ? nth(resolvedArgs, 2) : NIL);
|
||||
return makeCekState(nth(resolvedArgs, valIdx), env, kontPush(makeDefineFrame(symbolName(nameSym), env, hasEffects, effectList), kont));
|
||||
})();
|
||||
})(); };
|
||||
PRIMITIVES["step-sf-define"] = stepSfDefine;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user