Skip to content

Fix compiler bug #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/lambda-calculus.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,16 +345,16 @@ export function compile(code) {
function evalLC(term) {

// builds function to return to user ( representing an abstraction awaiting input )
function awaitArg(term, stack, env) {
function awaitArg(term, env) {
// callback function which will evaluate term.body in an env with the input
function result(arg) {
let argEnv;
if ( arg?.term && arg?.env ) ({ term: arg, env: argEnv } = arg); // if callback is passed another callback, or a term
const termVal = new Tuple( typeof arg === 'number' ? fromInt(arg) : arg , new Env(argEnv) );
if ( term.name==="_" )
return runEval( new Tuple(term.body, new Env(env)), stack );
return runEval( new Tuple(term.body, new Env(env)) );
else
return runEval( new Tuple(term.body, new Env(env).setThunk(term.name, termVal)), stack );
return runEval( new Tuple(term.body, new Env(env).setThunk(term.name, termVal)) );
}
return Object.assign( result, {term,env} );
}
Expand All @@ -363,8 +363,8 @@ function evalLC(term) {
// isRight :: bool (indicating whether the term is left or right side of an Application)
// isEvaluated :: bool (indicating whether the current term should be stored in the Env)
// callstack :: [String] (History of var lookups, for better error messages)
function runEval({term,env},stack) { // stack: [[term, isRight, isEvaluated]], term: LC term, env = Env { name => term }
const callstack = []; // Does not persist between requests for arguments
function runEval({term,env}) { // stack: [[term, isRight, isEvaluated]], term: LC term, env = Env { name => term }
const callstack = [], stack = []; // Does not persist between requests for arguments
while ( ! ( term instanceof L ) || stack.length > 0 ) {
if ( term instanceof V )
if ( term.name==="()" )
Expand All @@ -377,7 +377,7 @@ function evalLC(term) {
else {
if (res.term instanceof V || res.term instanceof A)
// Push a frame to the stack to indicate when the value should be stored back
stack.push( [new Tuple( term, env ), false, true ] );
stack.push( [new Tuple( term, env ), true, true ] );
({term, env} = res);
}
}
Expand All @@ -395,7 +395,7 @@ function evalLC(term) {
env = new Env(env).setThunk(term.name, new Tuple(lastTerm, lastEnv));
term = term.body;
} else { // Pass the function some other function.
term = lastTerm(awaitArg(term, [], env));
term = lastTerm(awaitArg(term, env));
}
} else if ( term instanceof Tuple ) {
// for primitives
Expand All @@ -421,9 +421,9 @@ function evalLC(term) {
}
}
// We need input
return awaitArg(term, stack, env);
return awaitArg(term, env);
}
return runEval(term, []);
return runEval(term);
}

// Print an error, with stack trace according to verbosity level
Expand Down
1 change: 1 addition & 0 deletions tests/known-bugs/solution.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo = \ x j c . x c ()
18 changes: 18 additions & 0 deletions tests/known-bugs/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {readFileSync} from "fs";
import {assert, config as chaiConfig} from "chai";
chaiConfig.truncateThreshold = 0;

import * as LC from "../../src/lambda-calculus.js";
LC.configure({ purity: "Let", numEncoding: "None" });

const solutionText = readFileSync(new URL("./solution.txt", import.meta.url), {encoding: "utf8"});
const { foo } = LC.compile(solutionText);

describe("No side effects", () => {
it("The initial failed call used to cause the second call to behave weirdly", () => {
try {
foo("hi")("there")("world")
} catch {}
assert.strictEqual( foo(null).term.toString(), "\\ j c . x c ()" );
});
});