Comparing version 1.3.1 to 1.4.0
@@ -16,3 +16,3 @@ "use strict"; | ||
var version = "1.3.1"; | ||
var version = "1.4.0"; | ||
@@ -33,4 +33,2 @@ function defineFunctionName(func, name) { | ||
var EmptyStatementReturn = Symbol("EmptyStatementReturn"); | ||
var IEval = Symbol("IEval"); | ||
var IFunction = Symbol("IFunction"); | ||
@@ -41,2 +39,100 @@ function isFunction(func) { | ||
var InternalInternalReflection = | ||
/*#__PURE__*/ | ||
function () { | ||
function InternalInternalReflection(interpreter) { | ||
this.interpreter = interpreter; | ||
} | ||
var _proto = InternalInternalReflection.prototype; | ||
_proto.generator = function generator() { | ||
var interpreter = this.interpreter; | ||
function getCurrentScope() { | ||
return this.getCurrentScope(); | ||
} | ||
function getGlobalScope() { | ||
return this.getGlobalScope(); | ||
} | ||
function getCurrentContext() { | ||
return this.getCurrentContext(); | ||
} | ||
return { | ||
getOptions: interpreter.getOptions.bind(interpreter), | ||
getCurrentScope: getCurrentScope.bind(interpreter), | ||
getGlobalScope: getGlobalScope.bind(interpreter), | ||
getCurrentContext: getCurrentContext.bind(interpreter), | ||
getExecStartTime: interpreter.getExecStartTime.bind(interpreter) | ||
}; | ||
}; | ||
return InternalInternalReflection; | ||
}(); | ||
function internalEval(reflection, code, useGlobalScope) { | ||
if (useGlobalScope === void 0) { | ||
useGlobalScope = true; | ||
} | ||
if (!(reflection instanceof InternalInternalReflection)) { | ||
throw new Error("Illegal call"); | ||
} | ||
if (typeof code !== "string") return code; | ||
if (!code) return void 0; | ||
var instance = reflection.generator(); | ||
var opts = instance.getOptions(); | ||
var options = { | ||
timeout: opts.timeout, | ||
_initEnv: function _initEnv() { | ||
// set caller context | ||
if (!useGlobalScope) { | ||
this.setCurrentContext(instance.getCurrentContext()); | ||
} // share timeout | ||
this.execStartTime = instance.getExecStartTime(); | ||
this.execEndTime = this.execStartTime; | ||
} | ||
}; | ||
var currentScope = useGlobalScope ? instance.getGlobalScope() : instance.getCurrentScope(); | ||
var interpreter = new Interpreter(currentScope, options); | ||
return interpreter.evaluate(code); | ||
} | ||
Object.defineProperty(internalEval, "__IS_EVAL_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
function internalFunction(reflection) { | ||
if (!(reflection instanceof InternalInternalReflection)) { | ||
throw new Error("Illegal call"); | ||
} | ||
var instance = reflection.generator(); | ||
for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
params[_key - 1] = arguments[_key]; | ||
} | ||
var code = params.pop(); | ||
var interpreter = new Interpreter(instance.getGlobalScope(), instance.getOptions()); | ||
var wrapCode = "\n\t\t (function anonymous(" + params.join(",") + "){\n\t\t " + code + "\n\t\t });\n\t\t "; | ||
return interpreter.evaluate(wrapCode); | ||
} | ||
Object.defineProperty(internalFunction, "__IS_FUNCTION_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
var Return = function Return(value) { | ||
@@ -53,3 +149,16 @@ this.value = value; | ||
}; | ||
/** | ||
* scope chain | ||
* | ||
* superScope | ||
* ↓ | ||
* rootScope | ||
* ↓ | ||
* globalScope | ||
* ↓ | ||
* functionScope | ||
* | ||
*/ | ||
var Scope = function Scope(data, parent, name) { | ||
@@ -100,3 +209,5 @@ if (parent === void 0) { | ||
escape: escape, | ||
unescape: unescape | ||
unescape: unescape, | ||
eval: internalEval, | ||
Function: internalFunction | ||
}; // ES5 Object | ||
@@ -162,12 +273,14 @@ | ||
timeout: options.timeout || 0, | ||
initEnv: options.initEnv | ||
rootContext: options.rootContext, | ||
globalContextInFunction: options.globalContextInFunction === undefined ? Interpreter.globalContextInFunction : options.globalContextInFunction, | ||
_initEnv: options._initEnv | ||
}; | ||
this.context = context; | ||
this.context = context || Object.create(null); | ||
this.callStack = []; | ||
this.initEnvironment(context); | ||
this.initEnvironment(this.context); | ||
} | ||
var _proto = Interpreter.prototype; | ||
var _proto2 = Interpreter.prototype; | ||
_proto.initEnvironment = function initEnvironment(ctx) { | ||
_proto2.initEnvironment = function initEnvironment(ctx) { | ||
var scope; //init global scope | ||
@@ -178,20 +291,16 @@ | ||
} else { | ||
var superScope = this.getSuperScope(ctx); // replace Interpreter.eval and Interpreter.Function | ||
var rootScope = null; | ||
var superScope = this.createSuperScope(ctx); | ||
Object.keys(ctx).forEach(function (key) { | ||
if (ctx[key] === IEval) { | ||
ctx[key] = superScope.data[IEval]; | ||
} | ||
if (this.options.rootContext) { | ||
rootScope = new Scope(this.options.rootContext, superScope, "rootScope"); | ||
} | ||
if (ctx[key] === IFunction) { | ||
ctx[key] = superScope.data[IFunction]; | ||
} | ||
}); | ||
scope = new Scope(ctx, superScope, "root"); | ||
scope = new Scope(ctx, rootScope || superScope, "globalScope"); | ||
} | ||
this.rootScope = scope; | ||
this.currentScope = this.rootScope; //init global context == this | ||
this.globalScope = scope; | ||
this.currentScope = this.globalScope; //init global context to this | ||
this.rootContext = scope.data; | ||
this.globalContext = scope.data; | ||
this.currentContext = scope.data; // collect var/function declare | ||
@@ -203,69 +312,48 @@ | ||
this.execEndTime = this.execStartTime; | ||
var initEnv = this.options.initEnv; | ||
var _initEnv = this.options._initEnv; | ||
if (initEnv) { | ||
initEnv(this); | ||
if (_initEnv) { | ||
_initEnv.call(this); | ||
} | ||
}; | ||
_proto.isInterruptThrow = function isInterruptThrow(err) { | ||
return err instanceof _messages.InterruptThrowError || err instanceof _messages.InterruptThrowReferenceError || err instanceof _messages.InterruptThrowSyntaxError; | ||
_proto2.getExecStartTime = function getExecStartTime() { | ||
return this.execStartTime; | ||
}; | ||
_proto.getSuperScope = function getSuperScope(ctx) { | ||
var _this = this; | ||
_proto2.getExecutionTime = function getExecutionTime() { | ||
return this.execEndTime - this.execStartTime; | ||
}; | ||
var data = Object.assign({}, BuildInObjects); | ||
_proto2.setExecTimeout = function setExecTimeout(timeout) { | ||
if (timeout === void 0) { | ||
timeout = 0; | ||
} | ||
data.eval = function (code, useGlobalScope) { | ||
if (useGlobalScope === void 0) { | ||
useGlobalScope = true; | ||
} | ||
this.options.timeout = timeout; | ||
}; | ||
if (typeof code !== "string") return code; | ||
if (!code) return void 0; | ||
var options = { | ||
timeout: _this.options.timeout, | ||
initEnv: function initEnv(inst) { | ||
// set caller context | ||
if (!useGlobalScope) { | ||
inst.setCurrentContext(_this.getCurrentContext()); | ||
} | ||
_proto2.getOptions = function getOptions() { | ||
return this.options; | ||
}; | ||
inst.execStartTime = _this.execStartTime; | ||
inst.execEndTime = inst.execStartTime; | ||
} | ||
}; | ||
var currentScope = useGlobalScope ? _this.rootScope : _this.getCurrentScope(); | ||
var interpreter = new Interpreter(currentScope, options); | ||
return interpreter.evaluate(code); | ||
}; | ||
_proto2.getGlobalScope = function getGlobalScope() { | ||
return this.globalScope; | ||
}; | ||
Object.defineProperty(data.eval, "__IS_EVAL_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
_proto2.getCurrentScope = function getCurrentScope() { | ||
return this.currentScope; | ||
}; | ||
data.Function = function () { | ||
for (var _len = arguments.length, params = new Array(_len), _key = 0; _key < _len; _key++) { | ||
params[_key] = arguments[_key]; | ||
} | ||
_proto2.getCurrentContext = function getCurrentContext() { | ||
return this.currentContext; | ||
}; | ||
var code = params.pop(); | ||
var interpreter = new Interpreter(_this.rootScope, _this.options); | ||
var wrapCode = "\n\t\t (function anonymous(" + params.join(",") + "){\n\t\t " + code + "\n\t\t });\n\t\t "; | ||
return interpreter.evaluate(wrapCode); | ||
}; | ||
_proto2.isInterruptThrow = function isInterruptThrow(err) { | ||
return err instanceof _messages.InterruptThrowError || err instanceof _messages.InterruptThrowReferenceError || err instanceof _messages.InterruptThrowSyntaxError; | ||
}; | ||
Object.defineProperty(data.Function, "__IS_FUNCTION_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
_proto2.createSuperScope = function createSuperScope(ctx) { | ||
var data = Object.assign({}, BuildInObjects); | ||
var buildInObjectKeys = Object.keys(data); | ||
data[IEval] = data.eval; | ||
data[IFunction] = data.Function; | ||
buildInObjectKeys.forEach(function (key) { | ||
@@ -276,14 +364,14 @@ if (key in ctx) { | ||
}); | ||
return new Scope(data, null, "superRoot"); | ||
return new Scope(data, null, "superScope"); | ||
}; | ||
_proto.setCurrentContext = function setCurrentContext(ctx) { | ||
_proto2.setCurrentContext = function setCurrentContext(ctx) { | ||
this.currentContext = ctx; | ||
}; | ||
_proto.setCurrentScope = function setCurrentScope(scope) { | ||
_proto2.setCurrentScope = function setCurrentScope(scope) { | ||
this.currentScope = scope; | ||
}; | ||
_proto.evaluate = function evaluate(code) { | ||
_proto2.evaluate = function evaluate(code) { | ||
if (code === void 0) { | ||
@@ -303,7 +391,7 @@ code = ""; | ||
_proto.appendCode = function appendCode(code) { | ||
_proto2.appendCode = function appendCode(code) { | ||
return this.evaluate(code); | ||
}; | ||
_proto.evaluateNode = function evaluateNode(node, source) { | ||
_proto2.evaluateNode = function evaluateNode(node, source) { | ||
if (source === void 0) { | ||
@@ -336,7 +424,3 @@ source = ""; | ||
_proto.getExecutionTime = function getExecutionTime() { | ||
return this.execEndTime - this.execStartTime; | ||
}; | ||
_proto.createErrorMessage = function createErrorMessage(msg, value, node) { | ||
_proto2.createErrorMessage = function createErrorMessage(msg, value, node) { | ||
var message = msg[1].replace("%0", String(value)); | ||
@@ -351,23 +435,15 @@ | ||
_proto.createError = function createError(message, error) { | ||
_proto2.createError = function createError(message, error) { | ||
return new error(message); | ||
}; | ||
_proto.createThrowError = function createThrowError(message, error) { | ||
_proto2.createThrowError = function createThrowError(message, error) { | ||
return this.createError(message, error); | ||
}; | ||
_proto.createInternalThrowError = function createInternalThrowError(msg, value, node) { | ||
_proto2.createInternalThrowError = function createInternalThrowError(msg, value, node) { | ||
return this.createError(this.createErrorMessage(msg, value, node), msg[2]); | ||
}; | ||
_proto.setExecTimeout = function setExecTimeout(timeout) { | ||
if (timeout === void 0) { | ||
timeout = 0; | ||
} | ||
this.options.timeout = timeout; | ||
}; | ||
_proto.checkTimeout = function checkTimeout() { | ||
_proto2.checkTimeout = function checkTimeout() { | ||
if (!this.isRunning) return false; | ||
@@ -384,3 +460,3 @@ var timeout = this.options.timeout || 0; | ||
_proto.getNodePosition = function getNodePosition(node) { | ||
_proto2.getNodePosition = function getNodePosition(node) { | ||
if (node) { | ||
@@ -395,4 +471,4 @@ var errorCode = ""; //this.source.slice(node.start, node.end); | ||
_proto.createClosure = function createClosure(node) { | ||
var _this2 = this; | ||
_proto2.createClosure = function createClosure(node) { | ||
var _this = this; | ||
@@ -548,9 +624,9 @@ var closure; | ||
return function () { | ||
var timeout = _this2.options.timeout; | ||
var timeout = _this.options.timeout; | ||
if (timeout && timeout > 0 && _this2.checkTimeout()) { | ||
throw _this2.createInternalThrowError(_messages.Messages.ExecutionTimeOutError, timeout, null); | ||
if (timeout && timeout > 0 && _this.checkTimeout()) { | ||
throw _this.createInternalThrowError(_messages.Messages.ExecutionTimeOutError, timeout, null); | ||
} | ||
_this2.lastExecNode = node; | ||
_this.lastExecNode = node; | ||
return closure.apply(void 0, arguments); | ||
@@ -561,4 +637,4 @@ }; | ||
_proto.binaryExpressionHandler = function binaryExpressionHandler(node) { | ||
var _this3 = this; | ||
_proto2.binaryExpressionHandler = function binaryExpressionHandler(node) { | ||
var _this2 = this; | ||
@@ -639,3 +715,3 @@ var leftExpression = this.createClosure(node.left); | ||
default: | ||
throw _this3.createInternalThrowError(_messages.Messages.BinaryOperatorSyntaxError, node.operator, node); | ||
throw _this2.createInternalThrowError(_messages.Messages.BinaryOperatorSyntaxError, node.operator, node); | ||
} | ||
@@ -646,4 +722,4 @@ }; | ||
_proto.logicalExpressionHandler = function logicalExpressionHandler(node) { | ||
var _this4 = this; | ||
_proto2.logicalExpressionHandler = function logicalExpressionHandler(node) { | ||
var _this3 = this; | ||
@@ -661,10 +737,19 @@ var leftExpression = this.createClosure(node.left); | ||
default: | ||
throw _this4.createInternalThrowError(_messages.Messages.LogicalOperatorSyntaxError, node.operator, node); | ||
throw _this3.createInternalThrowError(_messages.Messages.LogicalOperatorSyntaxError, node.operator, node); | ||
} | ||
}; | ||
}; | ||
_proto2.isRootScope = function isRootScope(node) { | ||
if (node.type === "Identifier") { | ||
var scope = this.getScopeFromName(node.name, this.getCurrentScope()); | ||
return scope.name === "rootScope"; | ||
} | ||
return false; | ||
} // typeof a !a() | ||
; | ||
_proto.unaryExpressionHandler = function unaryExpressionHandler(node) { | ||
var _this5 = this; | ||
_proto2.unaryExpressionHandler = function unaryExpressionHandler(node) { | ||
var _this4 = this; | ||
@@ -676,2 +761,7 @@ switch (node.operator) { | ||
return function () { | ||
// not allowed to delete root scope property | ||
if (_this4.isRootScope(node.argument)) { | ||
return false; | ||
} | ||
var obj = objectGetter(); | ||
@@ -721,3 +811,3 @@ var name = nameGetter(); | ||
default: | ||
throw _this5.createInternalThrowError(_messages.Messages.UnaryOperatorSyntaxError, node.operator, node); | ||
throw _this4.createInternalThrowError(_messages.Messages.UnaryOperatorSyntaxError, node.operator, node); | ||
} | ||
@@ -729,4 +819,4 @@ }; | ||
_proto.updateExpressionHandler = function updateExpressionHandler(node) { | ||
var _this6 = this; | ||
_proto2.updateExpressionHandler = function updateExpressionHandler(node) { | ||
var _this5 = this; | ||
@@ -739,3 +829,3 @@ var objectGetter = this.createObjectGetter(node.argument); | ||
_this6.assertVariable(obj, name, node); | ||
_this5.assertVariable(obj, name, node); | ||
@@ -750,3 +840,3 @@ switch (node.operator) { | ||
default: | ||
throw _this6.createInternalThrowError(_messages.Messages.UpdateOperatorSyntaxError, node.operator, node); | ||
throw _this5.createInternalThrowError(_messages.Messages.UpdateOperatorSyntaxError, node.operator, node); | ||
} | ||
@@ -757,4 +847,4 @@ }; | ||
_proto.objectExpressionHandler = function objectExpressionHandler(node) { | ||
var _this7 = this; | ||
_proto2.objectExpressionHandler = function objectExpressionHandler(node) { | ||
var _this6 = this; | ||
@@ -785,3 +875,3 @@ var items = []; | ||
properties[key][kind] = _this7.createClosure(property.value); | ||
properties[key][kind] = _this6.createClosure(property.value); | ||
items.push({ | ||
@@ -831,8 +921,8 @@ key: key, | ||
_proto.arrayExpressionHandler = function arrayExpressionHandler(node) { | ||
var _this8 = this; | ||
_proto2.arrayExpressionHandler = function arrayExpressionHandler(node) { | ||
var _this7 = this; | ||
//fix: [,,,1,2] | ||
var items = node.elements.map(function (element) { | ||
return element ? _this8.createClosure(element) : element; | ||
return element ? _this7.createClosure(element) : element; | ||
}); | ||
@@ -855,8 +945,8 @@ return function () { | ||
_proto.safeObjectGet = function safeObjectGet(obj, key, node) { | ||
_proto2.safeObjectGet = function safeObjectGet(obj, key, node) { | ||
return obj[key]; | ||
}; | ||
_proto.createCallFunctionGetter = function createCallFunctionGetter(node) { | ||
var _this9 = this; | ||
_proto2.createCallFunctionGetter = function createCallFunctionGetter(node) { | ||
var _this8 = this; | ||
@@ -872,18 +962,38 @@ switch (node.type) { | ||
var func = _this9.safeObjectGet(obj, key, node); | ||
var func = _this8.safeObjectGet(obj, key, node); | ||
if (!func || !isFunction(func)) { | ||
var name = source.slice(node.start, node.end); | ||
throw _this9.createInternalThrowError(_messages.Messages.FunctionUndefinedReferenceError, name, node); | ||
} | ||
throw _this8.createInternalThrowError(_messages.Messages.FunctionUndefinedReferenceError, name, node); | ||
} // obj.eval = eval | ||
// obj.eval(...) | ||
if (func.__IS_EVAL_FUNC) { | ||
return function (code) { | ||
return func(code, true); | ||
return func(new InternalInternalReflection(_this8), code, true); | ||
}; | ||
} // obj.func = Function | ||
// obj.func(...) | ||
if (func.__IS_FUNCTION_FUNC) { | ||
return function () { | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
return func.apply(void 0, [new InternalInternalReflection(_this8)].concat(args)); | ||
}; | ||
} // method call | ||
// eg:obj.say(...) | ||
// eg: obj.say.call(...) | ||
// eg: obj.say.apply(...) | ||
// ====================== | ||
// obj.func(...) | ||
// func = func.bind(obj) | ||
// tips: | ||
// test.call(ctx, ...) === test.call.bind(test)(ctx, ...) | ||
// test.apply(ctx, ...) === test.apply.bind(test)(ctx, ...) | ||
// test.f(...) === test.f.bind(test)(...) | ||
// func(...) -> func.bind(obj)(...) | ||
// func.call(...) -> obj.func.call.bind(obj.func)(...) | ||
// func.apply(...) -> obj.func.apply.bind(obj.func)(...) | ||
// ...others | ||
@@ -896,3 +1006,3 @@ | ||
default: | ||
// test() or (0.test)() or a[1]() ... | ||
// test() or (0,test)() or a[1]() ... | ||
var closure = this.createClosure(node); | ||
@@ -910,17 +1020,39 @@ return function () { | ||
if (!func || !isFunction(func)) { | ||
throw _this9.createInternalThrowError(_messages.Messages.FunctionUndefinedReferenceError, name, node); | ||
throw _this8.createInternalThrowError(_messages.Messages.FunctionUndefinedReferenceError, name, node); | ||
} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval | ||
// calling eval scope check | ||
// var geval = eval; | ||
// geval("a+1"); | ||
// var eval = eval; | ||
// function test(){ | ||
// eval(...); //note: use local scope in eval5,but in Browser is use global scope | ||
// } | ||
if (node.type === "Identifier" && func.__IS_EVAL_FUNC) { | ||
if (node.type === "Identifier" && func.__IS_EVAL_FUNC && name === "eval") { | ||
return function (code) { | ||
var scope = _this9.getScopeFromName(name, _this9.getCurrentScope()); | ||
var scope = _this8.getScopeFromName(name, _this8.getCurrentScope()); | ||
var isSuperScope = !scope.parent || _this9.rootScope === scope; // use local scope if calling eval in super scope | ||
var useGlobalScope = !scope.parent || _this8.globalScope === scope || scope.name === "rootScope"; // use local scope if calling eval in super scope | ||
return func(code, !isSuperScope); | ||
return func(new InternalInternalReflection(_this8), code, !useGlobalScope); | ||
}; | ||
} // use global scope | ||
// var g_eval = eval; | ||
// g_eval("a+1"); | ||
//(0,eval)(...) ...eval alias | ||
if (func.__IS_EVAL_FUNC) { | ||
return function (code) { | ||
return func(new InternalInternalReflection(_this8), code, true); | ||
}; | ||
} // Function('a', 'b', 'return a+b') | ||
if (func.__IS_FUNCTION_FUNC) { | ||
return function () { | ||
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
return func.apply(void 0, [new InternalInternalReflection(_this8)].concat(args)); | ||
}; | ||
} // function call | ||
@@ -930,5 +1062,6 @@ // this = undefined | ||
// test(...) === test.call(undefined, ...) | ||
// fix: alert.call({}, ...) Illegal invocation | ||
return func.bind(Interpreter.rootContext); | ||
return func.bind(_this8.options.globalContextInFunction); | ||
}; | ||
@@ -939,8 +1072,8 @@ } | ||
_proto.callExpressionHandler = function callExpressionHandler(node) { | ||
var _this10 = this; | ||
_proto2.callExpressionHandler = function callExpressionHandler(node) { | ||
var _this9 = this; | ||
var funcGetter = this.createCallFunctionGetter(node.callee); | ||
var argsGetter = node.arguments.map(function (arg) { | ||
return _this10.createClosure(arg); | ||
return _this9.createClosure(arg); | ||
}); | ||
@@ -955,4 +1088,4 @@ return function () { | ||
_proto.functionExpressionHandler = function functionExpressionHandler(node) { | ||
var _this11 = this; | ||
_proto2.functionExpressionHandler = function functionExpressionHandler(node) { | ||
var _this10 = this; | ||
@@ -970,3 +1103,3 @@ var self = this; | ||
var paramsGetter = node.params.map(function (param) { | ||
return _this11.createParamNameGetter(param); | ||
return _this10.createParamNameGetter(param); | ||
}); // set scope | ||
@@ -984,4 +1117,4 @@ | ||
var func = function func() { | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | ||
args[_key4] = arguments[_key4]; | ||
} | ||
@@ -1051,4 +1184,4 @@ | ||
_proto.newExpressionHandler = function newExpressionHandler(node) { | ||
var _this12 = this; | ||
_proto2.newExpressionHandler = function newExpressionHandler(node) { | ||
var _this11 = this; | ||
@@ -1058,3 +1191,3 @@ var source = this.source; | ||
var args = node.arguments.map(function (arg) { | ||
return _this12.createClosure(arg); | ||
return _this11.createClosure(arg); | ||
}); | ||
@@ -1064,6 +1197,13 @@ return function () { | ||
if (!isFunction(construct)) { | ||
if (!isFunction(construct) || construct.__IS_EVAL_FUNC) { | ||
var callee = node.callee; | ||
var name = source.slice(callee.start, callee.end); | ||
throw _this12.createInternalThrowError(_messages.Messages.IsNotConstructor, name, node); | ||
throw _this11.createInternalThrowError(_messages.Messages.IsNotConstructor, name, node); | ||
} // new Function(...) | ||
if (construct.__IS_FUNCTION_FUNC) { | ||
return construct.apply(void 0, [new InternalInternalReflection(_this11)].concat(args.map(function (arg) { | ||
return arg(); | ||
}))); | ||
} | ||
@@ -1078,3 +1218,3 @@ | ||
_proto.memberExpressionHandler = function memberExpressionHandler(node) { | ||
_proto2.memberExpressionHandler = function memberExpressionHandler(node) { | ||
var objectGetter = this.createClosure(node.object); | ||
@@ -1090,7 +1230,7 @@ var keyGetter = this.createMemberKeyGetter(node); | ||
_proto.thisExpressionHandler = function thisExpressionHandler(node) { | ||
var _this13 = this; | ||
_proto2.thisExpressionHandler = function thisExpressionHandler(node) { | ||
var _this12 = this; | ||
return function () { | ||
return _this13.getCurrentContext(); | ||
return _this12.getCurrentContext(); | ||
}; | ||
@@ -1100,7 +1240,7 @@ } // var1,var2,... | ||
_proto.sequenceExpressionHandler = function sequenceExpressionHandler(node) { | ||
var _this14 = this; | ||
_proto2.sequenceExpressionHandler = function sequenceExpressionHandler(node) { | ||
var _this13 = this; | ||
var expressions = node.expressions.map(function (item) { | ||
return _this14.createClosure(item); | ||
return _this13.createClosure(item); | ||
}); | ||
@@ -1121,3 +1261,3 @@ return function () { | ||
_proto.literalHandler = function literalHandler(node) { | ||
_proto2.literalHandler = function literalHandler(node) { | ||
return function () { | ||
@@ -1133,11 +1273,11 @@ if (node.regex) { | ||
_proto.identifierHandler = function identifierHandler(node) { | ||
var _this15 = this; | ||
_proto2.identifierHandler = function identifierHandler(node) { | ||
var _this14 = this; | ||
return function () { | ||
var currentScope = _this15.getCurrentScope(); | ||
var currentScope = _this14.getCurrentScope(); | ||
var data = _this15.getScopeDataFromName(node.name, currentScope); | ||
var data = _this14.getScopeDataFromName(node.name, currentScope); | ||
_this15.assertVariable(data, node.name, node); | ||
_this14.assertVariable(data, node.name, node); | ||
@@ -1149,4 +1289,4 @@ return data[node.name]; | ||
_proto.assignmentExpressionHandler = function assignmentExpressionHandler(node) { | ||
var _this16 = this; | ||
_proto2.assignmentExpressionHandler = function assignmentExpressionHandler(node) { | ||
var _this15 = this; | ||
@@ -1172,3 +1312,3 @@ // var s = function(){} | ||
// var1(undefined) += 1 | ||
_this16.assertVariable(data, name, node); | ||
_this15.assertVariable(data, name, node); | ||
} | ||
@@ -1232,3 +1372,3 @@ | ||
default: | ||
throw _this16.createInternalThrowError(_messages.Messages.AssignmentExpressionSyntaxError, node.type, node); | ||
throw _this15.createInternalThrowError(_messages.Messages.AssignmentExpressionSyntaxError, node.type, node); | ||
} | ||
@@ -1242,3 +1382,3 @@ | ||
_proto.functionDeclarationHandler = function functionDeclarationHandler(node) { | ||
_proto2.functionDeclarationHandler = function functionDeclarationHandler(node) { | ||
if (node.id) { | ||
@@ -1260,3 +1400,3 @@ var functionClosure = this.functionExpressionHandler(node); | ||
_proto.getVariableName = function getVariableName(node) { | ||
_proto2.getVariableName = function getVariableName(node) { | ||
if (node.type === "Identifier") { | ||
@@ -1271,4 +1411,4 @@ return node.name; | ||
_proto.variableDeclarationHandler = function variableDeclarationHandler(node) { | ||
var _this17 = this; | ||
_proto2.variableDeclarationHandler = function variableDeclarationHandler(node) { | ||
var _this16 = this; | ||
@@ -1301,5 +1441,5 @@ var assignmentsClosure; | ||
if (assignmentsClosure) { | ||
_this17.isVarDeclMode = true; | ||
_this16.isVarDeclMode = true; | ||
assignmentsClosure(); | ||
_this17.isVarDeclMode = false; | ||
_this16.isVarDeclMode = false; | ||
} | ||
@@ -1311,4 +1451,4 @@ | ||
_proto.assertVariable = function assertVariable(data, name, node) { | ||
if (data === this.rootScope.data && !(name in data)) { | ||
_proto2.assertVariable = function assertVariable(data, name, node) { | ||
if (data === this.globalScope.data && !(name in data)) { | ||
throw this.createInternalThrowError(_messages.Messages.VariableUndefinedReferenceError, name, node); | ||
@@ -1319,4 +1459,4 @@ } | ||
_proto.programHandler = function programHandler(node) { | ||
var _this18 = this; | ||
_proto2.programHandler = function programHandler(node) { | ||
var _this17 = this; | ||
@@ -1326,3 +1466,3 @@ // const currentScope = this.getCurrentScope(); | ||
// if (stmt.type === "EmptyStatement") return null; | ||
return _this18.createClosure(stmt); | ||
return _this17.createClosure(stmt); | ||
}); | ||
@@ -1335,3 +1475,3 @@ return function () { | ||
var ret = _this18.setValue(stmtClosure()); // if (!stmtClosure) continue; | ||
var ret = _this17.setValue(stmtClosure()); // if (!stmtClosure) continue; | ||
// EmptyStatement | ||
@@ -1355,7 +1495,7 @@ | ||
_proto.expressionStatementHandler = function expressionStatementHandler(node) { | ||
_proto2.expressionStatementHandler = function expressionStatementHandler(node) { | ||
return this.createClosure(node.expression); | ||
}; | ||
_proto.emptyStatementHandler = function emptyStatementHandler(node) { | ||
_proto2.emptyStatementHandler = function emptyStatementHandler(node) { | ||
return function () { | ||
@@ -1367,3 +1507,3 @@ return EmptyStatementReturn; | ||
_proto.returnStatementHandler = function returnStatementHandler(node) { | ||
_proto2.returnStatementHandler = function returnStatementHandler(node) { | ||
var argumentClosure = node.argument ? this.createClosure(node.argument) : noop; | ||
@@ -1376,3 +1516,3 @@ return function () { | ||
_proto.ifStatementHandler = function ifStatementHandler(node) { | ||
_proto2.ifStatementHandler = function ifStatementHandler(node) { | ||
var testClosure = this.createClosure(node.test); | ||
@@ -1391,3 +1531,3 @@ var consequentClosure = this.createClosure(node.consequent); | ||
_proto.conditionalExpressionHandler = function conditionalExpressionHandler(node) { | ||
_proto2.conditionalExpressionHandler = function conditionalExpressionHandler(node) { | ||
return this.ifStatementHandler(node); | ||
@@ -1397,4 +1537,4 @@ } // for(var i = 0; i < 10; i++) {...} | ||
_proto.forStatementHandler = function forStatementHandler(node) { | ||
var _this19 = this; | ||
_proto2.forStatementHandler = function forStatementHandler(node) { | ||
var _this18 = this; | ||
@@ -1425,3 +1565,3 @@ var initClosure = noop; | ||
var ret = _this19.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
var ret = _this18.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
@@ -1452,12 +1592,12 @@ | ||
_proto.whileStatementHandler = function whileStatementHandler(node) { | ||
_proto2.whileStatementHandler = function whileStatementHandler(node) { | ||
return this.forStatementHandler(node); | ||
}; | ||
_proto.doWhileStatementHandler = function doWhileStatementHandler(node) { | ||
_proto2.doWhileStatementHandler = function doWhileStatementHandler(node) { | ||
return this.forStatementHandler(node); | ||
}; | ||
_proto.forInStatementHandler = function forInStatementHandler(node) { | ||
var _this20 = this; | ||
_proto2.forInStatementHandler = function forInStatementHandler(node) { | ||
var _this19 = this; | ||
@@ -1492,3 +1632,3 @@ // for( k in obj) or for(o.k in obj) ... | ||
// o.k = x | ||
_this20.assignmentExpressionHandler({ | ||
_this19.assignmentExpressionHandler({ | ||
type: "AssignmentExpression", | ||
@@ -1504,3 +1644,3 @@ operator: "=", | ||
var ret = _this20.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
var ret = _this19.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
@@ -1530,4 +1670,4 @@ | ||
_proto.withStatementHandler = function withStatementHandler(node) { | ||
var _this21 = this; | ||
_proto2.withStatementHandler = function withStatementHandler(node) { | ||
var _this20 = this; | ||
@@ -1537,7 +1677,7 @@ var objectClosure = this.createClosure(node.object); | ||
return function () { | ||
var currentScope = _this21.getCurrentScope(); | ||
var currentScope = _this20.getCurrentScope(); | ||
var newScope = createScope(currentScope, "with"); | ||
var data = objectClosure(); // newScope.data = data; | ||
// copy all property | ||
// copy all properties | ||
@@ -1548,8 +1688,8 @@ for (var k in data) { | ||
_this21.setCurrentScope(newScope); // save last value | ||
_this20.setCurrentScope(newScope); // save last value | ||
var result = _this21.setValue(bodyClosure()); | ||
var result = _this20.setValue(bodyClosure()); | ||
_this21.setCurrentScope(currentScope); | ||
_this20.setCurrentScope(currentScope); | ||
@@ -1560,8 +1700,8 @@ return result; | ||
_proto.throwStatementHandler = function throwStatementHandler(node) { | ||
var _this22 = this; | ||
_proto2.throwStatementHandler = function throwStatementHandler(node) { | ||
var _this21 = this; | ||
var argumentClosure = this.createClosure(node.argument); | ||
return function () { | ||
_this22.setValue(undefined); | ||
_this21.setValue(undefined); | ||
@@ -1573,4 +1713,4 @@ throw argumentClosure(); | ||
_proto.tryStatementHandler = function tryStatementHandler(node) { | ||
var _this23 = this; | ||
_proto2.tryStatementHandler = function tryStatementHandler(node) { | ||
var _this22 = this; | ||
@@ -1581,9 +1721,9 @@ var blockClosure = this.createClosure(node.block); | ||
return function () { | ||
var currentScope = _this23.getCurrentScope(); | ||
var currentScope = _this22.getCurrentScope(); | ||
var currentContext = _this23.getCurrentContext(); | ||
var currentContext = _this22.getCurrentContext(); | ||
var labelStack = currentScope.labelStack.concat([]); | ||
var callStack = _this23.callStack.concat([]); | ||
var callStack = _this22.callStack.concat([]); | ||
@@ -1595,6 +1735,6 @@ var result = EmptyStatementReturn; | ||
var reset = function reset() { | ||
_this23.setCurrentScope(currentScope); //reset scope | ||
_this22.setCurrentScope(currentScope); //reset scope | ||
_this23.setCurrentContext(currentContext); //reset context | ||
_this22.setCurrentContext(currentContext); //reset context | ||
@@ -1604,3 +1744,3 @@ | ||
_this23.callStack = callStack; //reset call stack | ||
_this22.callStack = callStack; //reset call stack | ||
}; | ||
@@ -1620,3 +1760,3 @@ /** | ||
try { | ||
result = _this23.setValue(blockClosure()); | ||
result = _this22.setValue(blockClosure()); | ||
@@ -1629,3 +1769,3 @@ if (result instanceof Return) { | ||
if (_this23.isInterruptThrow(err)) { | ||
if (_this22.isInterruptThrow(err)) { | ||
throw err; | ||
@@ -1636,3 +1776,3 @@ } | ||
try { | ||
result = _this23.setValue(handlerClosure(err)); | ||
result = _this22.setValue(handlerClosure(err)); | ||
@@ -1645,3 +1785,3 @@ if (result instanceof Return) { | ||
if (_this23.isInterruptThrow(err)) { | ||
if (_this22.isInterruptThrow(err)) { | ||
throw err; | ||
@@ -1669,3 +1809,3 @@ } // save catch throw error | ||
if (_this23.isInterruptThrow(err)) { | ||
if (_this22.isInterruptThrow(err)) { | ||
throw err; | ||
@@ -1694,4 +1834,4 @@ } // save finally throw error | ||
_proto.catchClauseHandler = function catchClauseHandler(node) { | ||
var _this24 = this; | ||
_proto2.catchClauseHandler = function catchClauseHandler(node) { | ||
var _this23 = this; | ||
@@ -1703,3 +1843,3 @@ var paramNameGetter = this.createParamNameGetter(node.param); | ||
var currentScope = _this24.getCurrentScope(); | ||
var currentScope = _this23.getCurrentScope(); | ||
@@ -1729,3 +1869,3 @@ var scopeData = currentScope.data; // get param name "e" | ||
_proto.continueStatementHandler = function continueStatementHandler(node) { | ||
_proto2.continueStatementHandler = function continueStatementHandler(node) { | ||
return function () { | ||
@@ -1736,3 +1876,3 @@ return node.label ? new ContinueLabel(node.label.name) : Continue; | ||
_proto.breakStatementHandler = function breakStatementHandler(node) { | ||
_proto2.breakStatementHandler = function breakStatementHandler(node) { | ||
return function () { | ||
@@ -1743,8 +1883,8 @@ return node.label ? new BreakLabel(node.label.name) : Break; | ||
_proto.switchStatementHandler = function switchStatementHandler(node) { | ||
var _this25 = this; | ||
_proto2.switchStatementHandler = function switchStatementHandler(node) { | ||
var _this24 = this; | ||
var discriminantClosure = this.createClosure(node.discriminant); | ||
var caseClosures = node.cases.map(function (item) { | ||
return _this25.switchCaseHandler(item); | ||
return _this24.switchCaseHandler(item); | ||
}); | ||
@@ -1768,3 +1908,3 @@ return function () { | ||
match = true; | ||
ret = _this25.setValue(item.bodyClosure()); // notice: never return Break! | ||
ret = _this24.setValue(item.bodyClosure()); // notice: never return Break! | ||
@@ -1786,3 +1926,3 @@ if (ret === EmptyStatementReturn) continue; | ||
if (!match && defaultCase) { | ||
ret = _this25.setValue(defaultCase.bodyClosure()); | ||
ret = _this24.setValue(defaultCase.bodyClosure()); | ||
var isEBC = ret === EmptyStatementReturn || ret === Break || ret === Continue; // notice: never return Break or Continue! | ||
@@ -1799,3 +1939,3 @@ | ||
_proto.switchCaseHandler = function switchCaseHandler(node) { | ||
_proto2.switchCaseHandler = function switchCaseHandler(node) { | ||
var testClosure = node.test ? this.createClosure(node.test) : function () { | ||
@@ -1817,4 +1957,4 @@ return DefaultCase; | ||
_proto.labeledStatementHandler = function labeledStatementHandler(node) { | ||
var _this26 = this; | ||
_proto2.labeledStatementHandler = function labeledStatementHandler(node) { | ||
var _this25 = this; | ||
@@ -1826,3 +1966,3 @@ var labelName = node.label.name; | ||
var currentScope = _this26.getCurrentScope(); | ||
var currentScope = _this25.getCurrentScope(); | ||
@@ -1841,3 +1981,3 @@ currentScope.labelStack.push(labelName); | ||
_proto.debuggerStatementHandler = function debuggerStatementHandler(node) { | ||
_proto2.debuggerStatementHandler = function debuggerStatementHandler(node) { | ||
return function () { | ||
@@ -1850,3 +1990,3 @@ debugger; | ||
_proto.createParamNameGetter = function createParamNameGetter(node) { | ||
_proto2.createParamNameGetter = function createParamNameGetter(node) { | ||
if (node.type === "Identifier") { | ||
@@ -1861,3 +2001,3 @@ return function () { | ||
_proto.createObjectKeyGetter = function createObjectKeyGetter(node) { | ||
_proto2.createObjectKeyGetter = function createObjectKeyGetter(node) { | ||
var getter; // var obj = { title: "" } | ||
@@ -1880,3 +2020,3 @@ | ||
_proto.createMemberKeyGetter = function createMemberKeyGetter(node) { | ||
_proto2.createMemberKeyGetter = function createMemberKeyGetter(node) { | ||
// s['a']; node.computed = true | ||
@@ -1888,4 +2028,4 @@ // s.foo; node.computed = false | ||
_proto.createObjectGetter = function createObjectGetter(node) { | ||
var _this27 = this; | ||
_proto2.createObjectGetter = function createObjectGetter(node) { | ||
var _this26 = this; | ||
@@ -1895,3 +2035,3 @@ switch (node.type) { | ||
return function () { | ||
return _this27.getScopeDataFromName(node.name, _this27.getCurrentScope()); | ||
return _this26.getScopeDataFromName(node.name, _this26.getCurrentScope()); | ||
}; | ||
@@ -1908,3 +2048,3 @@ | ||
_proto.createNameGetter = function createNameGetter(node) { | ||
_proto2.createNameGetter = function createNameGetter(node) { | ||
switch (node.type) { | ||
@@ -1924,3 +2064,3 @@ case "Identifier": | ||
_proto.varDeclaration = function varDeclaration(name) { | ||
_proto2.varDeclaration = function varDeclaration(name) { | ||
var context = this.collectDeclVars; | ||
@@ -1930,3 +2070,3 @@ context[name] = undefined; | ||
_proto.funcDeclaration = function funcDeclaration(name, func) { | ||
_proto2.funcDeclaration = function funcDeclaration(name, func) { | ||
var context = this.collectDeclFuncs; | ||
@@ -1936,3 +2076,3 @@ context[name] = func; | ||
_proto.addDeclarationsToScope = function addDeclarationsToScope(declVars, declFuncs, scope) { | ||
_proto2.addDeclarationsToScope = function addDeclarationsToScope(declVars, declFuncs, scope) { | ||
var scopeData = scope.data; | ||
@@ -1945,5 +2085,5 @@ | ||
for (var _key3 in declVars) { | ||
if (!(_key3 in scopeData)) { | ||
scopeData[_key3] = void 0; | ||
for (var _key5 in declVars) { | ||
if (!(_key5 in scopeData)) { | ||
scopeData[_key5] = void 0; | ||
} | ||
@@ -1953,3 +2093,3 @@ } | ||
_proto.getScopeValue = function getScopeValue(name, startScope) { | ||
_proto2.getScopeValue = function getScopeValue(name, startScope) { | ||
var scope = this.getScopeFromName(name, startScope); | ||
@@ -1959,7 +2099,7 @@ return scope.data[name]; | ||
_proto.getScopeDataFromName = function getScopeDataFromName(name, startScope) { | ||
_proto2.getScopeDataFromName = function getScopeDataFromName(name, startScope) { | ||
return this.getScopeFromName(name, startScope).data; | ||
}; | ||
_proto.getScopeFromName = function getScopeFromName(name, startScope) { | ||
_proto2.getScopeFromName = function getScopeFromName(name, startScope) { | ||
var scope = startScope; | ||
@@ -1974,14 +2114,6 @@ | ||
return this.rootScope; | ||
return this.globalScope; | ||
}; | ||
_proto.getCurrentScope = function getCurrentScope() { | ||
return this.currentScope; | ||
}; | ||
_proto.getCurrentContext = function getCurrentContext() { | ||
return this.currentContext; | ||
}; | ||
_proto.setValue = function setValue(value) { | ||
_proto2.setValue = function setValue(value) { | ||
var isFunctionCall = this.callStack.length; | ||
@@ -1997,3 +2129,3 @@ | ||
_proto.getValue = function getValue() { | ||
_proto2.getValue = function getValue() { | ||
return this.value; | ||
@@ -2007,8 +2139,12 @@ }; | ||
Interpreter.version = version; | ||
Interpreter.eval = IEval; | ||
Interpreter.Function = IFunction; | ||
Interpreter.ecmaVersion = 5; // alert.call(rootContext, 1); | ||
// But alert({}, 1); // Illegal invocation | ||
Interpreter.eval = internalEval; | ||
Interpreter.Function = internalFunction; | ||
Interpreter.ecmaVersion = 5; // alert.call(globalContextInFunction, 1); | ||
// fix: alert.call({}, 1); // Illegal invocation | ||
// function func(){ | ||
// this;// Interpreter.globalContextInFunction | ||
// } | ||
// func() | ||
Interpreter.rootContext = void 0; | ||
Interpreter.globalContextInFunction = void 0; | ||
Interpreter.global = Object.create(null); |
@@ -37,3 +37,5 @@ "use strict"; | ||
ecmaVersion: options.ecmaVersion, | ||
timeout: timeout | ||
timeout: timeout, | ||
rootContext: options.rootContext, | ||
globalContextInFunction: options.globalContextInFunction | ||
}); | ||
@@ -40,0 +42,0 @@ return interpreter.evaluate(wrapCode); |
import _construct from "@babel/runtime/helpers/construct"; | ||
import { parse } from "acorn"; | ||
import { Messages, InterruptThrowError, InterruptThrowReferenceError, InterruptThrowSyntaxError } from "./messages"; | ||
var version = "1.3.1"; | ||
var version = "1.4.0"; | ||
@@ -20,4 +20,2 @@ function defineFunctionName(func, name) { | ||
var EmptyStatementReturn = Symbol("EmptyStatementReturn"); | ||
var IEval = Symbol("IEval"); | ||
var IFunction = Symbol("IFunction"); | ||
@@ -28,2 +26,100 @@ function isFunction(func) { | ||
var InternalInternalReflection = | ||
/*#__PURE__*/ | ||
function () { | ||
function InternalInternalReflection(interpreter) { | ||
this.interpreter = interpreter; | ||
} | ||
var _proto = InternalInternalReflection.prototype; | ||
_proto.generator = function generator() { | ||
var interpreter = this.interpreter; | ||
function getCurrentScope() { | ||
return this.getCurrentScope(); | ||
} | ||
function getGlobalScope() { | ||
return this.getGlobalScope(); | ||
} | ||
function getCurrentContext() { | ||
return this.getCurrentContext(); | ||
} | ||
return { | ||
getOptions: interpreter.getOptions.bind(interpreter), | ||
getCurrentScope: getCurrentScope.bind(interpreter), | ||
getGlobalScope: getGlobalScope.bind(interpreter), | ||
getCurrentContext: getCurrentContext.bind(interpreter), | ||
getExecStartTime: interpreter.getExecStartTime.bind(interpreter) | ||
}; | ||
}; | ||
return InternalInternalReflection; | ||
}(); | ||
function internalEval(reflection, code, useGlobalScope) { | ||
if (useGlobalScope === void 0) { | ||
useGlobalScope = true; | ||
} | ||
if (!(reflection instanceof InternalInternalReflection)) { | ||
throw new Error("Illegal call"); | ||
} | ||
if (typeof code !== "string") return code; | ||
if (!code) return void 0; | ||
var instance = reflection.generator(); | ||
var opts = instance.getOptions(); | ||
var options = { | ||
timeout: opts.timeout, | ||
_initEnv: function _initEnv() { | ||
// set caller context | ||
if (!useGlobalScope) { | ||
this.setCurrentContext(instance.getCurrentContext()); | ||
} // share timeout | ||
this.execStartTime = instance.getExecStartTime(); | ||
this.execEndTime = this.execStartTime; | ||
} | ||
}; | ||
var currentScope = useGlobalScope ? instance.getGlobalScope() : instance.getCurrentScope(); | ||
var interpreter = new Interpreter(currentScope, options); | ||
return interpreter.evaluate(code); | ||
} | ||
Object.defineProperty(internalEval, "__IS_EVAL_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
function internalFunction(reflection) { | ||
if (!(reflection instanceof InternalInternalReflection)) { | ||
throw new Error("Illegal call"); | ||
} | ||
var instance = reflection.generator(); | ||
for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
params[_key - 1] = arguments[_key]; | ||
} | ||
var code = params.pop(); | ||
var interpreter = new Interpreter(instance.getGlobalScope(), instance.getOptions()); | ||
var wrapCode = "\n\t\t (function anonymous(" + params.join(",") + "){\n\t\t " + code + "\n\t\t });\n\t\t "; | ||
return interpreter.evaluate(wrapCode); | ||
} | ||
Object.defineProperty(internalFunction, "__IS_FUNCTION_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
var Return = function Return(value) { | ||
@@ -40,3 +136,16 @@ this.value = value; | ||
}; | ||
/** | ||
* scope chain | ||
* | ||
* superScope | ||
* ↓ | ||
* rootScope | ||
* ↓ | ||
* globalScope | ||
* ↓ | ||
* functionScope | ||
* | ||
*/ | ||
var Scope = function Scope(data, parent, name) { | ||
@@ -87,3 +196,5 @@ if (parent === void 0) { | ||
escape: escape, | ||
unescape: unescape | ||
unescape: unescape, | ||
eval: internalEval, | ||
Function: internalFunction | ||
}; // ES5 Object | ||
@@ -149,12 +260,14 @@ | ||
timeout: options.timeout || 0, | ||
initEnv: options.initEnv | ||
rootContext: options.rootContext, | ||
globalContextInFunction: options.globalContextInFunction === undefined ? Interpreter.globalContextInFunction : options.globalContextInFunction, | ||
_initEnv: options._initEnv | ||
}; | ||
this.context = context; | ||
this.context = context || Object.create(null); | ||
this.callStack = []; | ||
this.initEnvironment(context); | ||
this.initEnvironment(this.context); | ||
} | ||
var _proto = Interpreter.prototype; | ||
var _proto2 = Interpreter.prototype; | ||
_proto.initEnvironment = function initEnvironment(ctx) { | ||
_proto2.initEnvironment = function initEnvironment(ctx) { | ||
var scope; //init global scope | ||
@@ -165,20 +278,16 @@ | ||
} else { | ||
var superScope = this.getSuperScope(ctx); // replace Interpreter.eval and Interpreter.Function | ||
var rootScope = null; | ||
var superScope = this.createSuperScope(ctx); | ||
Object.keys(ctx).forEach(function (key) { | ||
if (ctx[key] === IEval) { | ||
ctx[key] = superScope.data[IEval]; | ||
} | ||
if (this.options.rootContext) { | ||
rootScope = new Scope(this.options.rootContext, superScope, "rootScope"); | ||
} | ||
if (ctx[key] === IFunction) { | ||
ctx[key] = superScope.data[IFunction]; | ||
} | ||
}); | ||
scope = new Scope(ctx, superScope, "root"); | ||
scope = new Scope(ctx, rootScope || superScope, "globalScope"); | ||
} | ||
this.rootScope = scope; | ||
this.currentScope = this.rootScope; //init global context == this | ||
this.globalScope = scope; | ||
this.currentScope = this.globalScope; //init global context to this | ||
this.rootContext = scope.data; | ||
this.globalContext = scope.data; | ||
this.currentContext = scope.data; // collect var/function declare | ||
@@ -190,69 +299,48 @@ | ||
this.execEndTime = this.execStartTime; | ||
var initEnv = this.options.initEnv; | ||
var _initEnv = this.options._initEnv; | ||
if (initEnv) { | ||
initEnv(this); | ||
if (_initEnv) { | ||
_initEnv.call(this); | ||
} | ||
}; | ||
_proto.isInterruptThrow = function isInterruptThrow(err) { | ||
return err instanceof InterruptThrowError || err instanceof InterruptThrowReferenceError || err instanceof InterruptThrowSyntaxError; | ||
_proto2.getExecStartTime = function getExecStartTime() { | ||
return this.execStartTime; | ||
}; | ||
_proto.getSuperScope = function getSuperScope(ctx) { | ||
var _this = this; | ||
_proto2.getExecutionTime = function getExecutionTime() { | ||
return this.execEndTime - this.execStartTime; | ||
}; | ||
var data = Object.assign({}, BuildInObjects); | ||
_proto2.setExecTimeout = function setExecTimeout(timeout) { | ||
if (timeout === void 0) { | ||
timeout = 0; | ||
} | ||
data.eval = function (code, useGlobalScope) { | ||
if (useGlobalScope === void 0) { | ||
useGlobalScope = true; | ||
} | ||
this.options.timeout = timeout; | ||
}; | ||
if (typeof code !== "string") return code; | ||
if (!code) return void 0; | ||
var options = { | ||
timeout: _this.options.timeout, | ||
initEnv: function initEnv(inst) { | ||
// set caller context | ||
if (!useGlobalScope) { | ||
inst.setCurrentContext(_this.getCurrentContext()); | ||
} | ||
_proto2.getOptions = function getOptions() { | ||
return this.options; | ||
}; | ||
inst.execStartTime = _this.execStartTime; | ||
inst.execEndTime = inst.execStartTime; | ||
} | ||
}; | ||
var currentScope = useGlobalScope ? _this.rootScope : _this.getCurrentScope(); | ||
var interpreter = new Interpreter(currentScope, options); | ||
return interpreter.evaluate(code); | ||
}; | ||
_proto2.getGlobalScope = function getGlobalScope() { | ||
return this.globalScope; | ||
}; | ||
Object.defineProperty(data.eval, "__IS_EVAL_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
_proto2.getCurrentScope = function getCurrentScope() { | ||
return this.currentScope; | ||
}; | ||
data.Function = function () { | ||
for (var _len = arguments.length, params = new Array(_len), _key = 0; _key < _len; _key++) { | ||
params[_key] = arguments[_key]; | ||
} | ||
_proto2.getCurrentContext = function getCurrentContext() { | ||
return this.currentContext; | ||
}; | ||
var code = params.pop(); | ||
var interpreter = new Interpreter(_this.rootScope, _this.options); | ||
var wrapCode = "\n\t\t (function anonymous(" + params.join(",") + "){\n\t\t " + code + "\n\t\t });\n\t\t "; | ||
return interpreter.evaluate(wrapCode); | ||
}; | ||
_proto2.isInterruptThrow = function isInterruptThrow(err) { | ||
return err instanceof InterruptThrowError || err instanceof InterruptThrowReferenceError || err instanceof InterruptThrowSyntaxError; | ||
}; | ||
Object.defineProperty(data.Function, "__IS_FUNCTION_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false | ||
}); | ||
_proto2.createSuperScope = function createSuperScope(ctx) { | ||
var data = Object.assign({}, BuildInObjects); | ||
var buildInObjectKeys = Object.keys(data); | ||
data[IEval] = data.eval; | ||
data[IFunction] = data.Function; | ||
buildInObjectKeys.forEach(function (key) { | ||
@@ -263,14 +351,14 @@ if (key in ctx) { | ||
}); | ||
return new Scope(data, null, "superRoot"); | ||
return new Scope(data, null, "superScope"); | ||
}; | ||
_proto.setCurrentContext = function setCurrentContext(ctx) { | ||
_proto2.setCurrentContext = function setCurrentContext(ctx) { | ||
this.currentContext = ctx; | ||
}; | ||
_proto.setCurrentScope = function setCurrentScope(scope) { | ||
_proto2.setCurrentScope = function setCurrentScope(scope) { | ||
this.currentScope = scope; | ||
}; | ||
_proto.evaluate = function evaluate(code) { | ||
_proto2.evaluate = function evaluate(code) { | ||
if (code === void 0) { | ||
@@ -290,7 +378,7 @@ code = ""; | ||
_proto.appendCode = function appendCode(code) { | ||
_proto2.appendCode = function appendCode(code) { | ||
return this.evaluate(code); | ||
}; | ||
_proto.evaluateNode = function evaluateNode(node, source) { | ||
_proto2.evaluateNode = function evaluateNode(node, source) { | ||
if (source === void 0) { | ||
@@ -323,7 +411,3 @@ source = ""; | ||
_proto.getExecutionTime = function getExecutionTime() { | ||
return this.execEndTime - this.execStartTime; | ||
}; | ||
_proto.createErrorMessage = function createErrorMessage(msg, value, node) { | ||
_proto2.createErrorMessage = function createErrorMessage(msg, value, node) { | ||
var message = msg[1].replace("%0", String(value)); | ||
@@ -338,23 +422,15 @@ | ||
_proto.createError = function createError(message, error) { | ||
_proto2.createError = function createError(message, error) { | ||
return new error(message); | ||
}; | ||
_proto.createThrowError = function createThrowError(message, error) { | ||
_proto2.createThrowError = function createThrowError(message, error) { | ||
return this.createError(message, error); | ||
}; | ||
_proto.createInternalThrowError = function createInternalThrowError(msg, value, node) { | ||
_proto2.createInternalThrowError = function createInternalThrowError(msg, value, node) { | ||
return this.createError(this.createErrorMessage(msg, value, node), msg[2]); | ||
}; | ||
_proto.setExecTimeout = function setExecTimeout(timeout) { | ||
if (timeout === void 0) { | ||
timeout = 0; | ||
} | ||
this.options.timeout = timeout; | ||
}; | ||
_proto.checkTimeout = function checkTimeout() { | ||
_proto2.checkTimeout = function checkTimeout() { | ||
if (!this.isRunning) return false; | ||
@@ -371,3 +447,3 @@ var timeout = this.options.timeout || 0; | ||
_proto.getNodePosition = function getNodePosition(node) { | ||
_proto2.getNodePosition = function getNodePosition(node) { | ||
if (node) { | ||
@@ -382,4 +458,4 @@ var errorCode = ""; //this.source.slice(node.start, node.end); | ||
_proto.createClosure = function createClosure(node) { | ||
var _this2 = this; | ||
_proto2.createClosure = function createClosure(node) { | ||
var _this = this; | ||
@@ -535,9 +611,9 @@ var closure; | ||
return function () { | ||
var timeout = _this2.options.timeout; | ||
var timeout = _this.options.timeout; | ||
if (timeout && timeout > 0 && _this2.checkTimeout()) { | ||
throw _this2.createInternalThrowError(Messages.ExecutionTimeOutError, timeout, null); | ||
if (timeout && timeout > 0 && _this.checkTimeout()) { | ||
throw _this.createInternalThrowError(Messages.ExecutionTimeOutError, timeout, null); | ||
} | ||
_this2.lastExecNode = node; | ||
_this.lastExecNode = node; | ||
return closure.apply(void 0, arguments); | ||
@@ -548,4 +624,4 @@ }; | ||
_proto.binaryExpressionHandler = function binaryExpressionHandler(node) { | ||
var _this3 = this; | ||
_proto2.binaryExpressionHandler = function binaryExpressionHandler(node) { | ||
var _this2 = this; | ||
@@ -626,3 +702,3 @@ var leftExpression = this.createClosure(node.left); | ||
default: | ||
throw _this3.createInternalThrowError(Messages.BinaryOperatorSyntaxError, node.operator, node); | ||
throw _this2.createInternalThrowError(Messages.BinaryOperatorSyntaxError, node.operator, node); | ||
} | ||
@@ -633,4 +709,4 @@ }; | ||
_proto.logicalExpressionHandler = function logicalExpressionHandler(node) { | ||
var _this4 = this; | ||
_proto2.logicalExpressionHandler = function logicalExpressionHandler(node) { | ||
var _this3 = this; | ||
@@ -648,10 +724,19 @@ var leftExpression = this.createClosure(node.left); | ||
default: | ||
throw _this4.createInternalThrowError(Messages.LogicalOperatorSyntaxError, node.operator, node); | ||
throw _this3.createInternalThrowError(Messages.LogicalOperatorSyntaxError, node.operator, node); | ||
} | ||
}; | ||
}; | ||
_proto2.isRootScope = function isRootScope(node) { | ||
if (node.type === "Identifier") { | ||
var scope = this.getScopeFromName(node.name, this.getCurrentScope()); | ||
return scope.name === "rootScope"; | ||
} | ||
return false; | ||
} // typeof a !a() | ||
; | ||
_proto.unaryExpressionHandler = function unaryExpressionHandler(node) { | ||
var _this5 = this; | ||
_proto2.unaryExpressionHandler = function unaryExpressionHandler(node) { | ||
var _this4 = this; | ||
@@ -663,2 +748,7 @@ switch (node.operator) { | ||
return function () { | ||
// not allowed to delete root scope property | ||
if (_this4.isRootScope(node.argument)) { | ||
return false; | ||
} | ||
var obj = objectGetter(); | ||
@@ -708,3 +798,3 @@ var name = nameGetter(); | ||
default: | ||
throw _this5.createInternalThrowError(Messages.UnaryOperatorSyntaxError, node.operator, node); | ||
throw _this4.createInternalThrowError(Messages.UnaryOperatorSyntaxError, node.operator, node); | ||
} | ||
@@ -716,4 +806,4 @@ }; | ||
_proto.updateExpressionHandler = function updateExpressionHandler(node) { | ||
var _this6 = this; | ||
_proto2.updateExpressionHandler = function updateExpressionHandler(node) { | ||
var _this5 = this; | ||
@@ -726,3 +816,3 @@ var objectGetter = this.createObjectGetter(node.argument); | ||
_this6.assertVariable(obj, name, node); | ||
_this5.assertVariable(obj, name, node); | ||
@@ -737,3 +827,3 @@ switch (node.operator) { | ||
default: | ||
throw _this6.createInternalThrowError(Messages.UpdateOperatorSyntaxError, node.operator, node); | ||
throw _this5.createInternalThrowError(Messages.UpdateOperatorSyntaxError, node.operator, node); | ||
} | ||
@@ -744,4 +834,4 @@ }; | ||
_proto.objectExpressionHandler = function objectExpressionHandler(node) { | ||
var _this7 = this; | ||
_proto2.objectExpressionHandler = function objectExpressionHandler(node) { | ||
var _this6 = this; | ||
@@ -772,3 +862,3 @@ var items = []; | ||
properties[key][kind] = _this7.createClosure(property.value); | ||
properties[key][kind] = _this6.createClosure(property.value); | ||
items.push({ | ||
@@ -818,8 +908,8 @@ key: key, | ||
_proto.arrayExpressionHandler = function arrayExpressionHandler(node) { | ||
var _this8 = this; | ||
_proto2.arrayExpressionHandler = function arrayExpressionHandler(node) { | ||
var _this7 = this; | ||
//fix: [,,,1,2] | ||
var items = node.elements.map(function (element) { | ||
return element ? _this8.createClosure(element) : element; | ||
return element ? _this7.createClosure(element) : element; | ||
}); | ||
@@ -842,8 +932,8 @@ return function () { | ||
_proto.safeObjectGet = function safeObjectGet(obj, key, node) { | ||
_proto2.safeObjectGet = function safeObjectGet(obj, key, node) { | ||
return obj[key]; | ||
}; | ||
_proto.createCallFunctionGetter = function createCallFunctionGetter(node) { | ||
var _this9 = this; | ||
_proto2.createCallFunctionGetter = function createCallFunctionGetter(node) { | ||
var _this8 = this; | ||
@@ -859,18 +949,38 @@ switch (node.type) { | ||
var func = _this9.safeObjectGet(obj, key, node); | ||
var func = _this8.safeObjectGet(obj, key, node); | ||
if (!func || !isFunction(func)) { | ||
var name = source.slice(node.start, node.end); | ||
throw _this9.createInternalThrowError(Messages.FunctionUndefinedReferenceError, name, node); | ||
} | ||
throw _this8.createInternalThrowError(Messages.FunctionUndefinedReferenceError, name, node); | ||
} // obj.eval = eval | ||
// obj.eval(...) | ||
if (func.__IS_EVAL_FUNC) { | ||
return function (code) { | ||
return func(code, true); | ||
return func(new InternalInternalReflection(_this8), code, true); | ||
}; | ||
} // obj.func = Function | ||
// obj.func(...) | ||
if (func.__IS_FUNCTION_FUNC) { | ||
return function () { | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
return func.apply(void 0, [new InternalInternalReflection(_this8)].concat(args)); | ||
}; | ||
} // method call | ||
// eg:obj.say(...) | ||
// eg: obj.say.call(...) | ||
// eg: obj.say.apply(...) | ||
// ====================== | ||
// obj.func(...) | ||
// func = func.bind(obj) | ||
// tips: | ||
// test.call(ctx, ...) === test.call.bind(test)(ctx, ...) | ||
// test.apply(ctx, ...) === test.apply.bind(test)(ctx, ...) | ||
// test.f(...) === test.f.bind(test)(...) | ||
// func(...) -> func.bind(obj)(...) | ||
// func.call(...) -> obj.func.call.bind(obj.func)(...) | ||
// func.apply(...) -> obj.func.apply.bind(obj.func)(...) | ||
// ...others | ||
@@ -883,3 +993,3 @@ | ||
default: | ||
// test() or (0.test)() or a[1]() ... | ||
// test() or (0,test)() or a[1]() ... | ||
var closure = this.createClosure(node); | ||
@@ -897,17 +1007,39 @@ return function () { | ||
if (!func || !isFunction(func)) { | ||
throw _this9.createInternalThrowError(Messages.FunctionUndefinedReferenceError, name, node); | ||
throw _this8.createInternalThrowError(Messages.FunctionUndefinedReferenceError, name, node); | ||
} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval | ||
// calling eval scope check | ||
// var geval = eval; | ||
// geval("a+1"); | ||
// var eval = eval; | ||
// function test(){ | ||
// eval(...); //note: use local scope in eval5,but in Browser is use global scope | ||
// } | ||
if (node.type === "Identifier" && func.__IS_EVAL_FUNC) { | ||
if (node.type === "Identifier" && func.__IS_EVAL_FUNC && name === "eval") { | ||
return function (code) { | ||
var scope = _this9.getScopeFromName(name, _this9.getCurrentScope()); | ||
var scope = _this8.getScopeFromName(name, _this8.getCurrentScope()); | ||
var isSuperScope = !scope.parent || _this9.rootScope === scope; // use local scope if calling eval in super scope | ||
var useGlobalScope = !scope.parent || _this8.globalScope === scope || scope.name === "rootScope"; // use local scope if calling eval in super scope | ||
return func(code, !isSuperScope); | ||
return func(new InternalInternalReflection(_this8), code, !useGlobalScope); | ||
}; | ||
} // use global scope | ||
// var g_eval = eval; | ||
// g_eval("a+1"); | ||
//(0,eval)(...) ...eval alias | ||
if (func.__IS_EVAL_FUNC) { | ||
return function (code) { | ||
return func(new InternalInternalReflection(_this8), code, true); | ||
}; | ||
} // Function('a', 'b', 'return a+b') | ||
if (func.__IS_FUNCTION_FUNC) { | ||
return function () { | ||
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
return func.apply(void 0, [new InternalInternalReflection(_this8)].concat(args)); | ||
}; | ||
} // function call | ||
@@ -917,5 +1049,6 @@ // this = undefined | ||
// test(...) === test.call(undefined, ...) | ||
// fix: alert.call({}, ...) Illegal invocation | ||
return func.bind(Interpreter.rootContext); | ||
return func.bind(_this8.options.globalContextInFunction); | ||
}; | ||
@@ -926,8 +1059,8 @@ } | ||
_proto.callExpressionHandler = function callExpressionHandler(node) { | ||
var _this10 = this; | ||
_proto2.callExpressionHandler = function callExpressionHandler(node) { | ||
var _this9 = this; | ||
var funcGetter = this.createCallFunctionGetter(node.callee); | ||
var argsGetter = node.arguments.map(function (arg) { | ||
return _this10.createClosure(arg); | ||
return _this9.createClosure(arg); | ||
}); | ||
@@ -942,4 +1075,4 @@ return function () { | ||
_proto.functionExpressionHandler = function functionExpressionHandler(node) { | ||
var _this11 = this; | ||
_proto2.functionExpressionHandler = function functionExpressionHandler(node) { | ||
var _this10 = this; | ||
@@ -957,3 +1090,3 @@ var self = this; | ||
var paramsGetter = node.params.map(function (param) { | ||
return _this11.createParamNameGetter(param); | ||
return _this10.createParamNameGetter(param); | ||
}); // set scope | ||
@@ -971,4 +1104,4 @@ | ||
var func = function func() { | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | ||
args[_key4] = arguments[_key4]; | ||
} | ||
@@ -1038,4 +1171,4 @@ | ||
_proto.newExpressionHandler = function newExpressionHandler(node) { | ||
var _this12 = this; | ||
_proto2.newExpressionHandler = function newExpressionHandler(node) { | ||
var _this11 = this; | ||
@@ -1045,3 +1178,3 @@ var source = this.source; | ||
var args = node.arguments.map(function (arg) { | ||
return _this12.createClosure(arg); | ||
return _this11.createClosure(arg); | ||
}); | ||
@@ -1051,6 +1184,13 @@ return function () { | ||
if (!isFunction(construct)) { | ||
if (!isFunction(construct) || construct.__IS_EVAL_FUNC) { | ||
var callee = node.callee; | ||
var name = source.slice(callee.start, callee.end); | ||
throw _this12.createInternalThrowError(Messages.IsNotConstructor, name, node); | ||
throw _this11.createInternalThrowError(Messages.IsNotConstructor, name, node); | ||
} // new Function(...) | ||
if (construct.__IS_FUNCTION_FUNC) { | ||
return construct.apply(void 0, [new InternalInternalReflection(_this11)].concat(args.map(function (arg) { | ||
return arg(); | ||
}))); | ||
} | ||
@@ -1065,3 +1205,3 @@ | ||
_proto.memberExpressionHandler = function memberExpressionHandler(node) { | ||
_proto2.memberExpressionHandler = function memberExpressionHandler(node) { | ||
var objectGetter = this.createClosure(node.object); | ||
@@ -1077,7 +1217,7 @@ var keyGetter = this.createMemberKeyGetter(node); | ||
_proto.thisExpressionHandler = function thisExpressionHandler(node) { | ||
var _this13 = this; | ||
_proto2.thisExpressionHandler = function thisExpressionHandler(node) { | ||
var _this12 = this; | ||
return function () { | ||
return _this13.getCurrentContext(); | ||
return _this12.getCurrentContext(); | ||
}; | ||
@@ -1087,7 +1227,7 @@ } // var1,var2,... | ||
_proto.sequenceExpressionHandler = function sequenceExpressionHandler(node) { | ||
var _this14 = this; | ||
_proto2.sequenceExpressionHandler = function sequenceExpressionHandler(node) { | ||
var _this13 = this; | ||
var expressions = node.expressions.map(function (item) { | ||
return _this14.createClosure(item); | ||
return _this13.createClosure(item); | ||
}); | ||
@@ -1108,3 +1248,3 @@ return function () { | ||
_proto.literalHandler = function literalHandler(node) { | ||
_proto2.literalHandler = function literalHandler(node) { | ||
return function () { | ||
@@ -1120,11 +1260,11 @@ if (node.regex) { | ||
_proto.identifierHandler = function identifierHandler(node) { | ||
var _this15 = this; | ||
_proto2.identifierHandler = function identifierHandler(node) { | ||
var _this14 = this; | ||
return function () { | ||
var currentScope = _this15.getCurrentScope(); | ||
var currentScope = _this14.getCurrentScope(); | ||
var data = _this15.getScopeDataFromName(node.name, currentScope); | ||
var data = _this14.getScopeDataFromName(node.name, currentScope); | ||
_this15.assertVariable(data, node.name, node); | ||
_this14.assertVariable(data, node.name, node); | ||
@@ -1136,4 +1276,4 @@ return data[node.name]; | ||
_proto.assignmentExpressionHandler = function assignmentExpressionHandler(node) { | ||
var _this16 = this; | ||
_proto2.assignmentExpressionHandler = function assignmentExpressionHandler(node) { | ||
var _this15 = this; | ||
@@ -1159,3 +1299,3 @@ // var s = function(){} | ||
// var1(undefined) += 1 | ||
_this16.assertVariable(data, name, node); | ||
_this15.assertVariable(data, name, node); | ||
} | ||
@@ -1219,3 +1359,3 @@ | ||
default: | ||
throw _this16.createInternalThrowError(Messages.AssignmentExpressionSyntaxError, node.type, node); | ||
throw _this15.createInternalThrowError(Messages.AssignmentExpressionSyntaxError, node.type, node); | ||
} | ||
@@ -1229,3 +1369,3 @@ | ||
_proto.functionDeclarationHandler = function functionDeclarationHandler(node) { | ||
_proto2.functionDeclarationHandler = function functionDeclarationHandler(node) { | ||
if (node.id) { | ||
@@ -1247,3 +1387,3 @@ var functionClosure = this.functionExpressionHandler(node); | ||
_proto.getVariableName = function getVariableName(node) { | ||
_proto2.getVariableName = function getVariableName(node) { | ||
if (node.type === "Identifier") { | ||
@@ -1258,4 +1398,4 @@ return node.name; | ||
_proto.variableDeclarationHandler = function variableDeclarationHandler(node) { | ||
var _this17 = this; | ||
_proto2.variableDeclarationHandler = function variableDeclarationHandler(node) { | ||
var _this16 = this; | ||
@@ -1288,5 +1428,5 @@ var assignmentsClosure; | ||
if (assignmentsClosure) { | ||
_this17.isVarDeclMode = true; | ||
_this16.isVarDeclMode = true; | ||
assignmentsClosure(); | ||
_this17.isVarDeclMode = false; | ||
_this16.isVarDeclMode = false; | ||
} | ||
@@ -1298,4 +1438,4 @@ | ||
_proto.assertVariable = function assertVariable(data, name, node) { | ||
if (data === this.rootScope.data && !(name in data)) { | ||
_proto2.assertVariable = function assertVariable(data, name, node) { | ||
if (data === this.globalScope.data && !(name in data)) { | ||
throw this.createInternalThrowError(Messages.VariableUndefinedReferenceError, name, node); | ||
@@ -1306,4 +1446,4 @@ } | ||
_proto.programHandler = function programHandler(node) { | ||
var _this18 = this; | ||
_proto2.programHandler = function programHandler(node) { | ||
var _this17 = this; | ||
@@ -1313,3 +1453,3 @@ // const currentScope = this.getCurrentScope(); | ||
// if (stmt.type === "EmptyStatement") return null; | ||
return _this18.createClosure(stmt); | ||
return _this17.createClosure(stmt); | ||
}); | ||
@@ -1322,3 +1462,3 @@ return function () { | ||
var ret = _this18.setValue(stmtClosure()); // if (!stmtClosure) continue; | ||
var ret = _this17.setValue(stmtClosure()); // if (!stmtClosure) continue; | ||
// EmptyStatement | ||
@@ -1342,7 +1482,7 @@ | ||
_proto.expressionStatementHandler = function expressionStatementHandler(node) { | ||
_proto2.expressionStatementHandler = function expressionStatementHandler(node) { | ||
return this.createClosure(node.expression); | ||
}; | ||
_proto.emptyStatementHandler = function emptyStatementHandler(node) { | ||
_proto2.emptyStatementHandler = function emptyStatementHandler(node) { | ||
return function () { | ||
@@ -1354,3 +1494,3 @@ return EmptyStatementReturn; | ||
_proto.returnStatementHandler = function returnStatementHandler(node) { | ||
_proto2.returnStatementHandler = function returnStatementHandler(node) { | ||
var argumentClosure = node.argument ? this.createClosure(node.argument) : noop; | ||
@@ -1363,3 +1503,3 @@ return function () { | ||
_proto.ifStatementHandler = function ifStatementHandler(node) { | ||
_proto2.ifStatementHandler = function ifStatementHandler(node) { | ||
var testClosure = this.createClosure(node.test); | ||
@@ -1378,3 +1518,3 @@ var consequentClosure = this.createClosure(node.consequent); | ||
_proto.conditionalExpressionHandler = function conditionalExpressionHandler(node) { | ||
_proto2.conditionalExpressionHandler = function conditionalExpressionHandler(node) { | ||
return this.ifStatementHandler(node); | ||
@@ -1384,4 +1524,4 @@ } // for(var i = 0; i < 10; i++) {...} | ||
_proto.forStatementHandler = function forStatementHandler(node) { | ||
var _this19 = this; | ||
_proto2.forStatementHandler = function forStatementHandler(node) { | ||
var _this18 = this; | ||
@@ -1412,3 +1552,3 @@ var initClosure = noop; | ||
var ret = _this19.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
var ret = _this18.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
@@ -1439,12 +1579,12 @@ | ||
_proto.whileStatementHandler = function whileStatementHandler(node) { | ||
_proto2.whileStatementHandler = function whileStatementHandler(node) { | ||
return this.forStatementHandler(node); | ||
}; | ||
_proto.doWhileStatementHandler = function doWhileStatementHandler(node) { | ||
_proto2.doWhileStatementHandler = function doWhileStatementHandler(node) { | ||
return this.forStatementHandler(node); | ||
}; | ||
_proto.forInStatementHandler = function forInStatementHandler(node) { | ||
var _this20 = this; | ||
_proto2.forInStatementHandler = function forInStatementHandler(node) { | ||
var _this19 = this; | ||
@@ -1479,3 +1619,3 @@ // for( k in obj) or for(o.k in obj) ... | ||
// o.k = x | ||
_this20.assignmentExpressionHandler({ | ||
_this19.assignmentExpressionHandler({ | ||
type: "AssignmentExpression", | ||
@@ -1491,3 +1631,3 @@ operator: "=", | ||
var ret = _this20.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
var ret = _this19.setValue(bodyClosure()); // notice: never return Break or Continue! | ||
@@ -1517,4 +1657,4 @@ | ||
_proto.withStatementHandler = function withStatementHandler(node) { | ||
var _this21 = this; | ||
_proto2.withStatementHandler = function withStatementHandler(node) { | ||
var _this20 = this; | ||
@@ -1524,7 +1664,7 @@ var objectClosure = this.createClosure(node.object); | ||
return function () { | ||
var currentScope = _this21.getCurrentScope(); | ||
var currentScope = _this20.getCurrentScope(); | ||
var newScope = createScope(currentScope, "with"); | ||
var data = objectClosure(); // newScope.data = data; | ||
// copy all property | ||
// copy all properties | ||
@@ -1535,8 +1675,8 @@ for (var k in data) { | ||
_this21.setCurrentScope(newScope); // save last value | ||
_this20.setCurrentScope(newScope); // save last value | ||
var result = _this21.setValue(bodyClosure()); | ||
var result = _this20.setValue(bodyClosure()); | ||
_this21.setCurrentScope(currentScope); | ||
_this20.setCurrentScope(currentScope); | ||
@@ -1547,8 +1687,8 @@ return result; | ||
_proto.throwStatementHandler = function throwStatementHandler(node) { | ||
var _this22 = this; | ||
_proto2.throwStatementHandler = function throwStatementHandler(node) { | ||
var _this21 = this; | ||
var argumentClosure = this.createClosure(node.argument); | ||
return function () { | ||
_this22.setValue(undefined); | ||
_this21.setValue(undefined); | ||
@@ -1560,4 +1700,4 @@ throw argumentClosure(); | ||
_proto.tryStatementHandler = function tryStatementHandler(node) { | ||
var _this23 = this; | ||
_proto2.tryStatementHandler = function tryStatementHandler(node) { | ||
var _this22 = this; | ||
@@ -1568,9 +1708,9 @@ var blockClosure = this.createClosure(node.block); | ||
return function () { | ||
var currentScope = _this23.getCurrentScope(); | ||
var currentScope = _this22.getCurrentScope(); | ||
var currentContext = _this23.getCurrentContext(); | ||
var currentContext = _this22.getCurrentContext(); | ||
var labelStack = currentScope.labelStack.concat([]); | ||
var callStack = _this23.callStack.concat([]); | ||
var callStack = _this22.callStack.concat([]); | ||
@@ -1582,6 +1722,6 @@ var result = EmptyStatementReturn; | ||
var reset = function reset() { | ||
_this23.setCurrentScope(currentScope); //reset scope | ||
_this22.setCurrentScope(currentScope); //reset scope | ||
_this23.setCurrentContext(currentContext); //reset context | ||
_this22.setCurrentContext(currentContext); //reset context | ||
@@ -1591,3 +1731,3 @@ | ||
_this23.callStack = callStack; //reset call stack | ||
_this22.callStack = callStack; //reset call stack | ||
}; | ||
@@ -1607,3 +1747,3 @@ /** | ||
try { | ||
result = _this23.setValue(blockClosure()); | ||
result = _this22.setValue(blockClosure()); | ||
@@ -1616,3 +1756,3 @@ if (result instanceof Return) { | ||
if (_this23.isInterruptThrow(err)) { | ||
if (_this22.isInterruptThrow(err)) { | ||
throw err; | ||
@@ -1623,3 +1763,3 @@ } | ||
try { | ||
result = _this23.setValue(handlerClosure(err)); | ||
result = _this22.setValue(handlerClosure(err)); | ||
@@ -1632,3 +1772,3 @@ if (result instanceof Return) { | ||
if (_this23.isInterruptThrow(err)) { | ||
if (_this22.isInterruptThrow(err)) { | ||
throw err; | ||
@@ -1656,3 +1796,3 @@ } // save catch throw error | ||
if (_this23.isInterruptThrow(err)) { | ||
if (_this22.isInterruptThrow(err)) { | ||
throw err; | ||
@@ -1681,4 +1821,4 @@ } // save finally throw error | ||
_proto.catchClauseHandler = function catchClauseHandler(node) { | ||
var _this24 = this; | ||
_proto2.catchClauseHandler = function catchClauseHandler(node) { | ||
var _this23 = this; | ||
@@ -1690,3 +1830,3 @@ var paramNameGetter = this.createParamNameGetter(node.param); | ||
var currentScope = _this24.getCurrentScope(); | ||
var currentScope = _this23.getCurrentScope(); | ||
@@ -1716,3 +1856,3 @@ var scopeData = currentScope.data; // get param name "e" | ||
_proto.continueStatementHandler = function continueStatementHandler(node) { | ||
_proto2.continueStatementHandler = function continueStatementHandler(node) { | ||
return function () { | ||
@@ -1723,3 +1863,3 @@ return node.label ? new ContinueLabel(node.label.name) : Continue; | ||
_proto.breakStatementHandler = function breakStatementHandler(node) { | ||
_proto2.breakStatementHandler = function breakStatementHandler(node) { | ||
return function () { | ||
@@ -1730,8 +1870,8 @@ return node.label ? new BreakLabel(node.label.name) : Break; | ||
_proto.switchStatementHandler = function switchStatementHandler(node) { | ||
var _this25 = this; | ||
_proto2.switchStatementHandler = function switchStatementHandler(node) { | ||
var _this24 = this; | ||
var discriminantClosure = this.createClosure(node.discriminant); | ||
var caseClosures = node.cases.map(function (item) { | ||
return _this25.switchCaseHandler(item); | ||
return _this24.switchCaseHandler(item); | ||
}); | ||
@@ -1755,3 +1895,3 @@ return function () { | ||
match = true; | ||
ret = _this25.setValue(item.bodyClosure()); // notice: never return Break! | ||
ret = _this24.setValue(item.bodyClosure()); // notice: never return Break! | ||
@@ -1773,3 +1913,3 @@ if (ret === EmptyStatementReturn) continue; | ||
if (!match && defaultCase) { | ||
ret = _this25.setValue(defaultCase.bodyClosure()); | ||
ret = _this24.setValue(defaultCase.bodyClosure()); | ||
var isEBC = ret === EmptyStatementReturn || ret === Break || ret === Continue; // notice: never return Break or Continue! | ||
@@ -1786,3 +1926,3 @@ | ||
_proto.switchCaseHandler = function switchCaseHandler(node) { | ||
_proto2.switchCaseHandler = function switchCaseHandler(node) { | ||
var testClosure = node.test ? this.createClosure(node.test) : function () { | ||
@@ -1804,4 +1944,4 @@ return DefaultCase; | ||
_proto.labeledStatementHandler = function labeledStatementHandler(node) { | ||
var _this26 = this; | ||
_proto2.labeledStatementHandler = function labeledStatementHandler(node) { | ||
var _this25 = this; | ||
@@ -1813,3 +1953,3 @@ var labelName = node.label.name; | ||
var currentScope = _this26.getCurrentScope(); | ||
var currentScope = _this25.getCurrentScope(); | ||
@@ -1828,3 +1968,3 @@ currentScope.labelStack.push(labelName); | ||
_proto.debuggerStatementHandler = function debuggerStatementHandler(node) { | ||
_proto2.debuggerStatementHandler = function debuggerStatementHandler(node) { | ||
return function () { | ||
@@ -1837,3 +1977,3 @@ debugger; | ||
_proto.createParamNameGetter = function createParamNameGetter(node) { | ||
_proto2.createParamNameGetter = function createParamNameGetter(node) { | ||
if (node.type === "Identifier") { | ||
@@ -1848,3 +1988,3 @@ return function () { | ||
_proto.createObjectKeyGetter = function createObjectKeyGetter(node) { | ||
_proto2.createObjectKeyGetter = function createObjectKeyGetter(node) { | ||
var getter; // var obj = { title: "" } | ||
@@ -1867,3 +2007,3 @@ | ||
_proto.createMemberKeyGetter = function createMemberKeyGetter(node) { | ||
_proto2.createMemberKeyGetter = function createMemberKeyGetter(node) { | ||
// s['a']; node.computed = true | ||
@@ -1875,4 +2015,4 @@ // s.foo; node.computed = false | ||
_proto.createObjectGetter = function createObjectGetter(node) { | ||
var _this27 = this; | ||
_proto2.createObjectGetter = function createObjectGetter(node) { | ||
var _this26 = this; | ||
@@ -1882,3 +2022,3 @@ switch (node.type) { | ||
return function () { | ||
return _this27.getScopeDataFromName(node.name, _this27.getCurrentScope()); | ||
return _this26.getScopeDataFromName(node.name, _this26.getCurrentScope()); | ||
}; | ||
@@ -1895,3 +2035,3 @@ | ||
_proto.createNameGetter = function createNameGetter(node) { | ||
_proto2.createNameGetter = function createNameGetter(node) { | ||
switch (node.type) { | ||
@@ -1911,3 +2051,3 @@ case "Identifier": | ||
_proto.varDeclaration = function varDeclaration(name) { | ||
_proto2.varDeclaration = function varDeclaration(name) { | ||
var context = this.collectDeclVars; | ||
@@ -1917,3 +2057,3 @@ context[name] = undefined; | ||
_proto.funcDeclaration = function funcDeclaration(name, func) { | ||
_proto2.funcDeclaration = function funcDeclaration(name, func) { | ||
var context = this.collectDeclFuncs; | ||
@@ -1923,3 +2063,3 @@ context[name] = func; | ||
_proto.addDeclarationsToScope = function addDeclarationsToScope(declVars, declFuncs, scope) { | ||
_proto2.addDeclarationsToScope = function addDeclarationsToScope(declVars, declFuncs, scope) { | ||
var scopeData = scope.data; | ||
@@ -1932,5 +2072,5 @@ | ||
for (var _key3 in declVars) { | ||
if (!(_key3 in scopeData)) { | ||
scopeData[_key3] = void 0; | ||
for (var _key5 in declVars) { | ||
if (!(_key5 in scopeData)) { | ||
scopeData[_key5] = void 0; | ||
} | ||
@@ -1940,3 +2080,3 @@ } | ||
_proto.getScopeValue = function getScopeValue(name, startScope) { | ||
_proto2.getScopeValue = function getScopeValue(name, startScope) { | ||
var scope = this.getScopeFromName(name, startScope); | ||
@@ -1946,7 +2086,7 @@ return scope.data[name]; | ||
_proto.getScopeDataFromName = function getScopeDataFromName(name, startScope) { | ||
_proto2.getScopeDataFromName = function getScopeDataFromName(name, startScope) { | ||
return this.getScopeFromName(name, startScope).data; | ||
}; | ||
_proto.getScopeFromName = function getScopeFromName(name, startScope) { | ||
_proto2.getScopeFromName = function getScopeFromName(name, startScope) { | ||
var scope = startScope; | ||
@@ -1961,14 +2101,6 @@ | ||
return this.rootScope; | ||
return this.globalScope; | ||
}; | ||
_proto.getCurrentScope = function getCurrentScope() { | ||
return this.currentScope; | ||
}; | ||
_proto.getCurrentContext = function getCurrentContext() { | ||
return this.currentContext; | ||
}; | ||
_proto.setValue = function setValue(value) { | ||
_proto2.setValue = function setValue(value) { | ||
var isFunctionCall = this.callStack.length; | ||
@@ -1984,3 +2116,3 @@ | ||
_proto.getValue = function getValue() { | ||
_proto2.getValue = function getValue() { | ||
return this.value; | ||
@@ -1992,8 +2124,12 @@ }; | ||
Interpreter.version = version; | ||
Interpreter.eval = IEval; | ||
Interpreter.Function = IFunction; | ||
Interpreter.ecmaVersion = 5; // alert.call(rootContext, 1); | ||
// But alert({}, 1); // Illegal invocation | ||
Interpreter.eval = internalEval; | ||
Interpreter.Function = internalFunction; | ||
Interpreter.ecmaVersion = 5; // alert.call(globalContextInFunction, 1); | ||
// fix: alert.call({}, 1); // Illegal invocation | ||
// function func(){ | ||
// this;// Interpreter.globalContextInFunction | ||
// } | ||
// func() | ||
Interpreter.rootContext = void 0; | ||
Interpreter.globalContextInFunction = void 0; | ||
Interpreter.global = Object.create(null); |
@@ -25,3 +25,5 @@ import { Interpreter } from "./interpreter/main"; // TODO: | ||
ecmaVersion: options.ecmaVersion, | ||
timeout: timeout | ||
timeout: timeout, | ||
rootContext: options.rootContext, | ||
globalContextInFunction: options.globalContextInFunction | ||
}); | ||
@@ -28,0 +30,0 @@ return interpreter.evaluate(wrapCode); |
import { MessageItem } from "./messages"; | ||
import { Node, ESTree } from "./nodes"; | ||
declare const IEval: unique symbol; | ||
declare const IFunction: unique symbol; | ||
declare type Getter = () => any; | ||
@@ -20,3 +18,5 @@ interface BaseClosure { | ||
timeout?: number; | ||
initEnv?: (inst: Interpreter) => void; | ||
rootContext?: Context | null; | ||
globalContextInFunction?: any; | ||
_initEnv?: (this: Interpreter) => void; | ||
} | ||
@@ -29,24 +29,54 @@ interface CollectDeclarations { | ||
[prop: number]: any; | ||
[IEval]?: (code: string, useGlobalScope: boolean) => any; | ||
[IFunction]?: (...params: string[]) => (...args: any[]) => any; | ||
}; | ||
declare type Context = { | ||
[prop: string]: any; | ||
[prop: number]: any; | ||
}; | ||
interface GeneratorReflection { | ||
getOptions(): Readonly<Options>; | ||
getCurrentScope(): Scope; | ||
getGlobalScope(): Scope; | ||
getCurrentContext(): Context; | ||
getExecStartTime(): number; | ||
} | ||
declare class InternalInternalReflection { | ||
protected interpreter: Interpreter; | ||
constructor(interpreter: Interpreter); | ||
generator(): GeneratorReflection; | ||
} | ||
declare function internalEval(reflection: InternalInternalReflection, code?: string, useGlobalScope?: boolean): any; | ||
declare function internalFunction(reflection: InternalInternalReflection, ...params: string[]): (...args: any[]) => any; | ||
/** | ||
* scope chain | ||
* | ||
* superScope | ||
* ↓ | ||
* rootScope | ||
* ↓ | ||
* globalScope | ||
* ↓ | ||
* functionScope | ||
* | ||
*/ | ||
declare class Scope { | ||
name: string | undefined; | ||
parent: Scope | null; | ||
data: ScopeData; | ||
readonly name: string | undefined; | ||
readonly parent: Scope | null; | ||
readonly data: ScopeData; | ||
labelStack: string[]; | ||
constructor(data: ScopeData, parent?: Scope | null, name?: string); | ||
} | ||
declare type Context = { | ||
[prop: string]: any; | ||
[prop: number]: any; | ||
}; | ||
export declare class Interpreter { | ||
value: any; | ||
static readonly version: string; | ||
static readonly eval: typeof internalEval; | ||
static readonly Function: typeof internalFunction; | ||
static ecmaVersion: ECMA_VERSION; | ||
static globalContextInFunction: any; | ||
static global: Context; | ||
protected value: any; | ||
protected context: Context | Scope; | ||
protected rootContext: Context; | ||
protected globalContext: Context; | ||
protected source: string; | ||
protected sourceList: string[]; | ||
protected currentScope: Scope; | ||
protected rootScope: Scope; | ||
protected globalScope: Scope; | ||
protected currentContext: Context; | ||
@@ -62,12 +92,13 @@ protected options: Options; | ||
protected execEndTime: number; | ||
static readonly version = "1.3.1"; | ||
static readonly eval: symbol; | ||
static readonly Function: symbol; | ||
static ecmaVersion: ECMA_VERSION; | ||
static rootContext: undefined; | ||
static global: any; | ||
constructor(context?: Context | Scope, options?: Options); | ||
protected initEnvironment(ctx: Context | Scope): void; | ||
isInterruptThrow<T>(err: T): boolean; | ||
getSuperScope(ctx: Context): Scope; | ||
getExecStartTime(): number; | ||
getExecutionTime(): number; | ||
setExecTimeout(timeout?: number): void; | ||
getOptions(): Readonly<Options>; | ||
protected getGlobalScope(): Scope; | ||
protected getCurrentScope(): Scope; | ||
protected getCurrentContext(): Context; | ||
protected isInterruptThrow<T>(err: T): boolean; | ||
protected createSuperScope(ctx: Context): Scope; | ||
protected setCurrentContext(ctx: Context): void; | ||
@@ -77,32 +108,31 @@ protected setCurrentScope(scope: Scope): void; | ||
appendCode(code: string): any; | ||
evaluateNode(node: ESTree.Program, source?: string): any; | ||
getExecutionTime(): number; | ||
createErrorMessage(msg: MessageItem, value: string | number, node?: Node | null): string; | ||
createError<T>(message: string, error: { | ||
protected evaluateNode(node: ESTree.Program, source?: string): any; | ||
protected createErrorMessage(msg: MessageItem, value: string | number, node?: Node | null): string; | ||
protected createError<T>(message: string, error: { | ||
new (msg: string): T; | ||
}): T; | ||
createThrowError<T>(message: string, error: { | ||
protected createThrowError<T>(message: string, error: { | ||
new (msg: string): T; | ||
}): T; | ||
createInternalThrowError<T extends MessageItem>(msg: T, value: string | number, node?: Node | null): Error; | ||
setExecTimeout(timeout?: number): void; | ||
protected createInternalThrowError<T extends MessageItem>(msg: T, value: string | number, node?: Node | null): Error; | ||
protected checkTimeout(): boolean; | ||
getNodePosition(node: (Node & { | ||
protected getNodePosition(node: (Node & { | ||
start?: number; | ||
end?: number; | ||
}) | null): string; | ||
createClosure(node: Node): BaseClosure; | ||
binaryExpressionHandler(node: ESTree.BinaryExpression): BaseClosure; | ||
logicalExpressionHandler(node: ESTree.LogicalExpression): BaseClosure; | ||
unaryExpressionHandler(node: ESTree.UnaryExpression): BaseClosure; | ||
updateExpressionHandler(node: ESTree.UpdateExpression): BaseClosure; | ||
objectExpressionHandler(node: ESTree.ObjectExpression): () => {}; | ||
arrayExpressionHandler(node: ESTree.ArrayExpression): () => any[]; | ||
safeObjectGet(obj: any, key: any, node: Node): any; | ||
createCallFunctionGetter(node: Node & { | ||
protected createClosure(node: Node): BaseClosure; | ||
protected binaryExpressionHandler(node: ESTree.BinaryExpression): BaseClosure; | ||
protected logicalExpressionHandler(node: ESTree.LogicalExpression): BaseClosure; | ||
protected isRootScope(node: ESTree.Expression | ESTree.Pattern): boolean; | ||
protected unaryExpressionHandler(node: ESTree.UnaryExpression): BaseClosure; | ||
protected updateExpressionHandler(node: ESTree.UpdateExpression): BaseClosure; | ||
protected objectExpressionHandler(node: ESTree.ObjectExpression): () => {}; | ||
protected arrayExpressionHandler(node: ESTree.ArrayExpression): () => any[]; | ||
protected safeObjectGet(obj: any, key: any, node: Node): any; | ||
protected createCallFunctionGetter(node: Node & { | ||
start?: number; | ||
end?: number; | ||
}): () => any; | ||
callExpressionHandler(node: ESTree.CallExpression): BaseClosure; | ||
functionExpressionHandler(node: (ESTree.FunctionExpression & { | ||
protected callExpressionHandler(node: ESTree.CallExpression): BaseClosure; | ||
protected functionExpressionHandler(node: (ESTree.FunctionExpression & { | ||
start?: number; | ||
@@ -114,7 +144,7 @@ end?: number; | ||
})): BaseClosure; | ||
newExpressionHandler(node: ESTree.NewExpression): BaseClosure; | ||
memberExpressionHandler(node: ESTree.MemberExpression): BaseClosure; | ||
thisExpressionHandler(node: ESTree.ThisExpression): BaseClosure; | ||
sequenceExpressionHandler(node: ESTree.SequenceExpression): BaseClosure; | ||
literalHandler(node: ESTree.Literal & { | ||
protected newExpressionHandler(node: ESTree.NewExpression): BaseClosure; | ||
protected memberExpressionHandler(node: ESTree.MemberExpression): BaseClosure; | ||
protected thisExpressionHandler(node: ESTree.ThisExpression): BaseClosure; | ||
protected sequenceExpressionHandler(node: ESTree.SequenceExpression): BaseClosure; | ||
protected literalHandler(node: ESTree.Literal & { | ||
regex?: { | ||
@@ -125,44 +155,42 @@ pattern: string; | ||
}): BaseClosure; | ||
identifierHandler(node: ESTree.Identifier): BaseClosure; | ||
assignmentExpressionHandler(node: ESTree.AssignmentExpression): BaseClosure; | ||
functionDeclarationHandler(node: ESTree.FunctionDeclaration): BaseClosure; | ||
getVariableName(node: ESTree.Pattern): never | string; | ||
variableDeclarationHandler(node: ESTree.VariableDeclaration): BaseClosure; | ||
assertVariable(data: ScopeData, name: string, node: Node): void | never; | ||
programHandler(node: ESTree.Program | ESTree.BlockStatement): BaseClosure; | ||
expressionStatementHandler(node: ESTree.ExpressionStatement): BaseClosure; | ||
emptyStatementHandler(node: Node): BaseClosure; | ||
returnStatementHandler(node: ESTree.ReturnStatement): BaseClosure; | ||
ifStatementHandler(node: ESTree.IfStatement | ESTree.ConditionalExpression): BaseClosure; | ||
conditionalExpressionHandler(node: ESTree.ConditionalExpression): BaseClosure; | ||
forStatementHandler(node: ESTree.ForStatement | ESTree.WhileStatement | ESTree.DoWhileStatement): BaseClosure; | ||
whileStatementHandler(node: ESTree.WhileStatement): BaseClosure; | ||
doWhileStatementHandler(node: ESTree.DoWhileStatement): BaseClosure; | ||
forInStatementHandler(node: ESTree.ForInStatement): BaseClosure; | ||
withStatementHandler(node: ESTree.WithStatement): BaseClosure; | ||
throwStatementHandler(node: ESTree.ThrowStatement): BaseClosure; | ||
tryStatementHandler(node: ESTree.TryStatement): BaseClosure; | ||
catchClauseHandler(node: ESTree.CatchClause): (e: Error) => any; | ||
continueStatementHandler(node: ESTree.ContinueStatement): BaseClosure; | ||
breakStatementHandler(node: ESTree.BreakStatement): BaseClosure; | ||
switchStatementHandler(node: ESTree.SwitchStatement): BaseClosure; | ||
switchCaseHandler(node: ESTree.SwitchCase): SwitchCaseClosure; | ||
labeledStatementHandler(node: ESTree.LabeledStatement): BaseClosure; | ||
debuggerStatementHandler(node: ESTree.DebuggerStatement): BaseClosure; | ||
createParamNameGetter(node: ESTree.Pattern): ReturnStringClosure; | ||
createObjectKeyGetter(node: ESTree.Expression): Getter; | ||
createMemberKeyGetter(node: ESTree.MemberExpression): Getter; | ||
createObjectGetter(node: ESTree.Expression | ESTree.Pattern): Getter; | ||
createNameGetter(node: ESTree.Expression | ESTree.Pattern): Getter; | ||
varDeclaration(name: string): void; | ||
funcDeclaration(name: string, func: () => any): void; | ||
addDeclarationsToScope(declVars: CollectDeclarations, declFuncs: CollectDeclarations, scope: Scope): void; | ||
getScopeValue(name: string, startScope: Scope): any; | ||
getScopeDataFromName(name: string, startScope: Scope): ScopeData; | ||
getScopeFromName(name: string, startScope: Scope): Scope; | ||
getCurrentScope(): Scope; | ||
getCurrentContext(): Context; | ||
setValue(value: any): any; | ||
protected identifierHandler(node: ESTree.Identifier): BaseClosure; | ||
protected assignmentExpressionHandler(node: ESTree.AssignmentExpression): BaseClosure; | ||
protected functionDeclarationHandler(node: ESTree.FunctionDeclaration): BaseClosure; | ||
protected getVariableName(node: ESTree.Pattern): never | string; | ||
protected variableDeclarationHandler(node: ESTree.VariableDeclaration): BaseClosure; | ||
protected assertVariable(data: ScopeData, name: string, node: Node): void | never; | ||
protected programHandler(node: ESTree.Program | ESTree.BlockStatement): BaseClosure; | ||
protected expressionStatementHandler(node: ESTree.ExpressionStatement): BaseClosure; | ||
protected emptyStatementHandler(node: Node): BaseClosure; | ||
protected returnStatementHandler(node: ESTree.ReturnStatement): BaseClosure; | ||
protected ifStatementHandler(node: ESTree.IfStatement | ESTree.ConditionalExpression): BaseClosure; | ||
protected conditionalExpressionHandler(node: ESTree.ConditionalExpression): BaseClosure; | ||
protected forStatementHandler(node: ESTree.ForStatement | ESTree.WhileStatement | ESTree.DoWhileStatement): BaseClosure; | ||
protected whileStatementHandler(node: ESTree.WhileStatement): BaseClosure; | ||
protected doWhileStatementHandler(node: ESTree.DoWhileStatement): BaseClosure; | ||
protected forInStatementHandler(node: ESTree.ForInStatement): BaseClosure; | ||
protected withStatementHandler(node: ESTree.WithStatement): BaseClosure; | ||
protected throwStatementHandler(node: ESTree.ThrowStatement): BaseClosure; | ||
protected tryStatementHandler(node: ESTree.TryStatement): BaseClosure; | ||
protected catchClauseHandler(node: ESTree.CatchClause): (e: Error) => any; | ||
protected continueStatementHandler(node: ESTree.ContinueStatement): BaseClosure; | ||
protected breakStatementHandler(node: ESTree.BreakStatement): BaseClosure; | ||
protected switchStatementHandler(node: ESTree.SwitchStatement): BaseClosure; | ||
protected switchCaseHandler(node: ESTree.SwitchCase): SwitchCaseClosure; | ||
protected labeledStatementHandler(node: ESTree.LabeledStatement): BaseClosure; | ||
protected debuggerStatementHandler(node: ESTree.DebuggerStatement): BaseClosure; | ||
protected createParamNameGetter(node: ESTree.Pattern): ReturnStringClosure; | ||
protected createObjectKeyGetter(node: ESTree.Expression): Getter; | ||
protected createMemberKeyGetter(node: ESTree.MemberExpression): Getter; | ||
protected createObjectGetter(node: ESTree.Expression | ESTree.Pattern): Getter; | ||
protected createNameGetter(node: ESTree.Expression | ESTree.Pattern): Getter; | ||
protected varDeclaration(name: string): void; | ||
protected funcDeclaration(name: string, func: () => any): void; | ||
protected addDeclarationsToScope(declVars: CollectDeclarations, declFuncs: CollectDeclarations, scope: Scope): void; | ||
protected getScopeValue(name: string, startScope: Scope): any; | ||
protected getScopeDataFromName(name: string, startScope: Scope): ScopeData; | ||
protected getScopeFromName(name: string, startScope: Scope): Scope; | ||
protected setValue(value: any): any; | ||
getValue(): any; | ||
} | ||
export {}; |
import { parse } from "acorn"; | ||
import { Messages, InterruptThrowError, InterruptThrowReferenceError, InterruptThrowSyntaxError, } from "./messages"; | ||
const version = "1.3.1"; | ||
const version = "%VERSION%"; | ||
function defineFunctionName(func, name) { | ||
@@ -17,7 +17,81 @@ Object.defineProperty(func, "name", { | ||
const EmptyStatementReturn = Symbol("EmptyStatementReturn"); | ||
const IEval = Symbol("IEval"); | ||
const IFunction = Symbol("IFunction"); | ||
function isFunction(func) { | ||
return typeof func === "function"; | ||
} | ||
class InternalInternalReflection { | ||
constructor(interpreter) { | ||
this.interpreter = interpreter; | ||
} | ||
generator() { | ||
const interpreter = this.interpreter; | ||
function getCurrentScope() { | ||
return this.getCurrentScope(); | ||
} | ||
function getGlobalScope() { | ||
return this.getGlobalScope(); | ||
} | ||
function getCurrentContext() { | ||
return this.getCurrentContext(); | ||
} | ||
return { | ||
getOptions: interpreter.getOptions.bind(interpreter), | ||
getCurrentScope: getCurrentScope.bind(interpreter), | ||
getGlobalScope: getGlobalScope.bind(interpreter), | ||
getCurrentContext: getCurrentContext.bind(interpreter), | ||
getExecStartTime: interpreter.getExecStartTime.bind(interpreter), | ||
}; | ||
} | ||
} | ||
function internalEval(reflection, code, useGlobalScope = true) { | ||
if (!(reflection instanceof InternalInternalReflection)) { | ||
throw new Error("Illegal call"); | ||
} | ||
if (typeof code !== "string") | ||
return code; | ||
if (!code) | ||
return void 0; | ||
const instance = reflection.generator(); | ||
const opts = instance.getOptions(); | ||
const options = { | ||
timeout: opts.timeout, | ||
_initEnv: function () { | ||
// set caller context | ||
if (!useGlobalScope) { | ||
this.setCurrentContext(instance.getCurrentContext()); | ||
} | ||
// share timeout | ||
this.execStartTime = instance.getExecStartTime(); | ||
this.execEndTime = this.execStartTime; | ||
}, | ||
}; | ||
const currentScope = useGlobalScope ? instance.getGlobalScope() : instance.getCurrentScope(); | ||
const interpreter = new Interpreter(currentScope, options); | ||
return interpreter.evaluate(code); | ||
} | ||
Object.defineProperty(internalEval, "__IS_EVAL_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false, | ||
}); | ||
function internalFunction(reflection, ...params) { | ||
if (!(reflection instanceof InternalInternalReflection)) { | ||
throw new Error("Illegal call"); | ||
} | ||
const instance = reflection.generator(); | ||
const code = params.pop(); | ||
const interpreter = new Interpreter(instance.getGlobalScope(), instance.getOptions()); | ||
const wrapCode = ` | ||
(function anonymous(${params.join(",")}){ | ||
${code} | ||
}); | ||
`; | ||
return interpreter.evaluate(wrapCode); | ||
} | ||
Object.defineProperty(internalFunction, "__IS_FUNCTION_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false, | ||
}); | ||
class Return { | ||
@@ -38,2 +112,14 @@ constructor(value) { | ||
} | ||
/** | ||
* scope chain | ||
* | ||
* superScope | ||
* ↓ | ||
* rootScope | ||
* ↓ | ||
* globalScope | ||
* ↓ | ||
* functionScope | ||
* | ||
*/ | ||
class Scope { | ||
@@ -76,2 +162,4 @@ constructor(data, parent = null, name) { | ||
unescape, | ||
eval: internalEval, | ||
Function: internalFunction, | ||
}; | ||
@@ -118,7 +206,11 @@ // ES5 Object | ||
timeout: options.timeout || 0, | ||
initEnv: options.initEnv, | ||
rootContext: options.rootContext, | ||
globalContextInFunction: options.globalContextInFunction === undefined | ||
? Interpreter.globalContextInFunction | ||
: options.globalContextInFunction, | ||
_initEnv: options._initEnv, | ||
}; | ||
this.context = context; | ||
this.context = context || Object.create(null); | ||
this.callStack = []; | ||
this.initEnvironment(context); | ||
this.initEnvironment(this.context); | ||
} | ||
@@ -132,18 +224,13 @@ initEnvironment(ctx) { | ||
else { | ||
const superScope = this.getSuperScope(ctx); | ||
// replace Interpreter.eval and Interpreter.Function | ||
Object.keys(ctx).forEach(key => { | ||
if (ctx[key] === IEval) { | ||
ctx[key] = superScope.data[IEval]; | ||
} | ||
if (ctx[key] === IFunction) { | ||
ctx[key] = superScope.data[IFunction]; | ||
} | ||
}); | ||
scope = new Scope(ctx, superScope, "root"); | ||
let rootScope = null; | ||
const superScope = this.createSuperScope(ctx); | ||
if (this.options.rootContext) { | ||
rootScope = new Scope(this.options.rootContext, superScope, "rootScope"); | ||
} | ||
scope = new Scope(ctx, rootScope || superScope, "globalScope"); | ||
} | ||
this.rootScope = scope; | ||
this.currentScope = this.rootScope; | ||
//init global context == this | ||
this.rootContext = scope.data; | ||
this.globalScope = scope; | ||
this.currentScope = this.globalScope; | ||
//init global context to this | ||
this.globalContext = scope.data; | ||
this.currentContext = scope.data; | ||
@@ -155,7 +242,28 @@ // collect var/function declare | ||
this.execEndTime = this.execStartTime; | ||
const initEnv = this.options.initEnv; | ||
if (initEnv) { | ||
initEnv(this); | ||
const _initEnv = this.options._initEnv; | ||
if (_initEnv) { | ||
_initEnv.call(this); | ||
} | ||
} | ||
getExecStartTime() { | ||
return this.execStartTime; | ||
} | ||
getExecutionTime() { | ||
return this.execEndTime - this.execStartTime; | ||
} | ||
setExecTimeout(timeout = 0) { | ||
this.options.timeout = timeout; | ||
} | ||
getOptions() { | ||
return this.options; | ||
} | ||
getGlobalScope() { | ||
return this.globalScope; | ||
} | ||
getCurrentScope() { | ||
return this.currentScope; | ||
} | ||
getCurrentContext() { | ||
return this.currentContext; | ||
} | ||
isInterruptThrow(err) { | ||
@@ -166,49 +274,7 @@ return (err instanceof InterruptThrowError || | ||
} | ||
getSuperScope(ctx) { | ||
let data = Object.assign({}, BuildInObjects); | ||
data.eval = (code, useGlobalScope = true) => { | ||
if (typeof code !== "string") | ||
return code; | ||
if (!code) | ||
return void 0; | ||
const options = { | ||
timeout: this.options.timeout, | ||
initEnv: inst => { | ||
// set caller context | ||
if (!useGlobalScope) { | ||
inst.setCurrentContext(this.getCurrentContext()); | ||
} | ||
inst.execStartTime = this.execStartTime; | ||
inst.execEndTime = inst.execStartTime; | ||
}, | ||
}; | ||
const currentScope = useGlobalScope ? this.rootScope : this.getCurrentScope(); | ||
const interpreter = new Interpreter(currentScope, options); | ||
return interpreter.evaluate(code); | ||
createSuperScope(ctx) { | ||
let data = { | ||
...BuildInObjects, | ||
}; | ||
Object.defineProperty(data.eval, "__IS_EVAL_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false, | ||
}); | ||
data.Function = (...params) => { | ||
const code = params.pop(); | ||
const interpreter = new Interpreter(this.rootScope, this.options); | ||
const wrapCode = ` | ||
(function anonymous(${params.join(",")}){ | ||
${code} | ||
}); | ||
`; | ||
return interpreter.evaluate(wrapCode); | ||
}; | ||
Object.defineProperty(data.Function, "__IS_FUNCTION_FUNC", { | ||
value: true, | ||
writable: false, | ||
enumerable: false, | ||
configurable: false, | ||
}); | ||
const buildInObjectKeys = Object.keys(data); | ||
data[IEval] = data.eval; | ||
data[IFunction] = data.Function; | ||
buildInObjectKeys.forEach(key => { | ||
@@ -219,3 +285,3 @@ if (key in ctx) { | ||
}); | ||
return new Scope(data, null, "superRoot"); | ||
return new Scope(data, null, "superScope"); | ||
} | ||
@@ -266,5 +332,2 @@ setCurrentContext(ctx) { | ||
} | ||
getExecutionTime() { | ||
return this.execEndTime - this.execStartTime; | ||
} | ||
createErrorMessage(msg, value, node) { | ||
@@ -286,5 +349,2 @@ let message = msg[1].replace("%0", String(value)); | ||
} | ||
setExecTimeout(timeout = 0) { | ||
this.options.timeout = timeout; | ||
} | ||
checkTimeout() { | ||
@@ -500,2 +560,9 @@ if (!this.isRunning) | ||
} | ||
isRootScope(node) { | ||
if (node.type === "Identifier") { | ||
const scope = this.getScopeFromName(node.name, this.getCurrentScope()); | ||
return scope.name === "rootScope"; | ||
} | ||
return false; | ||
} | ||
// typeof a !a() | ||
@@ -508,2 +575,6 @@ unaryExpressionHandler(node) { | ||
return () => { | ||
// not allowed to delete root scope property | ||
if (this.isRootScope(node.argument)) { | ||
return false; | ||
} | ||
let obj = objectGetter(); | ||
@@ -664,12 +735,27 @@ const name = nameGetter(); | ||
} | ||
// obj.eval = eval | ||
// obj.eval(...) | ||
if (func.__IS_EVAL_FUNC) { | ||
return (code) => { | ||
return func(code, true); | ||
return func(new InternalInternalReflection(this), code, true); | ||
}; | ||
} | ||
// obj.func = Function | ||
// obj.func(...) | ||
if (func.__IS_FUNCTION_FUNC) { | ||
return (...args) => { | ||
return func(new InternalInternalReflection(this), ...args); | ||
}; | ||
} | ||
// method call | ||
// eg:obj.say(...) | ||
// eg: obj.say.call(...) | ||
// eg: obj.say.apply(...) | ||
// ====================== | ||
// obj.func(...) | ||
// func = func.bind(obj) | ||
// tips: | ||
// test.call(ctx, ...) === test.call.bind(test)(ctx, ...) | ||
// test.apply(ctx, ...) === test.apply.bind(test)(ctx, ...) | ||
// test.f(...) === test.f.bind(test)(...) | ||
// func(...) -> func.bind(obj)(...) | ||
// func.call(...) -> obj.func.call.bind(obj.func)(...) | ||
// func.apply(...) -> obj.func.apply.bind(obj.func)(...) | ||
// ...others | ||
@@ -679,3 +765,3 @@ return func.bind(obj); | ||
default: | ||
// test() or (0.test)() or a[1]() ... | ||
// test() or (0,test)() or a[1]() ... | ||
const closure = this.createClosure(node); | ||
@@ -693,13 +779,31 @@ return () => { | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval | ||
// calling eval scope check | ||
// var geval = eval; | ||
// geval("a+1"); | ||
if (node.type === "Identifier" && func.__IS_EVAL_FUNC) { | ||
// var eval = eval; | ||
// function test(){ | ||
// eval(...); //note: use local scope in eval5,but in Browser is use global scope | ||
// } | ||
if (node.type === "Identifier" && func.__IS_EVAL_FUNC && name === "eval") { | ||
return (code) => { | ||
const scope = this.getScopeFromName(name, this.getCurrentScope()); | ||
const isSuperScope = !scope.parent || this.rootScope === scope; | ||
const useGlobalScope = !scope.parent || | ||
this.globalScope === scope || | ||
scope.name === "rootScope"; | ||
// use local scope if calling eval in super scope | ||
return func(code, !isSuperScope); | ||
return func(new InternalInternalReflection(this), code, !useGlobalScope); | ||
}; | ||
} | ||
// use global scope | ||
// var g_eval = eval; | ||
// g_eval("a+1"); | ||
//(0,eval)(...) ...eval alias | ||
if (func.__IS_EVAL_FUNC) { | ||
return (code) => { | ||
return func(new InternalInternalReflection(this), code, true); | ||
}; | ||
} | ||
// Function('a', 'b', 'return a+b') | ||
if (func.__IS_FUNCTION_FUNC) { | ||
return (...args) => { | ||
return func(new InternalInternalReflection(this), ...args); | ||
}; | ||
} | ||
// function call | ||
@@ -709,3 +813,4 @@ // this = undefined | ||
// test(...) === test.call(undefined, ...) | ||
return func.bind(Interpreter.rootContext); | ||
// fix: alert.call({}, ...) Illegal invocation | ||
return func.bind(this.options.globalContextInFunction); | ||
}; | ||
@@ -807,3 +912,3 @@ } | ||
const construct = expression(); | ||
if (!isFunction(construct)) { | ||
if (!isFunction(construct) || construct.__IS_EVAL_FUNC) { | ||
const callee = node.callee; | ||
@@ -813,2 +918,6 @@ const name = source.slice(callee.start, callee.end); | ||
} | ||
// new Function(...) | ||
if (construct.__IS_FUNCTION_FUNC) { | ||
return construct(new InternalInternalReflection(this), ...args.map(arg => arg())); | ||
} | ||
return new construct(...args.map(arg => arg())); | ||
@@ -990,3 +1099,3 @@ }; | ||
assertVariable(data, name, node) { | ||
if (data === this.rootScope.data && !(name in data)) { | ||
if (data === this.globalScope.data && !(name in data)) { | ||
throw this.createInternalThrowError(Messages.VariableUndefinedReferenceError, name, node); | ||
@@ -1168,3 +1277,3 @@ } | ||
// newScope.data = data; | ||
// copy all property | ||
// copy all properties | ||
for (let k in data) { | ||
@@ -1475,10 +1584,4 @@ newScope.data[k] = data[k]; | ||
} while ((scope = scope.parent)); | ||
return this.rootScope; | ||
return this.globalScope; | ||
} | ||
getCurrentScope() { | ||
return this.currentScope; | ||
} | ||
getCurrentContext() { | ||
return this.currentContext; | ||
} | ||
setValue(value) { | ||
@@ -1503,8 +1606,12 @@ const isFunctionCall = this.callStack.length; | ||
Interpreter.version = version; | ||
Interpreter.eval = IEval; | ||
Interpreter.Function = IFunction; | ||
Interpreter.eval = internalEval; | ||
Interpreter.Function = internalFunction; | ||
Interpreter.ecmaVersion = 5; | ||
// alert.call(rootContext, 1); | ||
// But alert({}, 1); // Illegal invocation | ||
Interpreter.rootContext = void 0; | ||
// alert.call(globalContextInFunction, 1); | ||
// fix: alert.call({}, 1); // Illegal invocation | ||
// function func(){ | ||
// this;// Interpreter.globalContextInFunction | ||
// } | ||
// func() | ||
Interpreter.globalContextInFunction = void 0; | ||
Interpreter.global = Object.create(null); |
@@ -9,2 +9,4 @@ export declare type VMContext = { | ||
ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020; | ||
rootContext?: VMContext | null; | ||
globalContextInFunction?: any; | ||
} | ||
@@ -14,2 +16,4 @@ export interface ScriptOptions { | ||
timeout?: number; | ||
rootContext?: VMContext | null; | ||
globalContextInFunction?: any; | ||
} |
@@ -18,2 +18,4 @@ import { Interpreter } from "./interpreter/main"; | ||
timeout, | ||
rootContext: options.rootContext, | ||
globalContextInFunction: options.globalContextInFunction, | ||
}); | ||
@@ -20,0 +22,0 @@ return interpreter.evaluate(wrapCode); |
{ | ||
"name": "eval5", | ||
"version": "1.3.1", | ||
"description": "A JavaScript interpreter, written completely in JavaScript", | ||
"version": "1.4.0", | ||
"description": "A JavaScript interpreter written in JavaScript", | ||
"main": "./dist/cjs/index.js", | ||
@@ -10,3 +10,3 @@ "module": "./dist/esm/index.js", | ||
"start": "tsc -w", | ||
"build": "run-s clear build:* bundle bundle:min", | ||
"build": "run-s clear build:* bundle:dev bundle:prod bundle:banner", | ||
"build:lib": "tsc", | ||
@@ -16,4 +16,5 @@ "build:cjs": "babel lib --config-file=./babel.config.js --out-dir dist/cjs", | ||
"clear": "rimraf lib dist umd", | ||
"bundle": "packez bundle ./src/index.ts -d umd -c", | ||
"bundle:min": "packez bundle ./src/index.ts -d umd --state min", | ||
"bundle:dev": "packez bundle ./src/index.ts -d umd -c", | ||
"bundle:prod": "packez bundle ./src/index.ts -d umd --state prod", | ||
"bundle:banner": "node scripts/banner.js", | ||
"test": "jest" | ||
@@ -47,4 +48,7 @@ }, | ||
"@babel/cli": "^7.8.4", | ||
"@types/fs-extra": "^8.1.0", | ||
"@types/jest": "^24.0.25", | ||
"babel-plugin-search-and-replace": "^1.0.1", | ||
"babel-preset-packez": "^1.0.0", | ||
"fs-extra": "^8.1.0", | ||
"jest": "^24.9.0", | ||
@@ -51,0 +55,0 @@ "npm-run-all": "^4.1.5", |
223
README.md
@@ -7,26 +7,29 @@ # eval5 | ||
基于 JavaScript 编写的 JavaScript 解释器;A JavaScript interpreter, written completely in JavaScript; | ||
A JavaScript interpreter written in JavaScript. | ||
支持es5语法 | ||
[Try it out](https://bplok20010.github.io/eval5/) | ||
> 解决在不支持`eval`或`Function`的执行环境下执行 JavaScript 代码。例如:微信小程序 [示例](https://github.com/bplok20010/eval5-wx-demo)。 | ||
## You may not need it unless | ||
## Usage | ||
- Need to execute code in the browser with a sandbox environment | ||
- Controlling execution time | ||
- JavaScript runtime environment that does not support `eval` and `Function`. for example: WeChat Mini Program [demo](https://github.com/bplok20010/eval5-wx-demo) | ||
- Be interested or Be curious | ||
`npm install --save eval5` | ||
## Support | ||
```javascript | ||
import { evaluate, Function, vm, Interpreter } from "eval5"; | ||
ECMA5 | ||
// 设置默认作用域 | ||
Interpreter.global = window; | ||
## Install | ||
//或 evaluate("1+1", Object.create(window)); | ||
evaluate("1+1", window); // 2 | ||
``` | ||
npm install --save eval5 | ||
``` | ||
const func = new Function("a", "b", "return a+b;"); | ||
## Usage | ||
console.log(func(1, 1)); // 2 | ||
```javascript | ||
import { Interpreter } from "eval5"; | ||
const interpreter = new Interpreter(ctx, { | ||
const interpreter = new Interpreter(window, { | ||
timeout: 1000, | ||
@@ -39,118 +42,157 @@ }); | ||
result = interpreter.evaluate("1+1"); | ||
console.log(result); //2 | ||
console.log(result); | ||
interpreter.evaluate("var a=100"); | ||
interpreter.evaluate("var b=200"); | ||
result = interpreter.evaluate("a+b"); | ||
console.log(result); | ||
} catch (e) { | ||
//.. | ||
console.log(e); | ||
} | ||
``` | ||
## Options | ||
```ts | ||
interface Options { | ||
timeout?: number; | ||
rootContext?: {} | null; | ||
globalContextInFunction?: any; | ||
} | ||
``` | ||
## Interpreter | ||
### static `version` | ||
**`version`** | ||
VERSION | ||
current version | ||
### static `global` | ||
**`global`** | ||
`object` 默认:`Object.create(null)` | ||
default: `{}` | ||
设置默认作用域对象 | ||
global context | ||
例如: | ||
```javascript | ||
```js | ||
Interpreter.global = window; | ||
const interpreter = new Interpreter(); | ||
``` | ||
### static `eval` | ||
**`globalContextInFunction`** | ||
`readonly` | ||
default: `undefined` | ||
替代原有的`eval`占位符 | ||
`eval5` does not support `use strict` mode, but the default value of `this` in function calls is `undefined`, you can set this property as the default. | ||
> 如果执行环境支持 eval 函数建议使用原生的 eval,除非 eval 需要使用局部变量时,如下情况: | ||
```js | ||
import { Interpreter } from "Interpreter"; | ||
```javascript | ||
const ctx = Object.create(window); | ||
const ctx = {}; | ||
const interpreter = new Interpreter(ctx); | ||
interpreter.evaluate(` | ||
this; // ctx | ||
function func(){ | ||
return this; // undefined | ||
} | ||
func(); | ||
`); | ||
``` | ||
ctx.eval = Interpreter.eval; | ||
```js | ||
import { Interpreter } from "Interpreter"; | ||
const interpreter = new Interpreter(ctx); | ||
Interpreter.globalContextInFunction = window; | ||
const ctx = {}; | ||
const interpreter = new Interpreter({}); | ||
interpreter.evaluate(` | ||
function test(){ | ||
var a = 1; | ||
return eval('a+1') | ||
} | ||
test(); | ||
`); // output 2 | ||
this; // ctx | ||
function func(){ | ||
return this; // window | ||
} | ||
func(); | ||
`); | ||
``` | ||
### static `Function` | ||
**Note: Illegal invocation** | ||
`readonly` | ||
e.g. | ||
替代原有的`Function`占位符 | ||
``` | ||
import { Interpreter } from "Interpreter"; | ||
作用同`Interpreter.eval` | ||
Interpreter.globalContextInFunction = {}; | ||
> 除非不支持`Function`的环境,否则不建议使用 | ||
const ctx = {alert: alert}; | ||
### static `ecmaVersion` | ||
const interpreter = new Interpreter(ctx); | ||
可选值: `3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020` | ||
interpreter.evaluate(` | ||
// alert.call({}, 'Hello eval5') | ||
// Illegal invocation | ||
alert('Hello eval5'); | ||
`); | ||
``` | ||
默认: `5` | ||
**`constructor(context?: {}: options: Options = Interpreter.global)`** | ||
> 注:eval5 只支持 es5 语法,如果将 ecmaVersion 设为高版本尽管能编译通过,但解释时可能会报错或得到错误结果。 | ||
## Instance methods | ||
例如,如果设`ecmaVersion=6`或更高,以下代码可以正常解析执行,但结果非预期: | ||
**`evaluate(code: string): any`** | ||
``` | ||
const a = []; | ||
for(let i = 0; i < 10; i++) { | ||
a.push(function(){ | ||
console.log(i); | ||
}) | ||
} | ||
executes string code and returns the value of the last expression | ||
... | ||
```js | ||
import { Interpreter } from "Interpreter"; | ||
// output: 10 10 10... | ||
``` | ||
const interpreter = new Interpreter(window); | ||
**原因在于解释器会忽略`const` `let`类型,都当作`var`处理。** | ||
const result = interpreter.evaluate(` | ||
var a = 100; | ||
var b = 200; | ||
### `constructor`(ctx: {}, options?: { timeout?: number}) | ||
a+b; | ||
构造函数 | ||
`); | ||
```javascript | ||
var interpreter = new Interpreter(window); | ||
console.log(result); // 300 | ||
``` | ||
### `evaluate`(code: string): any | ||
**`appendCode(code: string): any`** | ||
返回脚本中执行的最后一个表达式结果 | ||
alias of `evaluate` | ||
```javascript | ||
var interpreter = new Interpreter(window); | ||
interpreter.evaluate("alert(1+1)"); | ||
``` | ||
**`getExecutionTime(): number`** | ||
### appendCode(code: string): any | ||
get the last execution time | ||
作用同`evaluate` | ||
**`setExecTimeout(): number`** | ||
### setExecTimeout(timeout: number) | ||
set the timeout for each execution | ||
单位:ms | ||
**`getOptions(): Readonly<Options>`** | ||
获取`evaluate`的执行时间 | ||
get interpreter options | ||
## evaluate(code: string, ctx?: {}) | ||
## evaluate(code: string, ctx?: {}, options?: Options) | ||
执行给定的字符串脚本,返回脚本中执行的最后一个表达式结果 | ||
executes string code and returns the value of the last expression | ||
```javascript | ||
evaluate("console.log(1+1)", { console: console }); | ||
> note: a new interpreter is created with every execution | ||
```js | ||
import { evaluate } from "eval5"; | ||
evaluate( | ||
` | ||
var a = 100; | ||
var b = 100; | ||
console.log(a+b); | ||
`, | ||
{ console: console } | ||
); // 200 | ||
evaluate(` | ||
a; | ||
`); // a is not defined | ||
``` | ||
@@ -160,7 +202,9 @@ | ||
同 js 原生的 Function | ||
use `Interpreter.global` as the default context, `Interpreter.globalContextInFunction` also | ||
```javascript | ||
```js | ||
import { Function } from "eval5"; | ||
const func = new Function("a", "b", "return a+b;"); | ||
console.log(func(1, 2)); | ||
console.log(func(100, 200)); // 300 | ||
``` | ||
@@ -170,6 +214,4 @@ | ||
参考 `node.js vm` | ||
see [vm](https://nodejs.org/dist/latest-v13.x/docs/api/vm.html) | ||
支持 api 列表: | ||
- vm.createContext | ||
@@ -185,12 +227,5 @@ - vm.compileFunction | ||
## Support | ||
- ECMA5 | ||
## Related | ||
[evaljs][] | ||
[closure-interpreter][] | ||
[evaljs]: https://github.com/marten-de-vries/evaljs | ||
[closure-interpreter]: https://github.com/int3/closure-interpreter | ||
- [evaljs](https://github.com/marten-de-vries/evaljs) | ||
- [closure-interpreter](https://github.com/int3/closure-interpreter) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1057612
12630
227
10