1141 lines
38 KiB
JavaScript
1141 lines
38 KiB
JavaScript
/* eslint-disable */
|
|
"use strict";
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
|
|
// dist/index.js
|
|
var dist_exports = {};
|
|
__export(dist_exports, {
|
|
Jinter: () => Jinter,
|
|
Nodes: () => nodes_exports,
|
|
Utils: () => utils_exports,
|
|
default: () => dist_default
|
|
});
|
|
module.exports = __toCommonJS(dist_exports);
|
|
|
|
// dist/nodes/index.js
|
|
var nodes_exports = {};
|
|
__export(nodes_exports, {
|
|
ArrayExpression: () => ArrayExpression,
|
|
ArrowFunctionExpression: () => ArrowFunctionExpression,
|
|
AssignmentExpression: () => AssignmentExpression,
|
|
BinaryExpression: () => BinaryExpression,
|
|
BlockStatement: () => BlockStatement,
|
|
BreakStatement: () => BreakStatement,
|
|
CallExpression: () => CallExpression,
|
|
ConditionalExpression: () => ConditionalExpression,
|
|
ContinueStatement: () => ContinueStatement,
|
|
ExpressionStatement: () => ExpressionStatement,
|
|
ForOfStatement: () => ForOfStatement,
|
|
ForStatement: () => ForStatement,
|
|
FunctionDeclaration: () => FunctionDeclaration,
|
|
FunctionExpression: () => FunctionExpression,
|
|
Identifier: () => Identifier,
|
|
IfStatement: () => IfStatement,
|
|
Literal: () => Literal,
|
|
LogicalExpression: () => LogicalExpression,
|
|
MemberExpression: () => MemberExpression,
|
|
NewExpression: () => NewExpression,
|
|
ObjectExpression: () => ObjectExpression,
|
|
Property: () => Property,
|
|
ReturnStatement: () => ReturnStatement,
|
|
SequenceExpression: () => SequenceExpression,
|
|
SwitchCase: () => SwitchCase,
|
|
SwitchStatement: () => SwitchStatement,
|
|
TemplateLiteral: () => TemplateLiteral,
|
|
ThisExpression: () => ThisExpression,
|
|
ThrowStatement: () => ThrowStatement,
|
|
TryStatement: () => TryStatement,
|
|
UnaryExpression: () => UnaryExpression,
|
|
UpdateExpression: () => UpdateExpression,
|
|
VariableDeclaration: () => VariableDeclaration,
|
|
WhileStatement: () => WhileStatement
|
|
});
|
|
|
|
// dist/nodes/BaseJSNode.js
|
|
var BaseJSNode = class {
|
|
constructor(node, visitor) {
|
|
this.node = node;
|
|
this.visitor = visitor;
|
|
}
|
|
run() {
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ArrayExpression.js
|
|
var ArrayExpression = class extends BaseJSNode {
|
|
run() {
|
|
return this.node.elements.map((el) => this.visitor.visitNode(el));
|
|
}
|
|
};
|
|
|
|
// dist/utils/index.js
|
|
var utils_exports = {};
|
|
__export(utils_exports, {
|
|
JinterError: () => JinterError,
|
|
namedFunction: () => namedFunction
|
|
});
|
|
var namedFunction = (name, fn) => Object.defineProperty(fn, "name", { value: name });
|
|
var JinterError = class extends Error {
|
|
constructor(message, info) {
|
|
super(message);
|
|
if (info) {
|
|
this.info = info;
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ArrowFunctionExpression.js
|
|
var ArrowFunctionExpression = class extends BaseJSNode {
|
|
run() {
|
|
const { params, body } = this.node;
|
|
const fn = namedFunction("anonymous function", (args) => {
|
|
let index = 0;
|
|
for (const param of params) {
|
|
this.visitor.visitNode(param);
|
|
if (param.type === "Identifier") {
|
|
this.visitor.scope.set(param.name, args[index]);
|
|
} else {
|
|
console.warn("Unhandled param type", param.type);
|
|
}
|
|
index++;
|
|
}
|
|
return this.visitor.visitNode(body);
|
|
});
|
|
return fn;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/AssignmentExpression.js
|
|
var AssignmentExpression = class extends BaseJSNode {
|
|
run() {
|
|
const operator = this.node.operator;
|
|
const right_node = this.visitor.visitNode(this.node.right);
|
|
switch (operator) {
|
|
case "=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] = right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
this.visitor.scope.set(this.node.left.name, right_node);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "+=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] += right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) + right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "-=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] -= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) - right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "*=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] *= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) * right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "/=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] /= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) / right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "%=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] %= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) % right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "**=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] **= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) ** right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "<<=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] <<= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) << right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case ">>=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] >>= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) >> right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case ">>>=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] >>>= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) >>> right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
case "&=":
|
|
if (this.node.left.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.left.object);
|
|
const prop = this.visitor.visitNode(this.node.left.property);
|
|
return obj[prop] &= right_node;
|
|
} else if (this.node.left.type === "Identifier") {
|
|
const result = this.visitor.visitNode(this.node.left) & right_node;
|
|
this.visitor.scope.set(this.node.left.name, result);
|
|
return this.visitor.scope.get(this.node.left.name);
|
|
}
|
|
console.warn("Unhandled left node", this.node.left);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/BinaryExpression.js
|
|
var BinaryExpression = class extends BaseJSNode {
|
|
run() {
|
|
const operator = this.node.operator;
|
|
const left_node = this.visitor.visitNode(this.node.left);
|
|
const right_node = this.visitor.visitNode(this.node.right);
|
|
switch (operator) {
|
|
case "!=":
|
|
return left_node != right_node;
|
|
case "!==":
|
|
return left_node !== right_node;
|
|
case "%":
|
|
return left_node % right_node;
|
|
case "&":
|
|
return left_node & right_node;
|
|
case "*":
|
|
return left_node * right_node;
|
|
case "**":
|
|
return left_node ** right_node;
|
|
case "+":
|
|
return left_node + right_node;
|
|
case "-":
|
|
return left_node - right_node;
|
|
case "/":
|
|
return left_node / right_node;
|
|
case "<":
|
|
return left_node < right_node;
|
|
case "<<":
|
|
return left_node << right_node;
|
|
case "<=":
|
|
return left_node <= right_node;
|
|
case "==":
|
|
return left_node == right_node;
|
|
case "===":
|
|
return left_node === right_node;
|
|
case ">":
|
|
return left_node > right_node;
|
|
case ">=":
|
|
return left_node >= right_node;
|
|
case ">>":
|
|
return left_node >> right_node;
|
|
case ">>>":
|
|
return left_node >>> right_node;
|
|
case "^":
|
|
return left_node ^ right_node;
|
|
case "|":
|
|
return left_node | right_node;
|
|
case "in":
|
|
return left_node in right_node;
|
|
case "instanceof":
|
|
return left_node instanceof right_node;
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/BlockStatement.js
|
|
var BlockStatement = class extends BaseJSNode {
|
|
run() {
|
|
for (const stmt of this.node.body) {
|
|
const result = this.visitor.visitNode(stmt);
|
|
if (stmt.type === "ReturnStatement")
|
|
return result;
|
|
if (result === "break" || result === "continue")
|
|
return result;
|
|
if ((stmt.type === "WhileStatement" || stmt.type === "IfStatement" || stmt.type === "ForStatement" || stmt.type === "TryStatement") && !!result) {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/BreakStatement.js
|
|
var BreakStatement = class extends BaseJSNode {
|
|
run() {
|
|
return "break";
|
|
}
|
|
};
|
|
|
|
// dist/nodes/CallExpression.js
|
|
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
};
|
|
var _CallExpression_instances;
|
|
var _CallExpression_throwError;
|
|
var _CallExpression_getCalleeString;
|
|
var CallExpression = class extends BaseJSNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
_CallExpression_instances.add(this);
|
|
}
|
|
run() {
|
|
let exp_object;
|
|
let exp_property;
|
|
if (this.node.callee.type === "MemberExpression") {
|
|
exp_object = this.visitor.getName(this.node.callee.object);
|
|
exp_property = this.visitor.getName(this.node.callee.property);
|
|
} else if (this.node.callee.type === "Identifier") {
|
|
exp_property = this.node.callee.name;
|
|
}
|
|
if (exp_object && this.visitor.listeners[exp_object]) {
|
|
const cb = this.visitor.listeners[exp_object](this.node, this.visitor);
|
|
if (cb !== "__continue_exec") {
|
|
return cb;
|
|
}
|
|
}
|
|
if (exp_property && exp_property !== "toString" && this.visitor.listeners[exp_property]) {
|
|
const cb = this.visitor.listeners[exp_property](this.node, this.visitor);
|
|
if (cb !== "__continue_exec") {
|
|
return cb;
|
|
}
|
|
}
|
|
if (this.node.callee.type === "MemberExpression") {
|
|
if (Builtins.has(this.node, this.visitor)) {
|
|
return Builtins.execute(this.node, this.visitor);
|
|
}
|
|
const obj = this.visitor.visitNode(this.node.callee.object);
|
|
const prop = this.node.callee.computed ? this.visitor.visitNode(this.node.callee.property) : this.visitor.getName(this.node.callee.property);
|
|
const args2 = this.node.arguments.map((arg) => this.visitor.visitNode(arg));
|
|
if (!obj)
|
|
__classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_throwError).call(this);
|
|
if (typeof obj[prop] !== "function")
|
|
__classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_throwError).call(this);
|
|
if (obj[prop].toString().includes("[native code]"))
|
|
return obj[prop](...args2);
|
|
return obj[prop](args2);
|
|
}
|
|
const fn = this.visitor.visitNode(this.node.callee);
|
|
const args = this.node.arguments.map((arg) => this.visitor.visitNode(arg));
|
|
if (typeof fn !== "function")
|
|
__classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_throwError).call(this);
|
|
return fn(args);
|
|
}
|
|
};
|
|
_CallExpression_instances = /* @__PURE__ */ new WeakSet(), _CallExpression_throwError = function _CallExpression_throwError2() {
|
|
if (this.node.callee.type === "MemberExpression" || this.node.callee.type === "Identifier") {
|
|
const callee_string = __classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_getCalleeString).call(this, this.node.callee);
|
|
throw new JinterError(`${callee_string} is not a function`);
|
|
} else if (this.node.callee.type === "SequenceExpression") {
|
|
const call = [];
|
|
const items = [];
|
|
call.push("(");
|
|
this.node.callee.expressions.forEach((expr) => {
|
|
if (expr.type === "Literal") {
|
|
items.push(expr.raw || "");
|
|
} else if (expr.type === "Identifier") {
|
|
items.push(expr.name);
|
|
} else if (expr.type === "MemberExpression") {
|
|
if (expr.computed) {
|
|
items.push(`${this.visitor.getName(expr.object)}[${this.visitor.getName(expr.property) || "..."}]`);
|
|
} else {
|
|
items.push(`${this.visitor.getName(expr.object)}.${this.visitor.getName(expr.property)}`);
|
|
}
|
|
}
|
|
});
|
|
call.push(items.join(", "));
|
|
call.push(")");
|
|
throw new JinterError(`${call.join("")} is not a function`);
|
|
}
|
|
}, _CallExpression_getCalleeString = function _CallExpression_getCalleeString2(node) {
|
|
if (node.type === "Identifier") {
|
|
return node.name;
|
|
} else if (node.type === "MemberExpression") {
|
|
const object_string = __classPrivateFieldGet(this, _CallExpression_instances, "m", _CallExpression_getCalleeString2).call(this, node.object);
|
|
const property_string = node.computed ? `[${this.visitor.getName(node.property) || "..."}]` : `.${this.visitor.getName(node.property)}`;
|
|
return `${object_string}${property_string}`;
|
|
}
|
|
return "<unknown>";
|
|
};
|
|
var Builtins = class {
|
|
static has(node, visitor) {
|
|
var _a;
|
|
if (node.callee.type === "MemberExpression") {
|
|
return !!((_a = this.builtins) === null || _a === void 0 ? void 0 : _a[visitor.getName(node.callee.property) || ""]);
|
|
}
|
|
return false;
|
|
}
|
|
static execute(node, visitor) {
|
|
if (node.callee.type === "MemberExpression") {
|
|
return this.builtins[visitor.getName(node.callee.property) || ""](node, visitor);
|
|
}
|
|
}
|
|
};
|
|
Builtins.builtins = {
|
|
// Override the forEach method so that the "this" arg is set correctly
|
|
forEach: (node, visitor) => {
|
|
const args = node.arguments.map((arg) => visitor.visitNode(arg));
|
|
if (node.callee.type === "MemberExpression") {
|
|
const arr = visitor.visitNode(node.callee.object);
|
|
if (args.length > 1) {
|
|
visitor.scope.set("_this", args.slice(-1)[0]);
|
|
}
|
|
let index = 0;
|
|
for (const element of arr) {
|
|
args[0]([element, index++, arr]);
|
|
}
|
|
} else {
|
|
console.warn("Unhandled callee type:", node.callee.type);
|
|
}
|
|
},
|
|
// Also override the toString method so that it stringifies the correct object
|
|
toString: (node, visitor) => {
|
|
if (node.callee.type === "MemberExpression") {
|
|
return visitor.visitNode(node.callee.object).toString();
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ConditionalExpression.js
|
|
var ConditionalExpression = class extends BaseJSNode {
|
|
run() {
|
|
const { test, consequent, alternate } = this.node;
|
|
const check = this.visitor.visitNode(test);
|
|
if (check) {
|
|
return this.visitor.visitNode(consequent);
|
|
}
|
|
return this.visitor.visitNode(alternate);
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ContinueStatement.js
|
|
var ContinueStatement = class extends BaseJSNode {
|
|
run() {
|
|
return "continue";
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ExpressionStatement.js
|
|
var ExpressionStatement = class extends BaseJSNode {
|
|
run() {
|
|
return this.visitor.visitNode(this.node.expression);
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ForOfStatement.js
|
|
var ForOfStatement = class extends BaseJSNode {
|
|
run() {
|
|
this.visitor.visitNode(this.node.left);
|
|
const right_node = this.visitor.visitNode(this.node.right);
|
|
for (const el of right_node) {
|
|
if (this.node.left.type === "VariableDeclaration" && this.node.left.declarations[0].id.type === "Identifier") {
|
|
this.visitor.scope.set(this.node.left.declarations[0].id.name, el);
|
|
} else if (this.node.left.type === "VariableDeclaration" && this.node.left.declarations[0].id.type === "ObjectPattern") {
|
|
for (const propert of this.node.left.declarations[0].id.properties) {
|
|
if (propert.type === "Property" && (propert.value.type === "Identifier" && propert.key.type === "Identifier")) {
|
|
this.visitor.scope.set(propert.value.name, el[propert.key.name]);
|
|
}
|
|
}
|
|
}
|
|
const body = this.visitor.visitNode(this.node.body);
|
|
if (body === "break") {
|
|
break;
|
|
}
|
|
if (body === "continue") {
|
|
continue;
|
|
}
|
|
if (body && this.node.body.type !== "ExpressionStatement") {
|
|
return body;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ForStatement.js
|
|
var ForStatement = class extends BaseJSNode {
|
|
run() {
|
|
if (this.node.init) {
|
|
this.visitor.visitNode(this.node.init);
|
|
}
|
|
const test = () => {
|
|
return this.node.test ? this.visitor.visitNode(this.node.test) : true;
|
|
};
|
|
for (; ; ) {
|
|
const _test = test();
|
|
if (!_test) {
|
|
break;
|
|
}
|
|
const body = this.visitor.visitNode(this.node.body);
|
|
if (body === "continue") {
|
|
continue;
|
|
}
|
|
if (body === "break") {
|
|
break;
|
|
}
|
|
if (this.node.update) {
|
|
this.visitor.visitNode(this.node.update);
|
|
}
|
|
if (body && this.node.body.type !== "ExpressionStatement") {
|
|
return body;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/FunctionDeclaration.js
|
|
var FunctionDeclaration = class extends BaseJSNode {
|
|
run() {
|
|
const { params, body } = this.node;
|
|
const id = this.visitor.visitNode(this.node.id);
|
|
const fn = namedFunction(id, (args) => {
|
|
let index = 0;
|
|
for (const param of params) {
|
|
this.visitor.visitNode(param);
|
|
if (param.type === "Identifier") {
|
|
this.visitor.scope.set(param.name, args[index]);
|
|
} else {
|
|
console.warn("Unhandled param type", param.type);
|
|
}
|
|
index++;
|
|
}
|
|
return this.visitor.visitNode(body);
|
|
});
|
|
this.visitor.scope.set(id, fn);
|
|
}
|
|
};
|
|
|
|
// dist/nodes/FunctionExpression.js
|
|
var FunctionExpression = class extends BaseJSNode {
|
|
run() {
|
|
const { params, body } = this.node;
|
|
const fn = namedFunction("anonymous function", (args) => {
|
|
let index = 0;
|
|
for (const param of params) {
|
|
this.visitor.visitNode(param);
|
|
if (param.type === "Identifier") {
|
|
this.visitor.scope.set(param.name, args[index]);
|
|
} else {
|
|
console.warn("Unhandled param type", param.type);
|
|
}
|
|
index++;
|
|
}
|
|
return this.visitor.visitNode(body);
|
|
});
|
|
return fn;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/Identifier.js
|
|
var Identifier = class extends BaseJSNode {
|
|
run() {
|
|
if (this.visitor.listeners[this.node.name]) {
|
|
const cb = this.visitor.listeners[this.node.name](this.node, this.visitor);
|
|
if (cb !== "__continue_exec") {
|
|
return cb;
|
|
}
|
|
}
|
|
if (this.visitor.scope.has(this.node.name))
|
|
return this.visitor.scope.get(this.node.name);
|
|
return this.node.name;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/IfStatement.js
|
|
var IfStatement = class extends BaseJSNode {
|
|
run() {
|
|
const test = this.visitor.visitNode(this.node.test);
|
|
if (test) {
|
|
return this.visitor.visitNode(this.node.consequent);
|
|
} else if (this.node.alternate) {
|
|
return this.visitor.visitNode(this.node.alternate);
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/Literal.js
|
|
var Literal = class extends BaseJSNode {
|
|
run() {
|
|
return this.node.value;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/LogicalExpression.js
|
|
var LogicalExpression = class extends BaseJSNode {
|
|
run() {
|
|
const operator = this.node.operator;
|
|
switch (operator) {
|
|
case "&&": {
|
|
const left_side = this.visitor.visitNode(this.node.left);
|
|
if (left_side === true)
|
|
return this.visitor.visitNode(this.node.right);
|
|
return left_side;
|
|
}
|
|
case "||": {
|
|
const left_side = this.visitor.visitNode(this.node.left);
|
|
return left_side || this.visitor.visitNode(this.node.right);
|
|
}
|
|
case "??": {
|
|
const left_side = this.visitor.visitNode(this.node.left);
|
|
return left_side !== null && left_side !== void 0 ? left_side : this.visitor.visitNode(this.node.right);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/MemberExpression.js
|
|
var MemberExpression = class extends BaseJSNode {
|
|
run() {
|
|
const { object, property, computed } = this.node;
|
|
const obj = this.visitor.visitNode(object);
|
|
const prop = computed ? this.visitor.visitNode(property) : this.visitor.getName(property);
|
|
if (prop !== void 0 || prop !== null) {
|
|
if (this.visitor.listeners[prop]) {
|
|
const cb = this.visitor.listeners[prop](this.node, this.visitor);
|
|
if (cb !== "__continue_exec") {
|
|
return cb;
|
|
}
|
|
}
|
|
return obj === null || obj === void 0 ? void 0 : obj[prop];
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/NewExpression.js
|
|
var NewExpression = class extends BaseJSNode {
|
|
run() {
|
|
const callee = this.visitor.visitNode(this.node.callee);
|
|
const args = this.node.arguments.map((arg) => this.visitor.visitNode(arg));
|
|
return args.length ? new callee(args) : new callee();
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ObjectExpression.js
|
|
var ObjectExpression = class extends BaseJSNode {
|
|
run() {
|
|
let result = {};
|
|
for (const prop of this.node.properties) {
|
|
if (prop.type === "Property") {
|
|
result = Object.assign(Object.assign({}, result), this.visitor.visitNode(prop));
|
|
} else {
|
|
throw new Error(`Unhandled property type: ${prop.type}`);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/Property.js
|
|
var __classPrivateFieldGet2 = function(receiver, state, kind, f) {
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
};
|
|
var _Property_instances;
|
|
var _Property_init;
|
|
var _Property_get;
|
|
var _Property_set;
|
|
var Property = class extends BaseJSNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
_Property_instances.add(this);
|
|
}
|
|
run() {
|
|
switch (this.node.kind) {
|
|
case "init":
|
|
return __classPrivateFieldGet2(this, _Property_instances, "m", _Property_init).call(this);
|
|
case "get":
|
|
return __classPrivateFieldGet2(this, _Property_instances, "m", _Property_get).call(this);
|
|
case "set":
|
|
return __classPrivateFieldGet2(this, _Property_instances, "m", _Property_set).call(this);
|
|
default:
|
|
throw new Error(`Unhandled property kind: ${this.node.kind}`);
|
|
}
|
|
}
|
|
};
|
|
_Property_instances = /* @__PURE__ */ new WeakSet(), _Property_init = function _Property_init2() {
|
|
const key = this.node.computed ? this.visitor.visitNode(this.node.key) : this.visitor.getName(this.node.key);
|
|
const value = this.visitor.visitNode(this.node.value);
|
|
if (key) {
|
|
return { [key]: value };
|
|
}
|
|
}, _Property_get = function _Property_get2() {
|
|
throw new TypeError("Not implemented: Property.get");
|
|
}, _Property_set = function _Property_set2() {
|
|
throw new TypeError("Not implemented: Property.set");
|
|
};
|
|
|
|
// dist/nodes/ReturnStatement.js
|
|
var ReturnStatement = class extends BaseJSNode {
|
|
run() {
|
|
if (this.node.argument) {
|
|
return this.visitor.visitNode(this.node.argument);
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/SequenceExpression.js
|
|
var SequenceExpression = class extends BaseJSNode {
|
|
run() {
|
|
let result;
|
|
for (const expression of this.node.expressions) {
|
|
result = this.visitor.visitNode(expression);
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/SwitchCase.js
|
|
var SwitchCase = class extends BaseJSNode {
|
|
run() {
|
|
for (const stmt of this.node.consequent) {
|
|
const result = this.visitor.visitNode(stmt);
|
|
if (stmt.type === "ContinueStatement" || stmt.type === "BreakStatement") {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/SwitchStatement.js
|
|
var SwitchStatement = class extends BaseJSNode {
|
|
run() {
|
|
const discriminant = this.visitor.visitNode(this.node.discriminant);
|
|
let matched = false;
|
|
let default_case = -1;
|
|
let index = 0;
|
|
while (true) {
|
|
const _case = this.node.cases[index];
|
|
if (matched) {
|
|
const result = this.visitor.visitNode(_case);
|
|
if (result === "break") {
|
|
break;
|
|
}
|
|
if (result === "continue") {
|
|
return result;
|
|
}
|
|
++index;
|
|
if (index >= this.node.cases.length) {
|
|
index = 0;
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
matched = _case && discriminant === this.visitor.visitNode(_case.test);
|
|
if (matched === void 0 && index > this.node.cases.length)
|
|
break;
|
|
if (_case && !matched && !_case.test) {
|
|
default_case = index;
|
|
index += 1;
|
|
continue;
|
|
}
|
|
if (!_case && !matched && default_case !== -1) {
|
|
matched = true;
|
|
index = default_case;
|
|
continue;
|
|
}
|
|
if (!matched) {
|
|
++index;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/TemplateLiteral.js
|
|
var TemplateLiteral = class extends BaseJSNode {
|
|
run() {
|
|
let result = "";
|
|
for (let i = 0; i < this.node.quasis.length; ++i) {
|
|
const quasi = this.node.quasis[i];
|
|
if (quasi.type === "TemplateElement") {
|
|
if (quasi.value.cooked === null) {
|
|
throw new Error(`Invalid template literal: ${quasi.value.raw}`);
|
|
}
|
|
if (quasi.value.cooked !== void 0) {
|
|
result += quasi.value.cooked;
|
|
}
|
|
if (!quasi.tail) {
|
|
const expr = this.node.expressions[i];
|
|
if (expr !== void 0) {
|
|
result += this.visitor.visitNode(expr);
|
|
} else {
|
|
throw new Error(`Expected expression after: ${quasi.value}`);
|
|
}
|
|
}
|
|
} else {
|
|
throw new Error(`Unhandled quasi type: ${quasi.type}`);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ThisExpression.js
|
|
var ThisExpression = class extends BaseJSNode {
|
|
run() {
|
|
return this.visitor.scope.get("_this");
|
|
}
|
|
};
|
|
|
|
// dist/nodes/ThrowStatement.js
|
|
var ThrowStatement = class extends BaseJSNode {
|
|
run() {
|
|
const arg = this.visitor.visitNode(this.node.argument);
|
|
throw arg;
|
|
}
|
|
};
|
|
|
|
// dist/nodes/TryStatement.js
|
|
var TryStatement = class extends BaseJSNode {
|
|
run() {
|
|
try {
|
|
return this.visitor.visitNode(this.node.block);
|
|
} catch (e) {
|
|
if (this.node.handler) {
|
|
if (this.node.handler.param && this.node.handler.param.type === "Identifier") {
|
|
this.visitor.scope.set(this.node.handler.param.name, e);
|
|
}
|
|
return this.visitor.visitNode(this.node.handler.body);
|
|
}
|
|
} finally {
|
|
this.visitor.visitNode(this.node.finalizer);
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/UnaryExpression.js
|
|
var UnaryExpression = class extends BaseJSNode {
|
|
run() {
|
|
const operator = this.node.operator;
|
|
switch (operator) {
|
|
case "-": {
|
|
const arg = this.visitor.visitNode(this.node.argument);
|
|
return -arg;
|
|
}
|
|
case "+": {
|
|
const arg = this.visitor.visitNode(this.node.argument);
|
|
return +arg;
|
|
}
|
|
case "!": {
|
|
const arg = this.visitor.visitNode(this.node.argument);
|
|
return !arg;
|
|
}
|
|
case "~": {
|
|
const arg = this.visitor.visitNode(this.node.argument);
|
|
return ~arg;
|
|
}
|
|
case "void": {
|
|
this.visitor.visitNode(this.node.argument);
|
|
return void 0;
|
|
}
|
|
case "typeof": {
|
|
const arg = this.visitor.visitNode(this.node.argument);
|
|
return typeof arg;
|
|
}
|
|
case "delete": {
|
|
if (this.node.argument.type === "MemberExpression") {
|
|
const obj = this.visitor.visitNode(this.node.argument.object);
|
|
const prop = this.node.argument.computed ? this.visitor.visitNode(this.node.argument.property) : this.visitor.getName(this.node.argument.property);
|
|
return delete obj[prop];
|
|
} else if (this.node.argument.type === "Identifier") {
|
|
return this.visitor.scope.delete(this.node.argument.name);
|
|
}
|
|
return true;
|
|
}
|
|
default:
|
|
console.warn("Unhandled UnaryExpression operator", operator);
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/UpdateExpression.js
|
|
var UpdateExpression = class extends BaseJSNode {
|
|
run() {
|
|
const operator = this.node.operator;
|
|
switch (operator) {
|
|
case "++":
|
|
{
|
|
if (this.node.argument.type === "MemberExpression") {
|
|
const target_node = this.visitor.visitNode(this.node.argument.object);
|
|
return target_node[this.visitor.visitNode(this.node.argument.property)]++;
|
|
} else if (this.node.argument.type === "Identifier") {
|
|
let target_node = this.visitor.visitNode(this.node.argument);
|
|
this.visitor.scope.set(this.node.argument.name, target_node + 1);
|
|
return this.node.prefix ? ++target_node : target_node;
|
|
}
|
|
}
|
|
break;
|
|
case "--":
|
|
{
|
|
if (this.node.argument.type === "MemberExpression") {
|
|
const target_node = this.visitor.visitNode(this.node.argument.object);
|
|
return target_node[this.visitor.visitNode(this.node.argument.property)]--;
|
|
} else if (this.node.argument.type === "Identifier") {
|
|
let target_node = this.visitor.visitNode(this.node.argument);
|
|
this.visitor.scope.set(this.node.argument.name, target_node - 1);
|
|
return this.node.prefix ? --target_node : target_node;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/nodes/VariableDeclaration.js
|
|
var VariableDeclaration = class extends BaseJSNode {
|
|
run() {
|
|
this.node.declarations.forEach((declar) => {
|
|
const { id, init } = declar;
|
|
const key = this.visitor.getName(id);
|
|
const value = init ? this.visitor.visitNode(init) : void 0;
|
|
if (key)
|
|
this.visitor.scope.set(key, value);
|
|
if (typeof value === "object" && value !== null)
|
|
this.visitor.scope.set("_this", value);
|
|
});
|
|
}
|
|
};
|
|
|
|
// dist/nodes/WhileStatement.js
|
|
var WhileStatement = class extends BaseJSNode {
|
|
run() {
|
|
while (this.visitor.visitNode(this.node.test)) {
|
|
const body = this.visitor.visitNode(this.node.body);
|
|
if (body === "break")
|
|
break;
|
|
if (body === "continue")
|
|
continue;
|
|
if (body)
|
|
return body;
|
|
}
|
|
}
|
|
};
|
|
|
|
// dist/visitor.js
|
|
var __classPrivateFieldGet3 = function(receiver, state, kind, f) {
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
};
|
|
var _Visitor_instances;
|
|
var _Visitor_getNode;
|
|
var Visitor = class {
|
|
constructor() {
|
|
_Visitor_instances.add(this);
|
|
this.scope = /* @__PURE__ */ new Map();
|
|
this.listeners = {};
|
|
this.ast = [];
|
|
}
|
|
setAST(ast) {
|
|
this.ast = ast;
|
|
}
|
|
run() {
|
|
let result;
|
|
for (const node of this.ast) {
|
|
result = this.visitNode(node);
|
|
}
|
|
return result;
|
|
}
|
|
/**
|
|
* Visits a given node and executes it.
|
|
*/
|
|
visitNode(node) {
|
|
if (!node)
|
|
return null;
|
|
const target_node = __classPrivateFieldGet3(this, _Visitor_instances, "m", _Visitor_getNode).call(this, node.type);
|
|
if (target_node) {
|
|
const instance = new target_node(node, this);
|
|
return instance.run();
|
|
}
|
|
}
|
|
/**
|
|
* Gets the name of a node.
|
|
* @param node - The target node.
|
|
*/
|
|
getName(node) {
|
|
if (node.type === "Identifier")
|
|
return node.name;
|
|
else if (node.type === "Literal")
|
|
return node.value;
|
|
}
|
|
/**
|
|
* Listens for node calls. Can be used to override default behavior or add new functionality.
|
|
* @param node_name - The node to listen for.
|
|
* @param listener - The callback function.
|
|
*/
|
|
on(node_name, listener) {
|
|
this.listeners[node_name] = listener;
|
|
}
|
|
};
|
|
_Visitor_instances = /* @__PURE__ */ new WeakSet(), _Visitor_getNode = function _Visitor_getNode2(type) {
|
|
const node = nodes_exports[type];
|
|
if (!node) {
|
|
console.warn("[JINTER]:", `JavaScript node "${type}" not implemented!
|
|
If this is causing unexpected behavior, please report it at https://github.com/LuanRT/Jinter/issues/new`);
|
|
}
|
|
return node;
|
|
};
|
|
|
|
// dist/main.js
|
|
var import_acorn = require("acorn");
|
|
var __classPrivateFieldSet = function(receiver, state, value, kind, f) {
|
|
if (kind === "m")
|
|
throw new TypeError("Private method is not writable");
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a setter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
};
|
|
var __classPrivateFieldGet4 = function(receiver, state, kind, f) {
|
|
if (kind === "a" && !f)
|
|
throw new TypeError("Private accessor was defined without a getter");
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
};
|
|
var _Jinter_ast;
|
|
var Jinter = class {
|
|
constructor() {
|
|
_Jinter_ast.set(this, []);
|
|
this.visitor = new Visitor();
|
|
this.scope = this.visitor.scope;
|
|
this.scope.set("print", (args) => console.log(...args));
|
|
this.defineObject("console", console);
|
|
this.defineObject("Math", Math);
|
|
this.defineObject("String", String);
|
|
this.defineObject("Array", Array);
|
|
this.defineObject("Date", Date);
|
|
}
|
|
defineObject(name, obj) {
|
|
this.visitor.on(name, (node, visitor) => {
|
|
if (node.type === "Identifier")
|
|
return obj;
|
|
if (node.type === "CallExpression" && node.callee.type === "MemberExpression") {
|
|
const prop = visitor.visitNode(node.callee.property);
|
|
const args = node.arguments.map((arg) => visitor.visitNode(arg));
|
|
const callable = obj[prop];
|
|
if (!callable)
|
|
return "__continue_exec";
|
|
return callable.apply(obj, args);
|
|
}
|
|
return "__continue_exec";
|
|
});
|
|
}
|
|
/**
|
|
* Generates an AST from the input.
|
|
*/
|
|
parseScript(input) {
|
|
try {
|
|
return (0, import_acorn.parse)(input, { ecmaVersion: 2020 });
|
|
} catch (e) {
|
|
throw new JinterError(e.message);
|
|
}
|
|
}
|
|
/**
|
|
* Evaluates the program.
|
|
* @returns The result of the last statement in the program.
|
|
*/
|
|
evaluate(input) {
|
|
try {
|
|
const program = (0, import_acorn.parse)(input, { ecmaVersion: 2020 });
|
|
__classPrivateFieldSet(this, _Jinter_ast, program.body, "f");
|
|
} catch (e) {
|
|
throw new JinterError(e.message);
|
|
}
|
|
this.visitor.setAST(__classPrivateFieldGet4(this, _Jinter_ast, "f"));
|
|
return this.visitor.run();
|
|
}
|
|
};
|
|
_Jinter_ast = /* @__PURE__ */ new WeakMap();
|
|
|
|
// dist/index.js
|
|
var dist_default = Jinter;
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
Jinter,
|
|
Nodes,
|
|
Utils
|
|
});
|
|
//# sourceMappingURL=jinter.cjs.map
|