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 '%':
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)}}`
}
}