bkc
Version:
:dog: If there are no dogs in Heaven, then when I die I want to go where they went.
144 lines (143 loc) • 5.26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const check_1 = require("../util/check");
const deepclone_1 = require("../util/deepclone");
const error_1 = require("./error");
const expr_1 = require("./expr");
const instant_1 = require("./instant");
const list_1 = require("./list");
const findVar = (val, vars) => {
for (let i = 0; i < vars.length; i++) {
if (vars[i].name === val) {
return i;
}
}
return -1;
};
const executeExpr = (args, options, previous) => {
const current = args.shift();
const vars = options.vars;
const externalInstants = options.instants;
if (!current) {
return previous;
}
switch (current.type) {
case 'exp':
switch (current.va) {
case '=':
return executeExpr(args, options, previous);
default:
const value = expr_1.default(current.va, previous, executeExpr(args, options));
return executeExpr(args, options, value);
}
case 'num':
case 'str':
return executeExpr(args, options, current.va);
case 'arg':
return current.va.map((value) => {
return executeExpr([value], options, previous);
});
case 'var':
let instantIndex = instant_1.instantList.indexOf(current.va);
if (instantIndex !== -1) {
let result;
try {
result = instant_1.instants[instantIndex].func(executeExpr(args, options, previous));
}
catch (err) {
throw error_1.error(error_1.ERROR_CODE.INSTANT_FUNCTION_EXECUTE_FAILED);
}
return result;
}
let externalInstantIndex = externalInstants.map((externalInstant) => externalInstant.command).indexOf(current.va);
if (externalInstantIndex !== -1) {
let result;
try {
result = externalInstants[externalInstantIndex].func(executeExpr(args, options, previous));
}
catch (err) {
throw error_1.error(error_1.ERROR_CODE.INSTANT_EXTERNAL_FUNCTION_EXECUTE_FAILED);
}
return result;
}
let varIndex = findVar(current.va, vars);
if (varIndex === -1) {
throw error_1.error(error_1.ERROR_CODE.UNDEFINED_VARIABLE);
}
else {
return executeExpr(args, options, vars[varIndex].value);
}
case 'emp':
return executeExpr(args, options, previous);
case 'err':
throw error_1.error(error_1.ERROR_CODE.UNEXPECTED_ARGUMENT);
}
};
const executeRecursive = (astE, reE, options) => {
const ast = deepclone_1.deepCloneArray(astE);
const re = deepclone_1.deepCloneArray(reE);
const current = ast.shift();
const vars = options.vars;
if (!current) {
return re;
}
loop: switch (current.type) {
case 'if':
if (!Boolean(executeExpr(current.args, options))) {
for (let i of ast) {
if (i.type !== 'end') {
i.type = 'skip';
}
else {
break loop;
}
}
throw error_1.error(error_1.ERROR_CODE.STATEMENT_END_NOT_MATCHED);
}
break;
case 'for':
throw error_1.error(error_1.ERROR_CODE.FOR_LOOP_IS_NOT_AVAILABLE);
case 'assign':
let varIndex = findVar(current.val, vars);
if (varIndex !== -1) {
vars[varIndex].value = executeExpr(current.args, options);
}
else {
const currentVar = {
name: current.val,
value: executeExpr(current.args, options),
};
vars.push(currentVar);
}
break;
case 'command':
if (list_1.internalList.indexOf(current.val) !== -1) {
const currentCommand = {
type: 'internal',
value: current.val,
arg: executeExpr(current.args, options),
};
re.push(currentCommand);
}
else {
const currentCommand = {
type: 'external',
value: current.val,
arg: executeExpr(current.args, options),
};
re.push(currentCommand);
}
break;
case 'error':
throw error_1.error(error_1.ERROR_CODE.NAMESPACE_UNAVAILABLE);
case 'skip':
default:
break;
}
return executeRecursive(ast, re, options);
};
const execute = (ast, optionsE) => {
const options = check_1.fixOption(optionsE);
return executeRecursive(ast, [], options);
};
exports.default = execute;