Skip to content

Commit

Permalink
with statements WIP 2
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Aug 29, 2023
1 parent 254543b commit f388403
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 22 deletions.
8 changes: 4 additions & 4 deletions lib/init/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
const getScopeId = require('./getScopeId.js'),
addEvalFunctionsToTracker = require('./eval.js'),
internal = require('../shared/internal.js'),
{tracker, getIfTrackerIsActive} = require('../shared/tracker.js'),
{tracker, getIsGettingScope} = require('../shared/tracker.js'),
{COMMON_JS_MODULE, INTERNAL_VAR_NAMES_PREFIX} = require('../shared/constants.js');

// Exports
Expand Down Expand Up @@ -64,7 +64,7 @@ function addWrapWithFunctionToTracker(localTracker, prefixNum) {
// so not going to try to solve it here either.
// TODO: Try to solve this.
//
// Also always returns false from `has` trap if in a tracker call.
// Also always returns false from `has` trap if getting scope vars for a function.
// This renders the `with` object transparent, so tracker can get values of variables
// outside of the `with () {}` block. e.g. `let f, x = 123; with ({x: 1}) { f = () => x; }`
// Tracker in `f` needs to be able to get the value of `x` in outer scope.
Expand All @@ -76,8 +76,8 @@ function addWrapWithFunctionToTracker(localTracker, prefixNum) {
const internalVarsPrefix = `${INTERNAL_VAR_NAMES_PREFIX}${prefixNum || ''}_`;
localTracker.wrapWith = withObj => new Proxy(Object.create(null), {
has(target, key) {
// Act as if object has no properties if tracker call is in process
if (getIfTrackerIsActive()) return false;
// Act as if object has no properties if currently getting scope vars for a function
if (getIsGettingScope()) return false;
// Act as if properties named like Livepack's internal vars don't exist
if (key.startsWith(internalVarsPrefix)) return false;
// Forward to `with` object
Expand Down
8 changes: 1 addition & 7 deletions lib/instrument/visitors/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const VariableDeclaration = require('./variableDeclaration.js'),
SwitchStatement = require('./switch.js'),
TryStatement = require('./try.js'),
ThrowStatement = require('./unary.js'),
WithStatement = require('./with.js'),
{visitKey, visitKeyMaybe} = require('../visit.js');

// Exports
Expand Down Expand Up @@ -71,13 +72,6 @@ function ReturnStatement(node, state) {
visitKeyMaybe(node, 'argument', Expression, state);
}

function WithStatement(node, state) {
// TODO: Maintain a state property `currentWithBlock` which can be used in `resolveBinding()`
// to flag functions which access a var which would be affected by `with`
visitKey(node, 'object', Expression, state);
visitKey(node, 'body', Statement, state);
}

function LabeledStatement(node, state) {
visitKey(node, 'body', Statement, state);
}
59 changes: 59 additions & 0 deletions lib/instrument/visitors/with.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* --------------------
* livepack module
* Code instrumentation visitor for `with` statements
* ------------------*/

'use strict';

// Export
module.exports = WithStatement;

// Modules
const t = require('@babel/types');

// Imports
const Expression = require('./expression.js'),
Statement = require('./statement.js'),
{
createAndEnterBlock, createBindingWithoutNameCheck, createBlockTempVar, activateBlock
} = require('../blocks.js'),
{createTrackerVarNode} = require('../internalVars.js'),
{visitKey} = require('../visit.js');

// Exports

/**
* Visitor for `with () {}` statement.
* @param {Object} node - Statement AST node
* @param {Object} state - State object
* @returns {undefined}
*/
function WithStatement(node, state) {
// Visit object i.e. expression inside `with (...)`
visitKey(node, 'object', Expression, state);

// Create block for `with` object
const parentBlock = state.currentBlock;
const block = createAndEnterBlock('with', false, state);
const tempVarNode = createBlockTempVar(block, state);
createBindingWithoutNameCheck(block, 'with', {isConst: true, varNode: tempVarNode}, state);
// TODO: Should this only happen if var is accessed?
activateBlock(block, state);

// Visit body
visitKey(node, 'body', Statement, state);

// Exit block
state.currentBlock = parentBlock;

// Queue action to wrap `with` object
state.secondPass(instrumentWithObj, node, tempVarNode, state);
}

function instrumentWithObj(node, tempVarNode, state) {
// `with (o) {}` -> `with ( livepack_tracker.wrapWith(livepack_temp2 = o) ) {}`
node.object = t.callExpression(
t.memberExpression(createTrackerVarNode(state), t.identifier('wrapWith')),
[t.assignmentExpression('=', tempVarNode, node.object)]
);
}
6 changes: 5 additions & 1 deletion lib/serialize/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const util = require('util'),
t = require('@babel/types');

// Imports
const {activateTracker, getTrackerResult, trackerError} = require('../shared/tracker.js'),
const {
activateTracker, getTrackerResult, trackerError, setIsGettingScope
} = require('../shared/tracker.js'),
specialFunctions = require('../shared/internal.js').functions,
{
TRACKER_COMMENT_PREFIX,
Expand Down Expand Up @@ -309,11 +311,13 @@ module.exports = {
// Call `getScopes()` to get scope vars
let scopeVars;
if (!errorMessage) {
setIsGettingScope(true);
try {
scopeVars = getScopes();
} catch (err) {
errorMessage = getErrorMessage(err);
}
setIsGettingScope(false);
}

assertBug(
Expand Down
22 changes: 12 additions & 10 deletions lib/shared/tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ const trackerError = {},
module.exports = {
tracker,
activateTracker,
getIfTrackerIsActive,
getTrackerResult,
trackerError
trackerError,
getIsGettingScope,
setIsGettingScope
};

let trackerIsActive = false,
isGettingScope = false,
trackerResult;

/**
Expand Down Expand Up @@ -51,14 +53,6 @@ function activateTracker() {
trackerIsActive = true;
}

/**
* Get if tracker call is in progress.
* @returns {boolean} - `true` if tracker call is in progress
*/
function getIfTrackerIsActive() {
return trackerIsActive;
}

/**
* Get tracker result.
* @returns {Object} - Tracker result. Object with properties:
Expand All @@ -71,3 +65,11 @@ function getTrackerResult() {
trackerResult = undefined;
return result || {getFnInfo: undefined, getScopes: undefined};
}

function getIsGettingScope() {
return isGettingScope;
}

function setIsGettingScope(isGetting) {
isGettingScope = isGetting;
}

0 comments on commit f388403

Please sign in to comment.