Skip to content

Commit

Permalink
Fix multiple-value-bind for single value forms
Browse files Browse the repository at this point in the history
A form like f(values, 1, 2, 3)

doesn't actually need to call values so we can't just use it as a
continuation. We need to wrap everything with mvbind to check if
values is called or not.

  mvbind(values => f(values, 1, 2, 3), (x,y)=>...)
  • Loading branch information
davazp committed Jun 28, 2019
1 parent 0b439fc commit fd33a99
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 9 deletions.
2 changes: 1 addition & 1 deletion packages/delisp-core/__tests__/eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ describe("Evaluation", () => {
});

it("multiple-value-bind can catch forms with a single value transparently", () => {
expect(evaluateString(`(multiple-value-bind (x) 3 x)`)).toBe(3);
expect(evaluateString(`(multiple-value-bind (x) 3 (+ x 1))`)).toBe(4);
});

it("multiple-value-bind can catch forms with a multiple values", () => {
Expand Down
9 changes: 3 additions & 6 deletions packages/delisp-core/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,7 @@ function compileMultipleValueBind(
compileBody(expr.node.body, newenv, multipleValues)
);

return {
type: "CallExpression",
callee: form,
arguments: [continuation]
};
return primitiveCall("mvbind", form, continuation);
}

function compileUnknown(
Expand Down Expand Up @@ -532,7 +528,8 @@ function compileRuntimeUtils(
"primaryValue",
"values",
"mvbind",
"bindPrimaryValue"
"bindPrimaryValue",
"mvbind"
]);
}

Expand Down
6 changes: 4 additions & 2 deletions packages/delisp-core/src/eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
snd,
values,
primaryValue,
bindPrimaryValue
bindPrimaryValue,
mvbind
} from "@delisp/runtime";

export function createContext() {
Expand All @@ -31,7 +32,8 @@ export function createContext() {
snd,
values,
primaryValue,
bindPrimaryValue
bindPrimaryValue,
mvbind
};
vm.createContext(sandbox);
return sandbox;
Expand Down
20 changes: 20 additions & 0 deletions packages/delisp-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,23 @@ export const values = primaryValue;
export function bindPrimaryValue(fn: Function): Function {
return (...args: unknown[]) => fn(primaryValue, ...args);
}

export function mvbind(
form: (values: any, ...args: any[]) => any,
cont: (...results: any[]) => any
) {
let valuesCalled = false;

const values = (...results: any[]) => {
valuesCalled = true;
return cont(...results);
};

const result = form(values);

if (valuesCalled) {
return result;
} else {
return values(result);
}
}

0 comments on commit fd33a99

Please sign in to comment.