complete compilation.

also rename misleading names "execution" to "compilation".
This commit is contained in:
trans_soup 2023-11-06 15:20:19 +01:00
parent 9a5597813c
commit 64a01d4abf
2 changed files with 113 additions and 66 deletions

113
src/compile.mjs Normal file
View File

@ -0,0 +1,113 @@
import Line from "./Line.mjs";
import Expr from "./Expr.mjs";
export function compile (program) {
let env = new Map();
for (const line of program) {
const result = compile_line(env, line);
if (!result.valid) {
return {
valid: false,
env: env,
};
}
env = result.env;
}
return {
valid: true,
env: env,
};
}
function compile_line (env, line) {
function invalid (current_env = env) {
return {
valid: false,
env: current_env,
};
}
if (line.type === Line.Invalid) return invalid();
if (line.type === Line.Empty || line.type === Line.Comment) {
return {
valid: true,
env: env,
};
}
if (line.type === Line.Special) {
// as there are currently no reserved special lines,
// and this implementation adds no custom ones,
// every special line is invalid.
return invalid();
}
if (line.type === Line.Binding) {
let value;
let valid = true;
try {
value = evaluate(env, line.body);
} catch (e) {
valid = false;
}
if (!valid) return invalid();
const new_env = new Map(env);
new_env.set(line.name, value);
return {
valid: true,
env: new_env,
};
}
return invalid();
}
function evaluate (env, expr, locals = []) {
if (expr.type === Expr.Token) {
const token = expr.value;
if (has_local(locals, token)) {
return get_local(locals, token);
}
if (env.has(token)) {
return env.get(token);
}
throw new Error();
}
if (expr.type === Expr.Application) {
const fn = evaluate(env, expr.fn, locals);
const arg = evaluate(env, expr.arg, locals);
return([fn, arg]);
}
if (expr.type === Expr.Fn) {
const args = [ ...expr.args ].reverse();
const body = evaluate(env, expr.body, args);
return body;
}
throw new Error();
}
function has_local (locals, name) {
return locals.includes(name);
}
function get_local (locals, name) {
return locals.indexOf(name);
}

View File

@ -1,66 +0,0 @@
import Line from "./Line.mjs";
export function execute (program) {
let env = new Map();
for (const line of program) {
const result = execute_line(env, line);
if (!result.valid) {
return {
valid: false,
env: env,
};
}
env = result.env;
}
return {
valid: true,
env: env,
};
}
function execute_line (env, line) {
function invalid () {
return {
valid: false,
env: env,
};
}
if (line.type === Line.Invalid) return invalid();
if (line.type === Line.Empty || line.type === Line.Comment) {
return {
valid: true,
env: env,
};
}
if (line.type === Line.Special) {
// as there are currently no reserved special lines,
// and this implementation adds no custom ones,
// every special line is invalid.
return invalid();
}
if (line.type === Line.Binding) {
const new_env = new Map(env);
new_env.set(line.name, evaluate(env, line.body));
return {
valid: true,
env: new_env,
};
}
return invalid();
}
function evaluate (env, expr) {
return expr;
}