UNPKG

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
"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 __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