UNPKG

microvium

Version:

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

191 lines 8.35 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValueWrapper = exports.NativeVMFriendly = void 0; const lib_1 = require("../lib"); const utils_1 = require("./utils"); const NativeVM = __importStar(require("./native-vm")); const runtime_types_1 = require("./runtime-types"); const snapshot_1 = require("./snapshot"); class NativeVMFriendly { constructor(snapshot, hostImportMap = lib_1.defaultHostEnvironment) { let hostImportFunction; if (typeof hostImportMap !== 'function') { hostImportFunction = (hostFunctionID) => { if (!hostImportMap.hasOwnProperty(hostFunctionID)) { return (0, utils_1.invalidOperation)('Unresolved import: ' + hostFunctionID); } return hostImportMap[hostFunctionID]; }; } else { hostImportFunction = hostImportMap; } this.vm = new NativeVM.NativeVM(snapshot.data, hostFunctionID => { const inner = hostImportFunction(hostFunctionID); return this.hostFunctionToVM(inner); }); } getMemoryStats() { return this.vm.getMemoryStats(); } resolveExport(exportID) { return vmValueToHost(this.vm, this.vm.resolveExport(exportID)); } garbageCollect(squeeze = false) { this.vm.runGC(squeeze); } createSnapshot() { return new snapshot_1.SnapshotClass(this.vm.createSnapshot()); } asyncStart() { return vmValueToHost(this.vm, this.vm.asyncStart()); } hostFunctionToVM(hostFunction) { return (args) => { const result = hostFunction.apply(undefined, args.map(a => vmValueToHost(this.vm, a))); return hostValueToVM(this.vm, result); }; } } exports.NativeVMFriendly = NativeVMFriendly; function vmValueToHost(vm, value) { switch (value.type) { case runtime_types_1.mvm_TeType.VM_T_UNDEFINED: return undefined; case runtime_types_1.mvm_TeType.VM_T_NULL: return null; case runtime_types_1.mvm_TeType.VM_T_BOOLEAN: return value.toBoolean(); case runtime_types_1.mvm_TeType.VM_T_NUMBER: return value.toNumber(); case runtime_types_1.mvm_TeType.VM_T_STRING: return value.toString(); case runtime_types_1.mvm_TeType.VM_T_FUNCTION: { return new Proxy(dummyFunctionTarget, new ValueWrapper(vm, value)); } case runtime_types_1.mvm_TeType.VM_T_OBJECT: { return new Proxy(dummyObject, new ValueWrapper(vm, value)); } case runtime_types_1.mvm_TeType.VM_T_ARRAY: return (0, utils_1.notImplemented)(); case runtime_types_1.mvm_TeType.VM_T_UINT8_ARRAY: return (0, utils_1.notImplemented)(); case runtime_types_1.mvm_TeType.VM_T_CLASS: return (0, utils_1.notImplemented)(); case runtime_types_1.mvm_TeType.VM_T_SYMBOL: return (0, utils_1.reserved)(); case runtime_types_1.mvm_TeType.VM_T_BIG_INT: return (0, utils_1.notImplemented)(); case runtime_types_1.mvm_TeType.VM_T_END: return (0, utils_1.unexpected)(); default: return (0, utils_1.assertUnreachable)(value.type); } } function hostValueToVM(vm, value) { switch (typeof value) { case 'undefined': return vm.undefined; case 'boolean': return vm.newBoolean(value); case 'number': return vm.newNumber(value); case 'string': return vm.newString(value); case 'function': { if (ValueWrapper.isWrapped(vm, value)) { return ValueWrapper.unwrap(vm, value); } else { return (0, utils_1.notImplemented)('Ephemeral in native VM'); // return vm.ephemeralFunction(hostFunctionToVM(vm, value), nameHint || value.name); } } case 'object': { if (value === null) { return (0, utils_1.notImplemented)(); // return vm.null; } if (ValueWrapper.isWrapped(vm, value)) { return ValueWrapper.unwrap(vm, value); } else { return (0, utils_1.notImplemented)('Ephemeral object in native VM'); } } default: return (0, utils_1.notImplemented)(); } } // Used as a target for function proxies, so that `typeof` and `call` work as expected const dummyFunctionTarget = () => { }; const dummyObject = {}; const vmValueSymbol = Symbol('vmValue'); const vmSymbol = Symbol('vm'); class ValueWrapper { constructor(vm, vmValue) { this.vm = vm; this.vmValue = vmValue; this.toString = this.toString.bind(this); } static isWrapped(vm, value) { return (typeof value === 'function' || typeof value === 'object') && value !== null && value[vmValueSymbol] && value[vmSymbol] == vm; // It needs to be a wrapped value in the context of the particular VM in question } static unwrap(vm, value) { (0, utils_1.hardAssert)(ValueWrapper.isWrapped(vm, value)); return value[vmValueSymbol]; } toString() { return `<Microvium native ${this.getTypeDescription()} 0x${this.vmValue.raw.toString(16).padStart(4, '0')} "${this.vmValue.toString()}">`; } getTypeDescription() { switch (this.vmValue.type) { case runtime_types_1.mvm_TeType.VM_T_UNDEFINED: return 'undefined'; case runtime_types_1.mvm_TeType.VM_T_NULL: return 'null'; case runtime_types_1.mvm_TeType.VM_T_BOOLEAN: return 'boolean'; case runtime_types_1.mvm_TeType.VM_T_NUMBER: return 'number'; case runtime_types_1.mvm_TeType.VM_T_STRING: return 'string'; case runtime_types_1.mvm_TeType.VM_T_FUNCTION: return 'function'; case runtime_types_1.mvm_TeType.VM_T_OBJECT: return 'object'; case runtime_types_1.mvm_TeType.VM_T_ARRAY: return 'array'; case runtime_types_1.mvm_TeType.VM_T_UINT8_ARRAY: return 'uint8 array'; case runtime_types_1.mvm_TeType.VM_T_CLASS: return 'class'; default: return 'unknown'; } } get(_target, p, receiver) { if (p === vmValueSymbol) return this.vmValue; if (p === vmSymbol) return this.vm; if (p === Symbol.toPrimitive) return this.toString; if (p === Symbol.toStringTag) return this.toString; if (p === 'toString') return this.toString; return undefined; } set(_target, p, value, receiver) { return (0, utils_1.notImplemented)(); } apply(_target, _thisArg, argArray = []) { const args = argArray.map(a => hostValueToVM(this.vm, a)); const func = this.vmValue; if (func.type !== runtime_types_1.mvm_TeType.VM_T_FUNCTION) return (0, utils_1.invalidOperation)('Target is not callable'); const result = this.vm.call(func, args); return vmValueToHost(this.vm, result); } } exports.ValueWrapper = ValueWrapper; //# sourceMappingURL=native-vm-friendly.js.map