Published
Edited
Feb 17, 2018
7 stars
Insert cell
Insert cell
tex.block`1+\frac{1}{2} + \frac{1}{3} + \frac{1}{4} + \frac{1}{5} + \cdots `
Insert cell
Insert cell
expr = (n, q) =>
n >= 10 ?
Math.PI + 1 + (1/2) + (1/n) + Math.pow(n, 22) * Math.sqrt(n) / Math.sin(n) % 3
: n == "lol" ?
Math.abs(-42) :
1 != Infinity ? 20 : q[5]
Insert cell
Insert cell
exprString = expr.toString()
Insert cell
Insert cell
acorn = require('acorn')
Insert cell
Insert cell
exprBody = {
const {body:[{expression:{body}}]} = acorn.parse(exprString);
return body;
}
Insert cell
Insert cell
function stringify(fn) {
const {body:[{expression:{body}}]} = acorn.parse(fn.toString());
return stringifyNode(body);
}
Insert cell
Insert cell
function stringifyNode(node) {
switch (node.type) {
case 'ConditionalExpression':
return `
\\begin{cases}
${stringifyNode(node.consequent)} & \\quad ${stringifyNode(node.test)} \\\\
${stringifyNode(node.alternate)} & \\quad
\\end{cases}`
case 'BinaryExpression':
switch (node.operator) {
case '+':
case '*':
case '>':
case '<':
return `${stringifyNode(node.left)} ${node.operator} ${stringifyNode(node.right)}`;
case '==':
case '===':
return `${stringifyNode(node.left)} = ${stringifyNode(node.right)}`;
case '!=':
case '!==':
return `${stringifyNode(node.left)} \\ne ${stringifyNode(node.right)}`;
case '>=':
return `${stringifyNode(node.left)} \\geq ${stringifyNode(node.right)}`;
case '<=':
return `${stringifyNode(node.left)} \\leq ${stringifyNode(node.right)}`;
case '/':
return `\\frac{${stringifyNode(node.left)}}\{${stringifyNode(node.right)}}`;
case '%':
// TODO: bmod or pmod?
return `${stringifyNode(node.left)} \\bmod ${stringifyNode(node.right)}`;
}
case 'Literal':
return node.raw;
case 'UnaryExpression':
switch (node.operator) {
case '-':
return `-${stringifyNode(node.argument)}`;
case '+':
return stringifyNode(node.argument);
}
case 'Identifier':
switch (node.name) {
case 'Infinity': return '\\infty';
default: return node.name;
}
break;
case 'CallExpression':
if (node.callee.object.name !== 'Math') throw new Error('ONLY MATH FOR THE LATEX EATER');
switch (node.callee.property.name) {
case 'pow':
return `${stringifyNode(node.arguments[0])}^{${stringifyNode(node.arguments[1])}}`;
case 'sqrt':
return `\\sqrt{${stringifyNode(node.arguments[0])}}`;
case 'sin':
case 'cos':
case 'tan':
case 'sinh':
case 'cosh':
case 'tanh':
return `\\${node.callee.property.name}{${stringifyNode(node.arguments[0])}}`;
case 'abs':
return `|${stringifyNode(node.arguments[0])}|`;
}
case 'MemberExpression':
if (node.object.name === 'Math') {
switch (node.property.name) {
case 'PI':
return '\\pi';
}
}
return `${stringifyNode(node.object)}_{${stringifyNode(node.property)}}`
}
}
Insert cell
Insert cell
stringify(expr)
Insert cell
Insert cell
tex.block`${stringify(expr)}`
Insert cell
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