UNPKG

microvium

Version:

A compact, embeddable scripting engine for microcontrollers for executing small scripts written in a subset of JavaScript.

124 lines 5.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calcStaticStackChangeOfOp = exports.calcDynamicStackChangeOfOp = exports.ExecutionFlag = exports.referenceValue = exports.hostFunctionValue = exports.functionValue = exports.emptyString = exports.stringValue = exports.numberValue = exports.trueValue = exports.falseValue = exports.nullValue = exports.undefinedValue = exports.noOpFunction = exports.deletedValue = exports.isLiteralOperand = exports.isLabelOperand = exports.isNameOperand = exports.dynamicEncoding = exports.ExportID = exports.MAX_COUNT = exports.MAX_INDEX = exports.opcodes = void 0; /* IL is a data format for virtual machine state. */ const utils_1 = require("./utils"); const runtime_types_1 = require("./runtime-types"); const il_opcodes_1 = require("./il-opcodes"); var il_opcodes_2 = require("./il-opcodes"); Object.defineProperty(exports, "opcodes", { enumerable: true, get: function () { return il_opcodes_2.opcodes; } }); exports.MAX_INDEX = 0x3FFF; exports.MAX_COUNT = 0x3FFF; const ExportID = (exportID) => { (0, utils_1.hardAssert)((0, runtime_types_1.isUInt16)(exportID)); return exportID; }; exports.ExportID = ExportID; exports.dynamicEncoding = Object.freeze({ type: 'DynamicEncoding' }); //| "void" //| "delete" function isNameOperand(value) { return value.type === 'NameOperand'; } exports.isNameOperand = isNameOperand; function isLabelOperand(value) { return value.type === 'LabelOperand'; } exports.isLabelOperand = isLabelOperand; function isLiteralOperand(value) { return value.type === 'LiteralOperand'; } exports.isLiteralOperand = isLiteralOperand; exports.deletedValue = Object.freeze({ type: 'DeletedValue', value: undefined }); exports.noOpFunction = Object.freeze({ type: 'NoOpFunction' }); exports.undefinedValue = Object.freeze({ type: 'UndefinedValue', value: undefined }); exports.nullValue = Object.freeze({ type: 'NullValue', value: null }); exports.falseValue = Object.freeze({ type: 'BooleanValue', value: false }); exports.trueValue = Object.freeze({ type: 'BooleanValue', value: true }); const numberValue = (n) => Object.freeze({ type: 'NumberValue', value: n }); exports.numberValue = numberValue; const stringValue = (s) => Object.freeze({ type: 'StringValue', value: s }); exports.stringValue = stringValue; exports.emptyString = (0, exports.stringValue)(''); const functionValue = (functionID) => Object.freeze({ type: 'FunctionValue', value: functionID }); exports.functionValue = functionValue; const hostFunctionValue = (hostFunctionID) => Object.freeze({ type: 'HostFunctionValue', value: hostFunctionID }); exports.hostFunctionValue = hostFunctionValue; const referenceValue = (allocationID) => Object.freeze({ type: 'ReferenceValue', value: allocationID }); exports.referenceValue = referenceValue; var ExecutionFlag; (function (ExecutionFlag) { ExecutionFlag[ExecutionFlag["FloatSupport"] = 0] = "FloatSupport"; ExecutionFlag[ExecutionFlag["CompiledWithOverflowChecks"] = 1] = "CompiledWithOverflowChecks"; })(ExecutionFlag = exports.ExecutionFlag || (exports.ExecutionFlag = {})); function calcDynamicStackChangeOfOp(operation) { const meta = il_opcodes_1.opcodes[operation.opcode]; let stackChange = meta.stackChange; if (typeof stackChange === 'function') stackChange = stackChange(...operation.operands); return stackChange; } exports.calcDynamicStackChangeOfOp = calcDynamicStackChangeOfOp; // The static stack change gives you stack depth at the instruction that follows // statically (physically) rather than the one that follows dynamically (from // runtime control flow). This is the same as the dynamic stack depth except in // the case of control flow instructions for which these diverge. function calcStaticStackChangeOfOp(operation) { // Control flow operations switch (operation.opcode) { case 'Return': return -1; // Return pops the result off the stack case 'AsyncReturn': return -1; // Return pops the result off the stack case 'Branch': return -1; // Pops predicate off the stack case 'Jump': return 0; case 'Call': { const forCall = calcDynamicStackChangeOfOp(operation) ?? (0, utils_1.unexpected)(); // Arguments popped from stack const isVoidCall = operation.operands[1]; (0, utils_1.hardAssert)(isVoidCall.type === 'FlagOperand'); const forReturn = isVoidCall.flag ? 0 : 1; // Return value pushed to the stack return forCall + forReturn; } case 'AwaitCall': { const forCall = calcDynamicStackChangeOfOp(operation) ?? (0, utils_1.unexpected)(); // Arguments popped from stack const forReturn = 1; return forCall + forReturn; } case 'New': return (0, utils_1.notUndefined)(calcDynamicStackChangeOfOp(operation)) + 1; // Includes the pushed return value default: return calcDynamicStackChangeOfOp(operation); } } exports.calcStaticStackChangeOfOp = calcStaticStackChangeOfOp; //# sourceMappingURL=il.js.map