You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.6 KiB
JavaScript
147 lines
3.6 KiB
JavaScript
'use strict';
|
|
|
|
const repeatString = require("repeat-string");
|
|
const assureArray = require("assure-array");
|
|
|
|
function debugPrintNode(node) {
|
|
return `${node.type} | ${node.value || node.operator || node.identifier}`;
|
|
}
|
|
|
|
function prettyPrint(items, indentation) {
|
|
if (indentation == null) {
|
|
throw new Error(`Missing indentation parameter (node: ${debugPrintNode(node)})`);
|
|
}
|
|
|
|
return items.map((item) => {
|
|
if (typeof item === "string") {
|
|
return item.split("\n").map((line) => {
|
|
return repeatString("\t", indentation) + line;
|
|
}).join("\n");
|
|
} else {
|
|
return prettyPrint(item, indentation + 1);
|
|
}
|
|
}).join("\n");
|
|
}
|
|
|
|
|
|
function stringifyNode(node, indentation) {
|
|
if (indentation == null) {
|
|
throw new Error(`Missing indentation parameter (node: ${debugPrintNode(node)})`);
|
|
}
|
|
|
|
switch (node.type) {
|
|
case "operatorExpression":
|
|
return stringifyOperator(node, indentation);
|
|
case "numberLiteral":
|
|
return stringifyNumberLiteral(node, indentation);
|
|
case "stringLiteral":
|
|
return stringifyStringLiteral(node, indentation);
|
|
case "identifier":
|
|
return stringifyIdentifier(node, indentation);
|
|
case "set":
|
|
return stringifySet(node, indentation);
|
|
case "letBlock":
|
|
return stringifyLetBlock(node, indentation);
|
|
case "list":
|
|
return stringifyList(node, indentation);
|
|
case "functionDefinition":
|
|
return stringifyFunctionDefinition(node, indentation);
|
|
case "group":
|
|
return stringifyGroup(node, indentation);
|
|
default:
|
|
throw new Error(`Unexpected node type '${node.type}'`);
|
|
}
|
|
}
|
|
|
|
function stringifyOperator(node, indentation) {
|
|
let result;
|
|
|
|
switch (node.operator) {
|
|
case "+":
|
|
case "-":
|
|
case "/":
|
|
case "*":
|
|
case "++":
|
|
case "//":
|
|
case "&&":
|
|
case "||":
|
|
case "==":
|
|
case "!=":
|
|
case "<":
|
|
case "<=":
|
|
case ">":
|
|
case ">=":
|
|
result = `${stringifyNode(node.left, indentation)} ${node.operator} ${stringifyNode(node.right, indentation)}`;
|
|
break;
|
|
case "call":
|
|
result = `${stringifyNode(node.left, indentation)} ${stringifyNode(node.right, indentation)}`;
|
|
break;
|
|
case "numericalNegate":
|
|
result = `-${stringifyNode(node.right, indentation)}`;
|
|
break;
|
|
case "booleanNegate":
|
|
result = `!${stringifyNode(node.right, indentation)}`;
|
|
break;
|
|
}
|
|
|
|
return `(${result})`;
|
|
}
|
|
|
|
function stringifyStringLiteral(node, indentation) {
|
|
return `"${node.value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
}
|
|
|
|
function stringifyNumberLiteral(node, indentation) {
|
|
return `${node.value}`;
|
|
}
|
|
|
|
function stringifyIdentifier(node, indentation) {
|
|
return `${node.identifier}`;
|
|
}
|
|
|
|
function stringifyBinding(node, indentation) {
|
|
return `${stringifyNode(node.identifier, indentation)} = ${stringifyNode(node.expression, indentation)};`
|
|
}
|
|
|
|
function stringifyGroup(node, indentation) {
|
|
return `(${stringifyNode(node.expression, indentation)})`
|
|
}
|
|
|
|
function stringifySet(node, indentation) {
|
|
return prettyPrint([
|
|
"{",
|
|
node.assignments.map((binding) => {
|
|
return stringifyBinding(binding, indentation);
|
|
}),
|
|
"}"
|
|
], indentation);
|
|
}
|
|
|
|
function stringifyLetBlock(node, indentation) {
|
|
return prettyPrint([
|
|
"let",
|
|
node.bindings.map((binding) => {
|
|
return stringifyBinding(binding, indentation);
|
|
}),
|
|
"in",
|
|
[stringifyNode(node.expression, indentation)]
|
|
], indentation);
|
|
}
|
|
|
|
function stringifyList(node, indentation) {
|
|
return `[ ${node.items.map(item => stringifyNode(item, indentation)).join(" ")} ]`;
|
|
}
|
|
|
|
function stringifyFunctionDefinition(node, indentation) {
|
|
return prettyPrint([
|
|
`${stringifyNode(node.argument, indentation)}:`,
|
|
[stringifyNode(node.body, indentation)]
|
|
], indentation);
|
|
}
|
|
|
|
module.exports = function stringifyTree(tree) {
|
|
return assureArray(tree).map((subTree) => {
|
|
return stringifyNode(subTree, 0);
|
|
}).join("\n");
|
|
};
|