UNPKG

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
"use strict"; 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;