more on haku, highlighting fixes
This commit is contained in:
parent
e9ae153266
commit
e1fe9fde11
5 changed files with 429 additions and 6 deletions
|
@ -2,7 +2,17 @@ export const treewalk = {};
|
|||
export const builtins = {};
|
||||
|
||||
treewalk.init = (input) => {
|
||||
return { input };
|
||||
return { input, scopes: [new Map(Object.entries(builtins))] };
|
||||
};
|
||||
|
||||
treewalk.lookupVariable = (state, name) => {
|
||||
for (let i = state.scopes.length; i-- > 0; ) {
|
||||
let scope = state.scopes[i];
|
||||
if (scope.has(name)) {
|
||||
return scope.get(name);
|
||||
}
|
||||
}
|
||||
throw new Error(`variable ${name} is undefined`);
|
||||
};
|
||||
|
||||
treewalk.eval = (state, node) => {
|
||||
|
@ -11,10 +21,12 @@ treewalk.eval = (state, node) => {
|
|||
let sourceString = state.input.substring(node.start, node.end);
|
||||
return parseInt(sourceString);
|
||||
|
||||
case "identifier":
|
||||
return treewalk.lookupVariable(state, state.input.substring(node.start, node.end));
|
||||
|
||||
case "list":
|
||||
let functionToCall = node.children[0];
|
||||
let builtin = builtins[state.input.substring(functionToCall.start, functionToCall.end)];
|
||||
return builtin(state, node);
|
||||
let functionToCall = treewalk.eval(state, node.children[0]);
|
||||
return functionToCall(state, node);
|
||||
|
||||
default:
|
||||
throw new Error(`unhandled node kind: ${node.kind}`);
|
||||
|
@ -40,3 +52,53 @@ builtins["+"] = arithmeticBuiltin((a, b) => a + b);
|
|||
builtins["-"] = arithmeticBuiltin((a, b) => a - b);
|
||||
builtins["*"] = arithmeticBuiltin((a, b) => a * b);
|
||||
builtins["/"] = arithmeticBuiltin((a, b) => a / b);
|
||||
|
||||
export function makeFunction(state, paramNames, bodyExpr) {
|
||||
let capturedScopes = [];
|
||||
// Start from 1 to skip builtins, which are always present anyways.
|
||||
for (let i = 1; i < state.scopes.length; ++i) {
|
||||
// We don't really mutate the scopes after pushing them onto the stack, so keeping
|
||||
// references to them is okay.
|
||||
capturedScopes.push(state.scopes[i]);
|
||||
}
|
||||
|
||||
return (state, node) => {
|
||||
if (node.children.length != paramNames.length + 1)
|
||||
throw new Error(
|
||||
`incorrect number of arguments: expected ${paramNames.length}, but got ${node.children.length - 1}`,
|
||||
);
|
||||
|
||||
let scope = new Map();
|
||||
for (let i = 0; i < paramNames.length; ++i) {
|
||||
scope.set(paramNames[i], treewalk.eval(state, node.children[i + 1]));
|
||||
}
|
||||
|
||||
state.scopes.push(...capturedScopes);
|
||||
state.scopes.push(scope);
|
||||
let result = treewalk.eval(state, bodyExpr);
|
||||
state.scopes.pop();
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
builtins.fn = (state, node) => {
|
||||
if (node.children.length != 3)
|
||||
throw new Error("an `fn` must have an argument list and a result expression");
|
||||
|
||||
let params = node.children[1];
|
||||
if (node.children[1].kind != "list")
|
||||
throw new Error("expected parameter list as second argument to `fn`");
|
||||
|
||||
let paramNames = [];
|
||||
for (let param of params.children) {
|
||||
if (param.kind != "identifier") {
|
||||
throw new Error("`fn` parameters must be identifiers");
|
||||
}
|
||||
paramNames.push(state.input.substring(param.start, param.end));
|
||||
}
|
||||
|
||||
let expr = node.children[2];
|
||||
|
||||
return makeFunction(state, paramNames, expr);
|
||||
};
|
||||
|
|
|
@ -79,7 +79,9 @@ export async function evaluate(commands, { error, newOutput }) {
|
|||
kind: "output",
|
||||
output: {
|
||||
kind: "error",
|
||||
message: [err.toString()],
|
||||
message: [
|
||||
err.stack.length > 0 ? err.toString() + "\n\n" + err.stack : err.toString(),
|
||||
],
|
||||
},
|
||||
outputIndex,
|
||||
});
|
||||
|
|
|
@ -53,7 +53,13 @@ function tokenize(text, syntax) {
|
|||
text.substring(start, end),
|
||||
);
|
||||
}
|
||||
lastMatchEnd = end;
|
||||
}
|
||||
pushToken(
|
||||
tokens,
|
||||
pattern.is.default,
|
||||
text.substring(lastMatchEnd, match.indices[0][1]),
|
||||
);
|
||||
} else {
|
||||
pushToken(tokens, pattern.is, match[0]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue