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

'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");
};