microvium
Version:
A compact, embeddable scripting engine for microcontrollers for executing small scripts written in a subset of JavaScript.
285 lines • 9.84 kB
JavaScript
;
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.mapEmplace = exports.defineContext = exports.jsonParse = exports.importPodValueRecursive = exports.arrayOfLength = exports.writeTextFile = exports.isNameString = exports.stringifyStringLiteral = exports.stringifyIdentifier = exports.todo = exports.fromEntries = exports.mapMap = exports.mapObject = exports.entriesInOrder = exports.entries = exports.uniqueNameInSet = exports.uniqueName = exports.abstractFunctionCalled = exports.notNull = exports.notUndefined = exports.invalidOperation = exports.hardAssert = exports.reserved = exports.unexpected = exports.assertUnreachable = exports.handlerNotImplemented = exports.notImplemented = exports.throwError = exports.todoSymbol = exports.never = exports.RuntimeError = exports.MicroviumSyntaxError = exports.CompileError = exports.MicroviumUsageError = void 0;
const fs = __importStar(require("fs"));
const im = __importStar(require("immutable"));
const os = __importStar(require("os"));
const _ = __importStar(require("lodash"));
const toSingleQuotes = require('to-single-quotes');
class MicroviumUsageError extends Error {
}
exports.MicroviumUsageError = MicroviumUsageError;
class CompileError extends MicroviumUsageError {
}
exports.CompileError = CompileError;
class MicroviumSyntaxError extends CompileError {
}
exports.MicroviumSyntaxError = MicroviumSyntaxError;
class RuntimeError extends MicroviumUsageError {
}
exports.RuntimeError = RuntimeError;
exports.never = undefined;
exports.todoSymbol = Symbol('To do');
function throwError(message) {
// A good place to set a breakpoint
throw new Error(message);
}
exports.throwError = throwError;
function notImplemented(feature) {
throwError(feature ? `Feature not implemented: ${feature}` : 'Feature not implemented');
}
exports.notImplemented = notImplemented;
function handlerNotImplemented() {
throwError('Internal error: handler not implemented');
}
exports.handlerNotImplemented = handlerNotImplemented;
function assertUnreachable(value) {
throwError('Internal error (reached unexpected code path)');
}
exports.assertUnreachable = assertUnreachable;
function unexpected(message) {
throwError('Internal error' + (message ? ': ' + message : ''));
}
exports.unexpected = unexpected;
function reserved(message) {
throwError('Internal error: reserved path' + (message ? ': ' + message : ''));
}
exports.reserved = reserved;
function hardAssert(predicate, message) {
if (!predicate) {
throwError('Internal error' + (message ? ': ' + message : ''));
}
}
exports.hardAssert = hardAssert;
function invalidOperation(message) {
throwError(`Unexpected state: ${message}`);
}
exports.invalidOperation = invalidOperation;
function notUndefined(v) {
if (v === undefined || v === null) {
throwError('Internal error: Did not expect value to be undefined');
}
return v;
}
exports.notUndefined = notUndefined;
function notNull(v) {
if (v === null) {
throwError('Internal error: Did not expect value to be null');
}
return v;
}
exports.notNull = notNull;
function abstractFunctionCalled(name) {
unexpected(`Abstract method called: ${name}`);
}
exports.abstractFunctionCalled = abstractFunctionCalled;
function uniqueName(base, nameTaken) {
if (!nameTaken(base)) {
return base;
}
const endsInNumber = base.match(/^(.*?)(\d+)$/);
let counter;
if (endsInNumber) {
let counterStr;
[, base, counterStr] = endsInNumber;
counter = parseInt(counterStr);
}
else {
counter = 1;
}
let name = base + counter;
while (nameTaken(name)) {
name = base + (++counter);
}
return name;
}
exports.uniqueName = uniqueName;
/*
* I caught myself using `uniqueName` but not adding the result to the set,
* which is why I created this.
*/
function uniqueNameInSet(base, set) {
const name = uniqueName(base, n => set.has(n));
set.add(name);
return name;
}
exports.uniqueNameInSet = uniqueNameInSet;
function entries(o) {
hardAssert(o !== null && typeof o === 'object');
if (im.Set.isSet(o)) {
const values = [...o];
values.sort();
return values;
}
else if (im.Map.isMap(o)) {
const values = [...o.entries()];
values.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
return values;
}
else if (o instanceof Map) {
const values = [...o.entries()];
values.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
return values;
}
else {
const values = Object.entries(o);
values.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
return values;
}
}
exports.entries = entries;
function entriesInOrder(o) {
return _.sortBy(entries(o));
}
exports.entriesInOrder = entriesInOrder;
function mapObject(obj, f) {
return fromEntries(Object.entries(obj)
.map(([k, v]) => [k, f(v, k)]));
}
exports.mapObject = mapObject;
function mapMap(src, f) {
return new Map(entries(src)
.map(([k, v]) => [k, f(v, k)]));
}
exports.mapMap = mapMap;
function fromEntries(entries) {
const result = {};
for (const [k, v] of entries) {
result[k] = v;
}
return result;
}
exports.fromEntries = fromEntries;
function todo(message) {
console.error('To do: ' + message);
return exports.todoSymbol;
}
exports.todo = todo;
function stringifyIdentifier(key) {
if (isNameString(key)) {
return key;
}
else {
return `[${stringifyStringLiteral(key)}]`;
}
}
exports.stringifyIdentifier = stringifyIdentifier;
function stringifyStringLiteral(s) {
return toSingleQuotes(JSON.stringify(s));
}
exports.stringifyStringLiteral = stringifyStringLiteral;
function isNameString(NameOperand) {
return /^[a-zA-Z_]+[a-zA-Z0-9_]*$/.test(NameOperand);
}
exports.isNameString = isNameString;
function writeTextFile(filename, content) {
fs.writeFileSync(filename, content.replace(/\r?\n/g, os.EOL));
}
exports.writeTextFile = writeTextFile;
/** An array of the given length with no holes in it */
function arrayOfLength(len) {
const arr = [];
for (let i = 0; i < len; i++)
arr.push(undefined);
return arr;
}
exports.arrayOfLength = arrayOfLength;
// Imports a host POD value into the VM
function importPodValueRecursive(vm, value) {
if (typeof value === 'object') {
if (Array.isArray(value)) {
const arr = vm.newArray();
for (let i = 0; i < value.length; i++) {
arr[i] = importPodValueRecursive(vm, value[i]);
}
return arr;
}
else {
const obj = vm.newObject();
for (const k of Object.keys(value)) {
obj[k] = importPodValueRecursive(vm, value[k]);
}
return obj;
}
}
else {
return value;
}
}
exports.importPodValueRecursive = importPodValueRecursive;
function jsonParse(vm) {
return function (text) {
const value = JSON.parse(text);
return importPodValueRecursive(vm, value);
};
}
exports.jsonParse = jsonParse;
/**
* A form of dynamic scoping
*/
function defineContext() {
let currentContext;
let currentContextDefined = false;
return {
use(value, scope) {
const [prevContext, prevContextDefined] = [currentContext, currentContextDefined];
[currentContext, currentContextDefined] = [value, true];
try {
return scope();
}
finally {
[currentContext, currentContextDefined] = [prevContext, prevContextDefined];
}
},
get value() {
if (!currentContextDefined)
invalidOperation('Accessing a context outside of a `Context.use` scope');
return currentContext;
}
};
}
exports.defineContext = defineContext;
function mapEmplace(map, key, handler) {
if (map.has(key)) {
const oldValue = map.get(key);
if (handler.update) {
const newValue = handler.update(oldValue, key, map);
map.set(key, newValue);
return newValue;
}
return oldValue;
}
else {
if (handler.insert) {
const newValue = handler.insert(key, map);
map.set(key, newValue);
return newValue;
}
return undefined;
}
}
exports.mapEmplace = mapEmplace;
//# sourceMappingURL=utils.js.map