microvium
Version:
A compact, embeddable scripting engine for microcontrollers for executing small scripts written in a subset of JavaScript.
90 lines (85 loc) • 3.88 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 __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeScopes = void 0;
const pass_1_find_scopes_and_bindings_1 = require("./pass-1-find-scopes-and-bindings");
const pass_2_compute_slots_1 = require("./pass-2-compute-slots");
const pass_3_compute_accessors_1 = require("./pass-3-compute-accessors");
__exportStar(require("./analysis-model"), exports);
/*
This does analysis of scopes and variables.
- Resolve identifiers to their corresponding declarations (bindings).
- Calculate how many variables are in each scope and assign indexes to each of
them.
- Compute closure information
In some ways, this basically returns a declarative representation of how all the
variables declarations and references must be emitted (including things like
parameters and function declarations).
*/
function analyzeScopes(file, filename, awaitStackDepths) {
/*
This function works in 3 passes with a "blackboard" design pattern. Each pass
populates or uses information from the `analysisState` model which contains
both intermediate information and final output information
*/
const analysisState = {
file,
cur: { filename, node: file },
importBindings: new Map(),
importedModuleNamespaceSlots: new Map(),
awaitStackDepths: awaitStackDepths,
model: {
references: new Map(),
scopes: new Map(),
bindings: new Map(),
functions: [],
moduleScope: undefined,
globalSlots: [],
freeVariables: new Set(),
thisModuleSlot: undefined,
moduleImports: new Map(),
exportedBindings: [],
}
};
/*
# Pass 1: Find scopes and bindings
Iterate the AST and build up a hierarchy of scopes and their bindings
(`ScopeBase.bindings`), and calculate references from variable identifiers to
the corresponding binding. This also marks which variables need to be
closure-allocated (via the `bindingIsClosureAllocated` set) and which
functions need to be closures. The scopes from this pass are only partially
populated.
*/
(0, pass_1_find_scopes_and_bindings_1.pass1_findScopesAndBindings)(analysisState);
/*
# Pass 2: Compute slots
Generate slots for all used bindings, based on metadata collected from the
first pass. This needs to be a second pass because we can't predict ahead of
time in a single pass which variables will need to be closure-allocated.
*/
(0, pass_2_compute_slots_1.pass2_computeSlots)(analysisState);
/*
# Pass 3: Compute slot accessors
A reference from a variable name to a corresponding slot in a closure scope
will need to be emitted as `LoadScoped` with an operand of the relative index
of the slot. This can only be computed now that we have all the slot
information calculated.
*/
(0, pass_3_compute_accessors_1.pass3_computeSlotAccessors)(analysisState);
return analysisState.model;
}
exports.analyzeScopes = analyzeScopes;
//# sourceMappingURL=index.js.map