Browse Source

another broken snapshot

value-tracking
Rich Harris 8 years ago
parent
commit
393d49e5eb
  1. 2
      package.json
  2. 18
      src/Declaration.js
  3. 4
      src/ast/Node.js
  4. 6
      src/ast/nodes/BinaryExpression.js
  5. 11
      src/ast/nodes/CallExpression.js
  6. 10
      src/ast/nodes/ConditionalExpression.js
  7. 4
      src/ast/nodes/ForOfStatement.js
  8. 19
      src/ast/nodes/FunctionDeclaration.js
  9. 31
      src/ast/nodes/FunctionExpression.js
  10. 11
      src/ast/nodes/Identifier.js
  11. 158
      src/ast/nodes/IfStatement.js
  12. 6
      src/ast/nodes/LogicalExpression.js
  13. 18
      src/ast/nodes/MemberExpression.js
  14. 10
      src/ast/nodes/ObjectExpression.js
  15. 5
      src/ast/nodes/ReturnStatement.js
  16. 10
      src/ast/nodes/UnaryExpression.js
  17. 5
      src/ast/nodes/VariableDeclarator.js
  18. 4
      src/ast/nodes/shared/callHasEffects.js
  19. 4
      src/ast/nodes/shared/isUsedByBundle.js
  20. 12
      src/ast/scopes/BundleScope.js
  21. 3
      src/ast/scopes/ModuleScope.js
  22. 4
      src/ast/scopes/Scope.js
  23. 19
      src/ast/values.js
  24. 2
      test/form/_tk/_config.js
  25. 1
      test/form/empty-if-statement/_config.js
  26. 2
      test/form/relative-external-with-global/_expected/amd.js
  27. 2
      test/form/relative-external-with-global/_expected/cjs.js
  28. 2
      test/form/relative-external-with-global/_expected/es.js
  29. 2
      test/form/relative-external-with-global/_expected/iife.js
  30. 2
      test/form/relative-external-with-global/_expected/umd.js
  31. 2
      test/form/relative-external-with-global/main.js

2
package.json

@ -59,7 +59,7 @@
"mocha": "^3.0.0", "mocha": "^3.0.0",
"remap-istanbul": "^0.6.4", "remap-istanbul": "^0.6.4",
"require-relative": "^0.8.7", "require-relative": "^0.8.7",
"rollup": "^0.39.0", "rollup": "^0.41.0",
"rollup-plugin-buble": "^0.13.0", "rollup-plugin-buble": "^0.13.0",
"rollup-plugin-commonjs": "^7.0.0", "rollup-plugin-commonjs": "^7.0.0",
"rollup-plugin-json": "^2.0.0", "rollup-plugin-json": "^2.0.0",

18
src/Declaration.js

@ -1,6 +1,6 @@
import { blank, forOwn, keys } from './utils/object.js'; import { blank, forOwn, keys } from './utils/object.js';
import makeLegalIdentifier, { reservedWords } from './utils/makeLegalIdentifier.js'; import makeLegalIdentifier, { reservedWords } from './utils/makeLegalIdentifier.js';
import { UNKNOWN } from './ast/values.js'; import { unknown } from './ast/values.js';
export default class Declaration { export default class Declaration {
constructor ( node, isParam ) { constructor ( node, isParam ) {
@ -31,6 +31,10 @@ export default class Declaration {
if ( reference.isReassignment ) this.isReassigned = true; if ( reference.isReassignment ) this.isReassigned = true;
} }
getInstance () {
return unknown;
}
render ( es ) { render ( es ) {
if ( es ) return this.name; if ( es ) return this.name;
if ( !this.isReassigned || !this.exportName ) return this.name; if ( !this.isReassigned || !this.exportName ) return this.name;
@ -68,7 +72,7 @@ export class SyntheticNamespaceDeclaration {
} }
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
values.add( UNKNOWN ); values.add( unknown );
} }
getName () { getName () {
@ -116,8 +120,12 @@ export class ExternalDeclaration {
} }
} }
call ( context, args ) {
console.log( `args`, args )
}
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
values.add( UNKNOWN ); values.add( unknown );
} }
getName ( es ) { getName ( es ) {
@ -134,6 +142,10 @@ export class ExternalDeclaration {
return es ? this.safeName : `${this.module.name}.${this.name}`; return es ? this.safeName : `${this.module.name}.${this.name}`;
} }
markReturnStatements () {
// noop
}
setSafeName ( name ) { setSafeName ( name ) {
this.safeName = name; this.safeName = name;
} }

4
src/ast/Node.js

@ -1,5 +1,5 @@
import { locate } from 'locate-character'; import { locate } from 'locate-character';
import { UNKNOWN } from './values.js'; import { unknown } from './values.js';
export default class Node { export default class Node {
bind ( scope ) { bind ( scope ) {
@ -35,7 +35,7 @@ export default class Node {
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
//this.eachChild( child => child.gatherPossibleValues( values ) ); //this.eachChild( child => child.gatherPossibleValues( values ) );
values.add( UNKNOWN ); values.add( unknown );
} }
getValue () { getValue () {

6
src/ast/nodes/BinaryExpression.js

@ -1,5 +1,5 @@
import Node from '../Node.js'; import Node from '../Node.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
const operators = { const operators = {
'==': ( left, right ) => left == right, '==': ( left, right ) => left == right,
@ -28,10 +28,10 @@ const operators = {
export default class BinaryExpression extends Node { export default class BinaryExpression extends Node {
getValue () { getValue () {
const leftValue = this.left.getValue(); const leftValue = this.left.getValue();
if ( leftValue === UNKNOWN ) return UNKNOWN; if ( leftValue === unknown ) return unknown;
const rightValue = this.right.getValue(); const rightValue = this.right.getValue();
if ( rightValue === UNKNOWN ) return UNKNOWN; if ( rightValue === unknown ) return unknown;
return operators[ this.operator ]( leftValue, rightValue ); return operators[ this.operator ]( leftValue, rightValue );
} }

11
src/ast/nodes/CallExpression.js

@ -25,6 +25,17 @@ export default class CallExpression extends Node {
super.bind( scope ); super.bind( scope );
} }
getProperty ( name ) {
// TODO unknown properties
return this.getValue().getProperty( name );
}
getValue () {
console.log( `TODO getValue ${this}` )
return this.callee.getReturnValue( this.arguments );
}
hasEffects ( scope ) { hasEffects ( scope ) {
return callHasEffects( scope, this.callee, false ); return callHasEffects( scope, this.callee, false );
} }

10
src/ast/nodes/ConditionalExpression.js

@ -1,12 +1,12 @@
import Node from '../Node.js'; import Node from '../Node.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
export default class ConditionalExpression extends Node { export default class ConditionalExpression extends Node {
initialise ( scope ) { initialise ( scope ) {
if ( this.module.bundle.treeshake ) { if ( this.module.bundle.treeshake ) {
this.testValue = this.test.getValue(); this.testValue = this.test.getValue();
if ( this.testValue === UNKNOWN ) { if ( this.testValue === unknown ) {
super.initialise( scope ); super.initialise( scope );
} }
@ -27,7 +27,7 @@ export default class ConditionalExpression extends Node {
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
const testValue = this.test.getValue(); const testValue = this.test.getValue();
if ( testValue === UNKNOWN ) { if ( testValue === unknown ) {
values.add( this.consequent ).add( this.alternate ); values.add( this.consequent ).add( this.alternate );
} else { } else {
values.add( testValue ? this.consequent : this.alternate ); values.add( testValue ? this.consequent : this.alternate );
@ -36,7 +36,7 @@ export default class ConditionalExpression extends Node {
getValue () { getValue () {
const testValue = this.test.getValue(); const testValue = this.test.getValue();
if ( testValue === UNKNOWN ) return UNKNOWN; if ( testValue === unknown ) return unknown;
return testValue ? this.consequent.getValue() : this.alternate.getValue(); return testValue ? this.consequent.getValue() : this.alternate.getValue();
} }
@ -47,7 +47,7 @@ export default class ConditionalExpression extends Node {
} }
else { else {
if ( this.testValue === UNKNOWN ) { if ( this.testValue === unknown ) {
super.render( code, es ); super.render( code, es );
} }

4
src/ast/nodes/ForOfStatement.js

@ -1,7 +1,7 @@
import Statement from './shared/Statement.js'; import Statement from './shared/Statement.js';
import assignTo from './shared/assignTo.js'; import assignTo from './shared/assignTo.js';
import Scope from '../scopes/Scope.js'; import Scope from '../scopes/Scope.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
export default class ForOfStatement extends Statement { export default class ForOfStatement extends Statement {
initialise ( scope ) { initialise ( scope ) {
@ -17,6 +17,6 @@ export default class ForOfStatement extends Statement {
} }
super.initialise( this.scope ); super.initialise( this.scope );
assignTo( this.left, this.scope, UNKNOWN ); assignTo( this.left, this.scope, unknown );
} }
} }

19
src/ast/nodes/FunctionDeclaration.js

@ -5,9 +5,7 @@ export default class FunctionDeclaration extends Node {
if ( this.activated ) return; if ( this.activated ) return;
this.activated = true; this.activated = true;
const scope = this.body.scope; this.body.mark();
this.params.forEach( param => param.run( scope ) ); // in case of assignment patterns
this.body.run();
} }
addReference () { addReference () {
@ -29,6 +27,8 @@ export default class FunctionDeclaration extends Node {
args.forEach( ( arg, i ) => { args.forEach( ( arg, i ) => {
const param = this.params[i]; const param = this.params[i];
if ( !param ) return;
if ( param.type !== 'Identifier' ) { if ( param.type !== 'Identifier' ) {
throw new Error( 'TODO desctructuring' ); throw new Error( 'TODO desctructuring' );
} }
@ -51,6 +51,19 @@ export default class FunctionDeclaration extends Node {
return this.name; return this.name;
} }
getReturnValue ( context, args ) {
if ( this.returnStatements.length === 0 ) {
console.log( `null!!!` )
return null; // TODO need a sentinel value for things like null
}
if ( this.returnStatements[0].parent === this.body ) {
throw new Error( 'TODO' );
}
console.log( `conditional return statements` )
}
hasEffects () { hasEffects () {
return false; return false;
} }

31
src/ast/nodes/FunctionExpression.js

@ -20,6 +20,31 @@ export default class FunctionExpression extends Node {
this.body.bind(); this.body.bind();
} }
call ( context, args ) {
if ( this.isCalling ) return; // recursive functions
this.isCalling = true;
this.body.scope.initialise();
args.forEach( ( arg, i ) => {
const param = this.params[i];
if ( !param ) return;
if ( param.type !== 'Identifier' ) {
throw new Error( 'TODO desctructuring' );
}
this.body.scope.setValue( param.name, arg );
});
for ( const node of this.body.body ) {
node.run();
}
this.isCalling = false;
}
getName () { getName () {
return this.name; return this.name;
} }
@ -37,6 +62,8 @@ export default class FunctionExpression extends Node {
this.body.scope.addDeclaration( this.id.name, this, false, false ); this.body.scope.addDeclaration( this.id.name, this, false, false );
} }
this.returnStatements = [];
this.params.forEach( param => param.initialise( this.body.scope ) ); this.params.forEach( param => param.initialise( this.body.scope ) );
this.body.initialise(); this.body.initialise();
} }
@ -45,4 +72,8 @@ export default class FunctionExpression extends Node {
this.body.mark(); this.body.mark();
super.mark(); super.mark();
} }
markReturnStatements () {
this.returnStatements.forEach( statement => statement.mark() );
}
} }

11
src/ast/nodes/Identifier.js

@ -35,6 +35,7 @@ export default class Identifier extends Node {
if ( !callee.call ) { if ( !callee.call ) {
throw new Error( `${callee} does not have call method (${this})` ); throw new Error( `${callee} does not have call method (${this})` );
} }
callee.call( undefined, args ); callee.call( undefined, args );
} }
@ -45,7 +46,15 @@ export default class Identifier extends Node {
} }
getInstance () { getInstance () {
return this.scope.getValue( this.name ).getInstance(); return this.getValue().getInstance();
}
getReturnValue ( args ) {
return this.declaration.getReturnValue( undefined, args );
}
getValue () {
return this.scope.getValue( this.name );
} }
initialise ( scope ) { initialise ( scope ) {

158
src/ast/nodes/IfStatement.js

@ -1,6 +1,6 @@
import Statement from './shared/Statement.js'; import Statement from './shared/Statement.js';
import extractNames from '../utils/extractNames.js'; import extractNames from '../utils/extractNames.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
// Statement types which may contain if-statements as direct children. // Statement types which may contain if-statements as direct children.
const statementsWithIfStatements = new Set([ const statementsWithIfStatements = new Set([
@ -39,82 +39,82 @@ function handleVarDeclarations ( node, scope ) {
// TODO DRY this out // TODO DRY this out
export default class IfStatement extends Statement { export default class IfStatement extends Statement {
initialise ( scope ) { // initialise ( scope ) {
this.scope = scope; // this.scope = scope;
this.testValue = this.test.getValue(); // this.testValue = this.test.getValue();
//
if ( this.module.bundle.treeshake ) { // if ( this.module.bundle.treeshake ) {
if ( this.testValue === UNKNOWN ) { // if ( this.testValue === unknown ) {
super.initialise( scope ); // super.initialise( scope );
} // }
//
else if ( this.testValue ) { // else if ( this.testValue ) {
this.consequent.initialise( scope ); // this.consequent.initialise( scope );
//
if ( this.alternate ) this.hoistedVars = handleVarDeclarations( this.alternate, scope ); // if ( this.alternate ) this.hoistedVars = handleVarDeclarations( this.alternate, scope );
this.alternate = null; // this.alternate = null;
} // }
//
else { // else {
if ( this.alternate ) this.alternate.initialise( scope ); // if ( this.alternate ) this.alternate.initialise( scope );
//
this.hoistedVars = handleVarDeclarations( this.consequent, scope ); // this.hoistedVars = handleVarDeclarations( this.consequent, scope );
this.consequent = null; // this.consequent = null;
} // }
} // }
//
else { // else {
super.initialise( scope ); // super.initialise( scope );
} // }
} // }
render ( code, es ) { // render ( code, es ) {
if ( this.module.bundle.treeshake ) { // if ( this.module.bundle.treeshake ) {
if ( this.testValue === UNKNOWN ) { // if ( this.testValue === unknown ) {
super.render( code, es ); // super.render( code, es );
} // }
//
else { // else {
code.overwrite( this.test.start, this.test.end, JSON.stringify( this.testValue ) ); // code.overwrite( this.test.start, this.test.end, JSON.stringify( this.testValue ) );
//
// TODO if no block-scoped declarations, remove enclosing // // TODO if no block-scoped declarations, remove enclosing
// curlies and dedent block (if there is a block) // // curlies and dedent block (if there is a block)
//
if ( this.hoistedVars ) { // if ( this.hoistedVars ) {
const names = this.hoistedVars // const names = this.hoistedVars
.map( name => { // .map( name => {
const declaration = this.scope.findDeclaration( name ); // const declaration = this.scope.findDeclaration( name );
return declaration.activated ? declaration.getName() : null; // return declaration.activated ? declaration.getName() : null;
}) // })
.filter( Boolean ); // .filter( Boolean );
//
if ( names.length > 0 ) { // if ( names.length > 0 ) {
code.insertLeft( this.start, `var ${names.join( ', ' )};\n\n` ); // code.insertLeft( this.start, `var ${names.join( ', ' )};\n\n` );
} // }
} // }
//
if ( this.testValue ) { // if ( this.testValue ) {
code.remove( this.start, this.consequent.start ); // code.remove( this.start, this.consequent.start );
code.remove( this.consequent.end, this.end ); // code.remove( this.consequent.end, this.end );
this.consequent.render( code, es ); // this.consequent.render( code, es );
} // }
//
else { // else {
code.remove( this.start, this.alternate ? this.alternate.start : this.next || this.end ); // code.remove( this.start, this.alternate ? this.alternate.start : this.next || this.end );
//
if ( this.alternate ) { // if ( this.alternate ) {
this.alternate.render( code, es ); // this.alternate.render( code, es );
} // }
//
else if ( statementsWithIfStatements.has( this.parent.type ) ) { // else if ( statementsWithIfStatements.has( this.parent.type ) ) {
code.insertRight( this.start, '{}' ); // code.insertRight( this.start, '{}' );
} // }
} // }
} // }
} // }
//
else { // else {
super.render( code, es ); // super.render( code, es );
} // }
} // }
} }

6
src/ast/nodes/LogicalExpression.js

@ -1,5 +1,5 @@
import Node from '../Node.js'; import Node from '../Node.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
const operators = { const operators = {
'&&': ( left, right ) => left && right, '&&': ( left, right ) => left && right,
@ -9,10 +9,10 @@ const operators = {
export default class LogicalExpression extends Node { export default class LogicalExpression extends Node {
getValue () { getValue () {
const leftValue = this.left.getValue(); const leftValue = this.left.getValue();
if ( leftValue === UNKNOWN ) return UNKNOWN; if ( leftValue === unknown ) return unknown;
const rightValue = this.right.getValue(); const rightValue = this.right.getValue();
if ( rightValue === UNKNOWN ) return UNKNOWN; if ( rightValue === unknown ) return unknown;
return operators[ this.operator ]( leftValue, rightValue ); return operators[ this.operator ]( leftValue, rightValue );
} }

18
src/ast/nodes/MemberExpression.js

@ -1,6 +1,6 @@
import relativeId from '../../utils/relativeId.js'; import relativeId from '../../utils/relativeId.js';
import Node from '../Node.js'; import Node from '../Node.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
const validProp = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/; const validProp = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
@ -73,11 +73,22 @@ export default class MemberExpression extends Node {
} }
call ( args ) { call ( args ) {
// TODO this.getValue().call( this.object, args );
} }
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
values.add( UNKNOWN ); // TODO values.add( unknown ); // TODO
}
getValue () {
if ( this.declaration ) {
return this.declaration;
}
const objectValue = this.object.getValue();
const propValue = this.computed ? this.property.getValue() : this.property.name;
const value = objectValue.getProperty( propValue ).getValue();
return value;
} }
mark () { mark () {
@ -87,6 +98,7 @@ export default class MemberExpression extends Node {
markReturnStatements () { markReturnStatements () {
// TODO // TODO
this.getValue().markReturnStatements();
} }
render ( code, es ) { render ( code, es ) {

10
src/ast/nodes/ObjectExpression.js

@ -5,4 +5,14 @@ export default class ObjectExpression extends Node {
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
values.add( OBJECT ); values.add( OBJECT );
} }
getProperty ( name ) {
// TODO handle unknowns
for ( const prop of this.properties ) {
// TODO handle computed properties
if ( prop.key.name === name && !prop.computed ) {
return prop.value;
}
}
}
} }

5
src/ast/nodes/ReturnStatement.js

@ -1,8 +1,11 @@
import Statement from './shared/Statement.js'; import Statement from './shared/Statement.js';
export default class ReturnStatement extends Statement { export default class ReturnStatement extends Statement {
initialise ( scope ) { bind () {
this.findParent( /Function/ ).returnStatements.push( this ); this.findParent( /Function/ ).returnStatements.push( this );
}
initialise ( scope ) {
super.initialise( scope ); super.initialise( scope );
} }
} }

10
src/ast/nodes/UnaryExpression.js

@ -1,5 +1,5 @@
import Node from '../Node.js'; import Node from '../Node.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
const operators = { const operators = {
"-": value => -value, "-": value => -value,
@ -8,17 +8,17 @@ const operators = {
"~": value => ~value, "~": value => ~value,
typeof: value => typeof value, typeof: value => typeof value,
void: () => undefined, void: () => undefined,
delete: () => UNKNOWN delete: () => unknown
}; };
export default class UnaryExpression extends Node { export default class UnaryExpression extends Node {
bind ( scope ) { bind ( scope ) {
if ( this.value === UNKNOWN ) super.bind( scope ); if ( this.value === unknown ) super.bind( scope );
} }
getValue () { getValue () {
const argumentValue = this.argument.getValue(); const argumentValue = this.argument.getValue();
if ( argumentValue === UNKNOWN ) return UNKNOWN; if ( argumentValue === unknown ) return unknown;
return operators[ this.operator ]( argumentValue ); return operators[ this.operator ]( argumentValue );
} }
@ -29,6 +29,6 @@ export default class UnaryExpression extends Node {
initialise ( scope ) { initialise ( scope ) {
this.value = this.getValue(); this.value = this.getValue();
if ( this.value === UNKNOWN ) super.initialise( scope ); if ( this.value === unknown ) super.initialise( scope );
} }
} }

5
src/ast/nodes/VariableDeclarator.js

@ -1,6 +1,6 @@
import Node from '../Node.js'; import Node from '../Node.js';
import extractNames from '../utils/extractNames.js'; import extractNames from '../utils/extractNames.js';
import { UNKNOWN } from '../values.js'; import { unknown } from '../values.js';
class DeclaratorProxy { class DeclaratorProxy {
constructor ( name, declarator, isTopLevel, init ) { constructor ( name, declarator, isTopLevel, init ) {
@ -63,7 +63,7 @@ export default class VariableDeclarator extends Node {
const lexicalBoundary = scope.findLexicalBoundary(); const lexicalBoundary = scope.findLexicalBoundary();
const init = this.init ? const init = this.init ?
( this.id.type === 'Identifier' ? this.init : UNKNOWN ) : // TODO maybe UNKNOWN is unnecessary ( this.id.type === 'Identifier' ? this.init : unknown ) : // TODO maybe unknown is unnecessary
null; null;
extractNames( this.id ).forEach( name => { extractNames( this.id ).forEach( name => {
@ -98,6 +98,7 @@ export default class VariableDeclarator extends Node {
} }
if ( this.init ) { if ( this.init ) {
this.init.run();
this.scope.setValue( this.id.name, this.init.getValue() ); this.scope.setValue( this.id.name, this.init.getValue() );
} else if ( this.parent.kind !== 'var' ) { } else if ( this.parent.kind !== 'var' ) {
this.scope.setValue( this.id.name, undefined ); // no longer TDZ violation this.scope.setValue( this.id.name, undefined ); // no longer TDZ violation

4
src/ast/nodes/shared/callHasEffects.js

@ -1,7 +1,7 @@
import isReference from 'is-reference'; import isReference from 'is-reference';
import flatten from '../../utils/flatten.js'; import flatten from '../../utils/flatten.js';
import pureFunctions from './pureFunctions.js'; import pureFunctions from './pureFunctions.js';
import { UNKNOWN } from '../../values.js'; import { unknown } from '../../values.js';
const currentlyCalling = new Set(); const currentlyCalling = new Set();
@ -64,7 +64,7 @@ export default function callHasEffects ( scope, callee, isNew ) {
const values = new Set([ callee ]); const values = new Set([ callee ]);
for ( const node of values ) { for ( const node of values ) {
if ( node === UNKNOWN ) return true; // err on side of caution if ( node === unknown ) return true; // err on side of caution
if ( /Function/.test( node.type ) ) { if ( /Function/.test( node.type ) ) {
if ( fnHasEffects( node, isNew && isES5Function( node ) ) ) return true; if ( fnHasEffects( node, isNew && isES5Function( node ) ) ) return true;

4
src/ast/nodes/shared/isUsedByBundle.js

@ -1,4 +1,4 @@
import { UNKNOWN } from '../../values.js'; import { unknown } from '../../values.js';
export default function isUsedByBundle ( scope, node ) { export default function isUsedByBundle ( scope, node ) {
// const expression = node; // const expression = node;
@ -18,7 +18,7 @@ export default function isUsedByBundle ( scope, node ) {
const values = new Set(); const values = new Set();
declaration.gatherPossibleValues( values ); declaration.gatherPossibleValues( values );
for ( const value of values ) { for ( const value of values ) {
if ( value === UNKNOWN ) { if ( value === unknown ) {
return true; return true;
} }

12
src/ast/scopes/BundleScope.js

@ -1,5 +1,5 @@
import Scope from './Scope.js'; import Scope from './Scope.js';
import { UNKNOWN } from '../values'; import { unknown } from '../values';
class SyntheticGlobalDeclaration { class SyntheticGlobalDeclaration {
constructor ( name ) { constructor ( name ) {
@ -25,7 +25,15 @@ class SyntheticGlobalDeclaration {
} }
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
values.add( UNKNOWN ); values.add( unknown );
}
getInstance () {
return unknown;
}
getProperty () {
return unknown;
} }
getName () { getName () {

3
src/ast/scopes/ModuleScope.js

@ -1,5 +1,6 @@
import { forOwn } from '../../utils/object.js'; import { forOwn } from '../../utils/object.js';
import relativeId from '../../utils/relativeId.js'; import relativeId from '../../utils/relativeId.js';
import { unknown } from '../values.js';
import Scope from './Scope.js'; import Scope from './Scope.js';
export default class ModuleScope extends Scope { export default class ModuleScope extends Scope {
@ -63,6 +64,8 @@ export default class ModuleScope extends Scope {
const imported = this.module.imports[ name ]; const imported = this.module.imports[ name ];
if ( imported ) { if ( imported ) {
if ( imported.module.isExternal ) return unknown;
const exported = imported.module.exports[ imported.name ]; const exported = imported.module.exports[ imported.name ];
const exportedName = exported.localName === 'default' && exported.identifier ? exported.identifier : exported.localName; // TODO this is a mess const exportedName = exported.localName === 'default' && exported.identifier ? exported.identifier : exported.localName; // TODO this is a mess
return imported.module.scope.getValue( exportedName ); return imported.module.scope.getValue( exportedName );

4
src/ast/scopes/Scope.js

@ -1,5 +1,5 @@
import { blank, keys } from '../../utils/object.js'; import { blank, keys } from '../../utils/object.js';
import { UNKNOWN, TDZ_VIOLATION } from '../values.js'; import { unknown, TDZ_VIOLATION } from '../values.js';
class Parameter { class Parameter {
constructor ( name ) { constructor ( name ) {
@ -18,7 +18,7 @@ class Parameter {
} }
gatherPossibleValues ( values ) { gatherPossibleValues ( values ) {
values.add( UNKNOWN ); // TODO populate this at call time values.add( unknown ); // TODO populate this at call time
} }
getName () { getName () {

19
src/ast/values.js

@ -5,5 +5,22 @@ export const FUNCTION = { FUNCTION: true, toString: () => '[[FUNCTION]]' };
export const NUMBER = { NUMBER: true, toString: () => '[[NUMBER]]' }; export const NUMBER = { NUMBER: true, toString: () => '[[NUMBER]]' };
export const OBJECT = { OBJECT: true, toString: () => '[[OBJECT]]' }; export const OBJECT = { OBJECT: true, toString: () => '[[OBJECT]]' };
export const STRING = { STRING: true, toString: () => '[[STRING]]' }; export const STRING = { STRING: true, toString: () => '[[STRING]]' };
export const UNKNOWN = { UNKNOWN: true, toString: () => '[[UNKNOWN]]' };
export const TDZ_VIOLATION = { TDZ_VIOLATION: true, toString: () => '[[TDZ_VIOLATION]]' }; export const TDZ_VIOLATION = { TDZ_VIOLATION: true, toString: () => '[[TDZ_VIOLATION]]' };
export class UnknownValue {
call ( context, args ) {
args.forEach( arg => {
// TODO call functions (and children of objects...) with unknown arguments
});
}
getValue () {
return unknown;
}
markReturnStatements () {
// noop?
}
}
export const unknown = new UnknownValue();

2
test/form/_tk/_config.js

@ -1,3 +1,3 @@
module.exports = { module.exports = {
// solo: true solo: true
}; };

1
test/form/empty-if-statement/_config.js

@ -1,4 +1,3 @@
module.exports = { module.exports = {
solo: true,
description: 'removes an empty if statement' description: 'removes an empty if statement'
}; };

2
test/form/relative-external-with-global/_expected/amd.js

@ -6,6 +6,6 @@ define(['./lib/throttle.js'], function (throttle) { 'use strict';
console.log( '.' ); console.log( '.' );
}, 500 ); }, 500 );
window.addEventListener( 'mousemove', throttle ); window.addEventListener( 'mousemove', fn );
}); });

2
test/form/relative-external-with-global/_expected/cjs.js

@ -8,4 +8,4 @@ const fn = throttle( () => {
console.log( '.' ); console.log( '.' );
}, 500 ); }, 500 );
window.addEventListener( 'mousemove', throttle ); window.addEventListener( 'mousemove', fn );

2
test/form/relative-external-with-global/_expected/es.js

@ -4,4 +4,4 @@ const fn = throttle( () => {
console.log( '.' ); console.log( '.' );
}, 500 ); }, 500 );
window.addEventListener( 'mousemove', throttle ); window.addEventListener( 'mousemove', fn );

2
test/form/relative-external-with-global/_expected/iife.js

@ -7,6 +7,6 @@
console.log( '.' ); console.log( '.' );
}, 500 ); }, 500 );
window.addEventListener( 'mousemove', throttle ); window.addEventListener( 'mousemove', fn );
}(Lib.throttle)); }(Lib.throttle));

2
test/form/relative-external-with-global/_expected/umd.js

@ -10,6 +10,6 @@
console.log( '.' ); console.log( '.' );
}, 500 ); }, 500 );
window.addEventListener( 'mousemove', throttle ); window.addEventListener( 'mousemove', fn );
}))); })));

2
test/form/relative-external-with-global/main.js

@ -4,4 +4,4 @@ const fn = throttle( () => {
console.log( '.' ); console.log( '.' );
}, 500 ); }, 500 );
window.addEventListener( 'mousemove', throttle ); window.addEventListener( 'mousemove', fn );

Loading…
Cancel
Save