@readable-js/core
Version:
ReadableJS is a toolkit for teachers to craft small demos that can be explored interactively.
135 lines (134 loc) • 5.83 kB
JavaScript
import { is } from './enode-type-check';
// not suer this work, maybe it can be refactored
// need to evaluate value at some point..
function generateReadableValue(left, right, options) {
// not sure when that is used
if ((right === null || right === void 0 ? void 0 : right.type) === "FunctionExpression") {
console.warn('generateReadableValue unknown path');
return "this function";
}
if (!!left && is.Identifier(left) && (options === null || options === void 0 ? void 0 : options.replaceVar)) {
return (`##replace-${left.name}##`);
}
return generateReadableExpression(right);
}
// equivalent to truthy function
function formatBinary(node, verbiage, negation) {
let isOrNotText = '';
// ignore if undefined
if (negation === true) {
isOrNotText = " is not";
}
else if (negation === false) {
isOrNotText = " is";
}
return generateReadableExpression(node["left"]) + isOrNotText + verbiage + generateReadableExpression(node["right"]);
}
const converter = {
"AssignmentExpression": (e, options) => {
// note: he evaluate the expression on the right `foo = 1 + bar`, 1+bar is evaluated, I need to put a marker somewhere
const map = new Map([
['=', (e) => `set ${ge(e['left'])} to ${generateReadableValue(e['left'], e['right'], options)}`],
['+=', (e) => `add ${ge(e['right'])} to ${ge(e['left'])} and set ${ge(e['left'])} to ${generateReadableValue(e['left'], e['right'])}`],
['-=', (e) => `subtract ${ge(e['right'])} from ${ge(e['left'])} and set ${ge(e['left'])} to ${generateReadableValue(e['left'], e['right'])}`],
['*=', (e) => `multiply ${ge(e['left'])} by ${ge(e['right'])} and set ${ge(e['left'])} to ${generateReadableValue(e['left'], e['right'])}`],
['/=', (e) => `divide ${ge(e['left'])} to ${ge(e['right'])} and set ${ge(e['left'])} to ${generateReadableValue(e['left'], e['right'])}`],
['%=', (e) => `divide ${ge(e['left'])} to ${ge(e['right'])} and set ${ge(e['left'])} to the remainder: ${generateReadableValue(e['left'], e['right'])}`],
['**=', (e) => ``],
['<<=', (e) => ``],
['>>=', (e) => ``],
['>>>=', (e) => ``],
['|=', (e) => ``],
['^=', (e) => ``],
['&=', (e) => ``],
]);
return map.get(e.operator)(e);
},
"BinaryExpression": (e) => {
const map = new Map([
['==', (e) => formatBinary(e, " equal to ")],
['!=', (e) => formatBinary(e, " different ")],
['===', (e) => formatBinary(e, " strict equal to ")],
['!==', (e) => formatBinary(e, " strict different ")],
['<', (e) => formatBinary(e, " less than ")],
['<=', (e) => formatBinary(e, " less than or equal to ")],
['>', (e) => formatBinary(e, " greater than ")],
['>=', (e) => formatBinary(e, " greater than or equal to ")],
['<<', (e) => ''],
['>>', (e) => ''],
['>>>', (e) => ''],
['+', (e) => formatBinary(e, " plus ")],
['-', (e) => formatBinary(e, " minus ")],
['*', (e) => formatBinary(e, " times ")],
['/', (e) => formatBinary(e, " divided by ")],
['%', (e) => formatBinary(e, " modulo ")],
['**', (e) => ''],
['|', (e) => formatBinary(e, " bitwise-or ")],
['^', (e) => formatBinary(e, " bitwise-and ")],
['&', (e) => ''],
['in', (e) => ''],
['instanceof', (e) => ''],
]);
return map.get(e.operator)(e);
},
"ObjectExpression": (e) => "an object",
"CallExpression": (e) => {
if (e.callee.type === "Identifier"
|| e.callee.type === "MemberExpression") {
}
if (is.Identifier(e.callee)) {
return `Call the function ${generateReadableExpression(e.callee)}`;
// ignored compile thing, probably something missing with else
}
else if (is.MemberExpression(e.callee)) {
if (is.Super(e.callee.object)) {
return 'super'; // that's new
}
else { // is Expression
return generateReadableExpression(e.callee.object);
// ignored compile thing, probably something missing with else
}
}
else if (is.ExpressionWithProperty(e.callee)) {
return e.callee.property.name;
}
else {
throw new Error(`Unknown CallExpression of type: ${e.callee.type}`);
}
},
"MemberExpression": (e) => {
if (is.Super(e.object)) {
return 'super';
}
else { // is Expression
// strange, we don't process this as in CallExpression
return generateReadableExpression(e.object)
+ '.'
+ generateReadableExpression(e.property); // can be PrivateIdentifier too
}
},
"Literal": (e) => e.value + '',
"Identifier": (e) => e.name,
"VariableDeclarator": (e) => {
if (is.FunctionExpression(e.init)) {
return 'this function';
}
else {
return generateReadableExpression(e.id);
}
},
"FunctionExpression": (e) => 'this function'
};
export function generateReadableExpression(exp, options) {
if (!exp) {
return '';
}
if (converter.hasOwnProperty(exp.type)) {
return converter[exp.type](exp, options);
}
else {
console.warn(`Not found converter for: ${exp.type}`);
return '';
}
}
const ge = generateReadableExpression;