Public
Edited
Sep 10, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function parseValue(funNode, value) {
let res;
if (value instanceof Fun) {
res = new FunUsage(value);
} else if (typeof value === 'string') {
const nameObj = funNode.getName(value);
const usageObj = new NameUsage(nameObj);
res = usageObj;
} else if (Array.isArray(value)) {
const head = parseValue(funNode, value[0]);
if (head instanceof FunUsage || head instanceof NameUsage || head instanceof Call) {
let args = value.slice(1).map(expr => parseValue(funNode, expr));
if (head instanceof FunUsage && head.target.meta.parse) {
args = head.target.meta.parse(...args);
}
res = new Call(head, args);
} else {
throw new Error('Unexpected call head');
}
} else if (isPlainObject(value)) {
const assignments = Object.entries(value).map(([key, val]) => {
return new Assignment(
new NameUsage(funNode.getName(key)),
parseValue(funNode, val),
);
});
res = new Assignments(assignments);
} else {
res = new Data(value);
}
res.syntax = value;
return res;
}
Insert cell
Insert cell
Insert cell
parseFun({}, {a: 'b'})
Insert cell
Insert cell
Insert cell
Insert cell
function interpretFun(funNode) {

function interpretFunBody(ctx, argsKey, body) {
return (...args) => {
ctx[argsKey] = args;
try {
const res = interpretNode(ctx, body);
if (body instanceof Assignments) {
return res();
} else {
return res;
}
} catch (e) {
if (e instanceof ReturnException) {
return e.value;
} else if (e instanceof BreakException || e instanceof ContinueException) {
throw new Error('Break or continue without loop');
} else {
throw e;
}
}
}
}
function interpretNode(ctx, node, params={}) {
if (node instanceof NameUsage) {
if (node.isRef) {
return node.name.name;
} else {
return ctx[node.name.name];
}
} else if (node instanceof FunUsage) {
return interpretFun(node.target);
} else if (node instanceof Assignments) {
return () => {
let res;
for (const assignment of node.assignments) {
res = interpretNode(ctx, assignment);
}
return res;
}
} else if (node instanceof Assignment) {
const name = node.nameUsage.name.name;
const val = interpretNode(ctx, node.val);
ctx[name] = val;
return val;
} else if (node instanceof Data) {
return node.value;
} else if (node instanceof Lambda) {
return interpretFunBody(ctx, '$', node.body);
} else if (node instanceof Call) {
const head = interpretNode(ctx, node.head);
const args = node.args.map(arg => interpretNode(ctx, arg));
if (head.passCtx) {
return head(ctx, ...args);
} else {
return head(...args);
}
} else {
throw new Error('Unsupported node class');
}
}

let res;
if (funNode.meta.interpret) {
res = funNode.meta.interpret;
} else {
res = interpretFunBody({}, '', funNode.body);
}
if (funNode.meta.passCtx) {
res.passCtx = true;
}
return res;
}
Insert cell
function toLambda(node) {
if (node instanceof Assignments || node instanceof Lambda) {
return node;
} else {
return new Lambda(node);
}
}
Insert cell
function toName(node) {
if (node instanceof NameUsage) {
node.isRef = true;
}
return node;
}
Insert cell
ifThen = parseFun({
parse: (cond, ifTrue, ifFalse) => {
const res = [
cond,
toLambda(ifTrue),
];
if (ifFalse) {
res.push(toLambda(ifFalse));
}
return res;
},
interpret: (cond, ifTrue, ifFalse) => {
if (cond) {
return ifTrue();
} else if (ifFalse) {
return ifFalse();
}
},
})
Insert cell
inc = parseFun({
passCtx: true,
parse: (name) => {
return [toName(name)];
},
interpret: (ctx, name) => {
ctx[name] += 1;
return ctx[name];
}
})
Insert cell
data = parseFun({
parse: value => {
return [new Data(value.syntax)];
},
interpret: value => value,
})
Insert cell
lambda = parseFun({
parse: args => {
const vars = args.slice(0, -1);
const body = args.at(-1);
return new Lambda();
},
interpret: () => {
},
})
Insert cell
fn = parseFun({}, [data, {x: 1, incX: [inc, 'x'], y: 'x'}])
Insert cell
interpretFun(fn)()
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more