From 393d49e5ebd2eacbde3ecb9d9c4898cf5598b3f1 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 12 Jan 2017 17:54:40 -0500 Subject: [PATCH] another broken snapshot --- package.json | 2 +- src/Declaration.js | 18 +- src/ast/Node.js | 4 +- src/ast/nodes/BinaryExpression.js | 6 +- src/ast/nodes/CallExpression.js | 11 ++ src/ast/nodes/ConditionalExpression.js | 10 +- src/ast/nodes/ForOfStatement.js | 4 +- src/ast/nodes/FunctionDeclaration.js | 19 ++- src/ast/nodes/FunctionExpression.js | 31 ++++ src/ast/nodes/Identifier.js | 11 +- src/ast/nodes/IfStatement.js | 158 +++++++++--------- src/ast/nodes/LogicalExpression.js | 6 +- src/ast/nodes/MemberExpression.js | 18 +- src/ast/nodes/ObjectExpression.js | 10 ++ src/ast/nodes/ReturnStatement.js | 5 +- src/ast/nodes/UnaryExpression.js | 10 +- src/ast/nodes/VariableDeclarator.js | 5 +- src/ast/nodes/shared/callHasEffects.js | 4 +- src/ast/nodes/shared/isUsedByBundle.js | 4 +- src/ast/scopes/BundleScope.js | 12 +- src/ast/scopes/ModuleScope.js | 3 + src/ast/scopes/Scope.js | 4 +- src/ast/values.js | 19 ++- test/form/_tk/_config.js | 2 +- test/form/empty-if-statement/_config.js | 1 - .../_expected/amd.js | 4 +- .../_expected/cjs.js | 2 +- .../_expected/es.js | 2 +- .../_expected/iife.js | 2 +- .../_expected/umd.js | 2 +- .../relative-external-with-global/main.js | 2 +- 31 files changed, 260 insertions(+), 131 deletions(-) diff --git a/package.json b/package.json index de06261..1f06c0d 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "mocha": "^3.0.0", "remap-istanbul": "^0.6.4", "require-relative": "^0.8.7", - "rollup": "^0.39.0", + "rollup": "^0.41.0", "rollup-plugin-buble": "^0.13.0", "rollup-plugin-commonjs": "^7.0.0", "rollup-plugin-json": "^2.0.0", diff --git a/src/Declaration.js b/src/Declaration.js index 04670d3..4b3dcdc 100644 --- a/src/Declaration.js +++ b/src/Declaration.js @@ -1,6 +1,6 @@ import { blank, forOwn, keys } from './utils/object.js'; import makeLegalIdentifier, { reservedWords } from './utils/makeLegalIdentifier.js'; -import { UNKNOWN } from './ast/values.js'; +import { unknown } from './ast/values.js'; export default class Declaration { constructor ( node, isParam ) { @@ -31,6 +31,10 @@ export default class Declaration { if ( reference.isReassignment ) this.isReassigned = true; } + getInstance () { + return unknown; + } + render ( es ) { if ( es ) return this.name; if ( !this.isReassigned || !this.exportName ) return this.name; @@ -68,7 +72,7 @@ export class SyntheticNamespaceDeclaration { } gatherPossibleValues ( values ) { - values.add( UNKNOWN ); + values.add( unknown ); } getName () { @@ -116,8 +120,12 @@ export class ExternalDeclaration { } } + call ( context, args ) { + console.log( `args`, args ) + } + gatherPossibleValues ( values ) { - values.add( UNKNOWN ); + values.add( unknown ); } getName ( es ) { @@ -134,6 +142,10 @@ export class ExternalDeclaration { return es ? this.safeName : `${this.module.name}.${this.name}`; } + markReturnStatements () { + // noop + } + setSafeName ( name ) { this.safeName = name; } diff --git a/src/ast/Node.js b/src/ast/Node.js index ce7e254..10b8e79 100644 --- a/src/ast/Node.js +++ b/src/ast/Node.js @@ -1,5 +1,5 @@ import { locate } from 'locate-character'; -import { UNKNOWN } from './values.js'; +import { unknown } from './values.js'; export default class Node { bind ( scope ) { @@ -35,7 +35,7 @@ export default class Node { gatherPossibleValues ( values ) { //this.eachChild( child => child.gatherPossibleValues( values ) ); - values.add( UNKNOWN ); + values.add( unknown ); } getValue () { diff --git a/src/ast/nodes/BinaryExpression.js b/src/ast/nodes/BinaryExpression.js index da3d4da..d4371ae 100644 --- a/src/ast/nodes/BinaryExpression.js +++ b/src/ast/nodes/BinaryExpression.js @@ -1,5 +1,5 @@ import Node from '../Node.js'; -import { UNKNOWN } from '../values.js'; +import { unknown } from '../values.js'; const operators = { '==': ( left, right ) => left == right, @@ -28,10 +28,10 @@ const operators = { export default class BinaryExpression extends Node { getValue () { const leftValue = this.left.getValue(); - if ( leftValue === UNKNOWN ) return UNKNOWN; + if ( leftValue === unknown ) return unknown; const rightValue = this.right.getValue(); - if ( rightValue === UNKNOWN ) return UNKNOWN; + if ( rightValue === unknown ) return unknown; return operators[ this.operator ]( leftValue, rightValue ); } diff --git a/src/ast/nodes/CallExpression.js b/src/ast/nodes/CallExpression.js index 0014a58..08a57b6 100644 --- a/src/ast/nodes/CallExpression.js +++ b/src/ast/nodes/CallExpression.js @@ -25,6 +25,17 @@ export default class CallExpression extends Node { 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 ) { return callHasEffects( scope, this.callee, false ); } diff --git a/src/ast/nodes/ConditionalExpression.js b/src/ast/nodes/ConditionalExpression.js index 9c7b444..7fc1993 100644 --- a/src/ast/nodes/ConditionalExpression.js +++ b/src/ast/nodes/ConditionalExpression.js @@ -1,12 +1,12 @@ import Node from '../Node.js'; -import { UNKNOWN } from '../values.js'; +import { unknown } from '../values.js'; export default class ConditionalExpression extends Node { initialise ( scope ) { if ( this.module.bundle.treeshake ) { this.testValue = this.test.getValue(); - if ( this.testValue === UNKNOWN ) { + if ( this.testValue === unknown ) { super.initialise( scope ); } @@ -27,7 +27,7 @@ export default class ConditionalExpression extends Node { gatherPossibleValues ( values ) { const testValue = this.test.getValue(); - if ( testValue === UNKNOWN ) { + if ( testValue === unknown ) { values.add( this.consequent ).add( this.alternate ); } else { values.add( testValue ? this.consequent : this.alternate ); @@ -36,7 +36,7 @@ export default class ConditionalExpression extends Node { getValue () { const testValue = this.test.getValue(); - if ( testValue === UNKNOWN ) return UNKNOWN; + if ( testValue === unknown ) return unknown; return testValue ? this.consequent.getValue() : this.alternate.getValue(); } @@ -47,7 +47,7 @@ export default class ConditionalExpression extends Node { } else { - if ( this.testValue === UNKNOWN ) { + if ( this.testValue === unknown ) { super.render( code, es ); } diff --git a/src/ast/nodes/ForOfStatement.js b/src/ast/nodes/ForOfStatement.js index a5225f8..0c570c9 100644 --- a/src/ast/nodes/ForOfStatement.js +++ b/src/ast/nodes/ForOfStatement.js @@ -1,7 +1,7 @@ import Statement from './shared/Statement.js'; import assignTo from './shared/assignTo.js'; import Scope from '../scopes/Scope.js'; -import { UNKNOWN } from '../values.js'; +import { unknown } from '../values.js'; export default class ForOfStatement extends Statement { initialise ( scope ) { @@ -17,6 +17,6 @@ export default class ForOfStatement extends Statement { } super.initialise( this.scope ); - assignTo( this.left, this.scope, UNKNOWN ); + assignTo( this.left, this.scope, unknown ); } } diff --git a/src/ast/nodes/FunctionDeclaration.js b/src/ast/nodes/FunctionDeclaration.js index eddcb0f..0cd35c8 100644 --- a/src/ast/nodes/FunctionDeclaration.js +++ b/src/ast/nodes/FunctionDeclaration.js @@ -5,9 +5,7 @@ export default class FunctionDeclaration extends Node { if ( this.activated ) return; this.activated = true; - const scope = this.body.scope; - this.params.forEach( param => param.run( scope ) ); // in case of assignment patterns - this.body.run(); + this.body.mark(); } addReference () { @@ -29,6 +27,8 @@ export default class FunctionDeclaration extends Node { args.forEach( ( arg, i ) => { const param = this.params[i]; + if ( !param ) return; + if ( param.type !== 'Identifier' ) { throw new Error( 'TODO desctructuring' ); } @@ -51,6 +51,19 @@ export default class FunctionDeclaration extends Node { 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 () { return false; } diff --git a/src/ast/nodes/FunctionExpression.js b/src/ast/nodes/FunctionExpression.js index 1266836..0d65a0d 100644 --- a/src/ast/nodes/FunctionExpression.js +++ b/src/ast/nodes/FunctionExpression.js @@ -20,6 +20,31 @@ export default class FunctionExpression extends Node { 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 () { return this.name; } @@ -37,6 +62,8 @@ export default class FunctionExpression extends Node { this.body.scope.addDeclaration( this.id.name, this, false, false ); } + this.returnStatements = []; + this.params.forEach( param => param.initialise( this.body.scope ) ); this.body.initialise(); } @@ -45,4 +72,8 @@ export default class FunctionExpression extends Node { this.body.mark(); super.mark(); } + + markReturnStatements () { + this.returnStatements.forEach( statement => statement.mark() ); + } } diff --git a/src/ast/nodes/Identifier.js b/src/ast/nodes/Identifier.js index 0c35b68..8090ed4 100644 --- a/src/ast/nodes/Identifier.js +++ b/src/ast/nodes/Identifier.js @@ -35,6 +35,7 @@ export default class Identifier extends Node { if ( !callee.call ) { throw new Error( `${callee} does not have call method (${this})` ); } + callee.call( undefined, args ); } @@ -45,7 +46,15 @@ export default class Identifier extends Node { } 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 ) { diff --git a/src/ast/nodes/IfStatement.js b/src/ast/nodes/IfStatement.js index a16d3ca..ab42309 100644 --- a/src/ast/nodes/IfStatement.js +++ b/src/ast/nodes/IfStatement.js @@ -1,6 +1,6 @@ import Statement from './shared/Statement.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. const statementsWithIfStatements = new Set([ @@ -39,82 +39,82 @@ function handleVarDeclarations ( node, scope ) { // TODO DRY this out export default class IfStatement extends Statement { - initialise ( scope ) { - this.scope = scope; - this.testValue = this.test.getValue(); - - if ( this.module.bundle.treeshake ) { - if ( this.testValue === UNKNOWN ) { - super.initialise( scope ); - } - - else if ( this.testValue ) { - this.consequent.initialise( scope ); - - if ( this.alternate ) this.hoistedVars = handleVarDeclarations( this.alternate, scope ); - this.alternate = null; - } - - else { - if ( this.alternate ) this.alternate.initialise( scope ); - - this.hoistedVars = handleVarDeclarations( this.consequent, scope ); - this.consequent = null; - } - } - - else { - super.initialise( scope ); - } - } - - render ( code, es ) { - if ( this.module.bundle.treeshake ) { - if ( this.testValue === UNKNOWN ) { - super.render( code, es ); - } - - else { - code.overwrite( this.test.start, this.test.end, JSON.stringify( this.testValue ) ); - - // TODO if no block-scoped declarations, remove enclosing - // curlies and dedent block (if there is a block) - - if ( this.hoistedVars ) { - const names = this.hoistedVars - .map( name => { - const declaration = this.scope.findDeclaration( name ); - return declaration.activated ? declaration.getName() : null; - }) - .filter( Boolean ); - - if ( names.length > 0 ) { - code.insertLeft( this.start, `var ${names.join( ', ' )};\n\n` ); - } - } - - if ( this.testValue ) { - code.remove( this.start, this.consequent.start ); - code.remove( this.consequent.end, this.end ); - this.consequent.render( code, es ); - } - - else { - code.remove( this.start, this.alternate ? this.alternate.start : this.next || this.end ); - - if ( this.alternate ) { - this.alternate.render( code, es ); - } - - else if ( statementsWithIfStatements.has( this.parent.type ) ) { - code.insertRight( this.start, '{}' ); - } - } - } - } - - else { - super.render( code, es ); - } - } + // initialise ( scope ) { + // this.scope = scope; + // this.testValue = this.test.getValue(); + // + // if ( this.module.bundle.treeshake ) { + // if ( this.testValue === unknown ) { + // super.initialise( scope ); + // } + // + // else if ( this.testValue ) { + // this.consequent.initialise( scope ); + // + // if ( this.alternate ) this.hoistedVars = handleVarDeclarations( this.alternate, scope ); + // this.alternate = null; + // } + // + // else { + // if ( this.alternate ) this.alternate.initialise( scope ); + // + // this.hoistedVars = handleVarDeclarations( this.consequent, scope ); + // this.consequent = null; + // } + // } + // + // else { + // super.initialise( scope ); + // } + // } + + // render ( code, es ) { + // if ( this.module.bundle.treeshake ) { + // if ( this.testValue === unknown ) { + // super.render( code, es ); + // } + // + // else { + // code.overwrite( this.test.start, this.test.end, JSON.stringify( this.testValue ) ); + // + // // TODO if no block-scoped declarations, remove enclosing + // // curlies and dedent block (if there is a block) + // + // if ( this.hoistedVars ) { + // const names = this.hoistedVars + // .map( name => { + // const declaration = this.scope.findDeclaration( name ); + // return declaration.activated ? declaration.getName() : null; + // }) + // .filter( Boolean ); + // + // if ( names.length > 0 ) { + // code.insertLeft( this.start, `var ${names.join( ', ' )};\n\n` ); + // } + // } + // + // if ( this.testValue ) { + // code.remove( this.start, this.consequent.start ); + // code.remove( this.consequent.end, this.end ); + // this.consequent.render( code, es ); + // } + // + // else { + // code.remove( this.start, this.alternate ? this.alternate.start : this.next || this.end ); + // + // if ( this.alternate ) { + // this.alternate.render( code, es ); + // } + // + // else if ( statementsWithIfStatements.has( this.parent.type ) ) { + // code.insertRight( this.start, '{}' ); + // } + // } + // } + // } + // + // else { + // super.render( code, es ); + // } + // } } diff --git a/src/ast/nodes/LogicalExpression.js b/src/ast/nodes/LogicalExpression.js index 4f81d3b..4aa54df 100644 --- a/src/ast/nodes/LogicalExpression.js +++ b/src/ast/nodes/LogicalExpression.js @@ -1,5 +1,5 @@ import Node from '../Node.js'; -import { UNKNOWN } from '../values.js'; +import { unknown } from '../values.js'; const operators = { '&&': ( left, right ) => left && right, @@ -9,10 +9,10 @@ const operators = { export default class LogicalExpression extends Node { getValue () { const leftValue = this.left.getValue(); - if ( leftValue === UNKNOWN ) return UNKNOWN; + if ( leftValue === unknown ) return unknown; const rightValue = this.right.getValue(); - if ( rightValue === UNKNOWN ) return UNKNOWN; + if ( rightValue === unknown ) return unknown; return operators[ this.operator ]( leftValue, rightValue ); } diff --git a/src/ast/nodes/MemberExpression.js b/src/ast/nodes/MemberExpression.js index 2c8dd0a..b04bf0b 100644 --- a/src/ast/nodes/MemberExpression.js +++ b/src/ast/nodes/MemberExpression.js @@ -1,6 +1,6 @@ import relativeId from '../../utils/relativeId.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]*$/; @@ -73,11 +73,22 @@ export default class MemberExpression extends Node { } call ( args ) { - // TODO + this.getValue().call( this.object, args ); } 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 () { @@ -87,6 +98,7 @@ export default class MemberExpression extends Node { markReturnStatements () { // TODO + this.getValue().markReturnStatements(); } render ( code, es ) { diff --git a/src/ast/nodes/ObjectExpression.js b/src/ast/nodes/ObjectExpression.js index 724cb00..cc0a0a7 100644 --- a/src/ast/nodes/ObjectExpression.js +++ b/src/ast/nodes/ObjectExpression.js @@ -5,4 +5,14 @@ export default class ObjectExpression extends Node { gatherPossibleValues ( values ) { 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; + } + } + } } diff --git a/src/ast/nodes/ReturnStatement.js b/src/ast/nodes/ReturnStatement.js index 7f144a4..3664b4f 100644 --- a/src/ast/nodes/ReturnStatement.js +++ b/src/ast/nodes/ReturnStatement.js @@ -1,8 +1,11 @@ import Statement from './shared/Statement.js'; export default class ReturnStatement extends Statement { - initialise ( scope ) { + bind () { this.findParent( /Function/ ).returnStatements.push( this ); + } + + initialise ( scope ) { super.initialise( scope ); } } diff --git a/src/ast/nodes/UnaryExpression.js b/src/ast/nodes/UnaryExpression.js index 9be1c2c..9ebd4cd 100644 --- a/src/ast/nodes/UnaryExpression.js +++ b/src/ast/nodes/UnaryExpression.js @@ -1,5 +1,5 @@ import Node from '../Node.js'; -import { UNKNOWN } from '../values.js'; +import { unknown } from '../values.js'; const operators = { "-": value => -value, @@ -8,17 +8,17 @@ const operators = { "~": value => ~value, typeof: value => typeof value, void: () => undefined, - delete: () => UNKNOWN + delete: () => unknown }; export default class UnaryExpression extends Node { bind ( scope ) { - if ( this.value === UNKNOWN ) super.bind( scope ); + if ( this.value === unknown ) super.bind( scope ); } getValue () { const argumentValue = this.argument.getValue(); - if ( argumentValue === UNKNOWN ) return UNKNOWN; + if ( argumentValue === unknown ) return unknown; return operators[ this.operator ]( argumentValue ); } @@ -29,6 +29,6 @@ export default class UnaryExpression extends Node { initialise ( scope ) { this.value = this.getValue(); - if ( this.value === UNKNOWN ) super.initialise( scope ); + if ( this.value === unknown ) super.initialise( scope ); } } diff --git a/src/ast/nodes/VariableDeclarator.js b/src/ast/nodes/VariableDeclarator.js index 6e3391e..d5ccd94 100644 --- a/src/ast/nodes/VariableDeclarator.js +++ b/src/ast/nodes/VariableDeclarator.js @@ -1,6 +1,6 @@ import Node from '../Node.js'; import extractNames from '../utils/extractNames.js'; -import { UNKNOWN } from '../values.js'; +import { unknown } from '../values.js'; class DeclaratorProxy { constructor ( name, declarator, isTopLevel, init ) { @@ -63,7 +63,7 @@ export default class VariableDeclarator extends Node { const lexicalBoundary = scope.findLexicalBoundary(); 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; extractNames( this.id ).forEach( name => { @@ -98,6 +98,7 @@ export default class VariableDeclarator extends Node { } if ( this.init ) { + this.init.run(); this.scope.setValue( this.id.name, this.init.getValue() ); } else if ( this.parent.kind !== 'var' ) { this.scope.setValue( this.id.name, undefined ); // no longer TDZ violation diff --git a/src/ast/nodes/shared/callHasEffects.js b/src/ast/nodes/shared/callHasEffects.js index 2c37442..80b0c55 100644 --- a/src/ast/nodes/shared/callHasEffects.js +++ b/src/ast/nodes/shared/callHasEffects.js @@ -1,7 +1,7 @@ import isReference from 'is-reference'; import flatten from '../../utils/flatten.js'; import pureFunctions from './pureFunctions.js'; -import { UNKNOWN } from '../../values.js'; +import { unknown } from '../../values.js'; const currentlyCalling = new Set(); @@ -64,7 +64,7 @@ export default function callHasEffects ( scope, callee, isNew ) { const values = new Set([ callee ]); 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 ( fnHasEffects( node, isNew && isES5Function( node ) ) ) return true; diff --git a/src/ast/nodes/shared/isUsedByBundle.js b/src/ast/nodes/shared/isUsedByBundle.js index d33561a..2d4bbc1 100644 --- a/src/ast/nodes/shared/isUsedByBundle.js +++ b/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 ) { // const expression = node; @@ -18,7 +18,7 @@ export default function isUsedByBundle ( scope, node ) { const values = new Set(); declaration.gatherPossibleValues( values ); for ( const value of values ) { - if ( value === UNKNOWN ) { + if ( value === unknown ) { return true; } diff --git a/src/ast/scopes/BundleScope.js b/src/ast/scopes/BundleScope.js index fb3ab59..915d810 100644 --- a/src/ast/scopes/BundleScope.js +++ b/src/ast/scopes/BundleScope.js @@ -1,5 +1,5 @@ import Scope from './Scope.js'; -import { UNKNOWN } from '../values'; +import { unknown } from '../values'; class SyntheticGlobalDeclaration { constructor ( name ) { @@ -25,7 +25,15 @@ class SyntheticGlobalDeclaration { } gatherPossibleValues ( values ) { - values.add( UNKNOWN ); + values.add( unknown ); + } + + getInstance () { + return unknown; + } + + getProperty () { + return unknown; } getName () { diff --git a/src/ast/scopes/ModuleScope.js b/src/ast/scopes/ModuleScope.js index 82f9c09..99706f1 100644 --- a/src/ast/scopes/ModuleScope.js +++ b/src/ast/scopes/ModuleScope.js @@ -1,5 +1,6 @@ import { forOwn } from '../../utils/object.js'; import relativeId from '../../utils/relativeId.js'; +import { unknown } from '../values.js'; import Scope from './Scope.js'; export default class ModuleScope extends Scope { @@ -63,6 +64,8 @@ export default class ModuleScope extends Scope { const imported = this.module.imports[ name ]; if ( imported ) { + if ( imported.module.isExternal ) return unknown; + const exported = imported.module.exports[ imported.name ]; const exportedName = exported.localName === 'default' && exported.identifier ? exported.identifier : exported.localName; // TODO this is a mess return imported.module.scope.getValue( exportedName ); diff --git a/src/ast/scopes/Scope.js b/src/ast/scopes/Scope.js index 3219890..9a0331c 100644 --- a/src/ast/scopes/Scope.js +++ b/src/ast/scopes/Scope.js @@ -1,5 +1,5 @@ import { blank, keys } from '../../utils/object.js'; -import { UNKNOWN, TDZ_VIOLATION } from '../values.js'; +import { unknown, TDZ_VIOLATION } from '../values.js'; class Parameter { constructor ( name ) { @@ -18,7 +18,7 @@ class Parameter { } gatherPossibleValues ( values ) { - values.add( UNKNOWN ); // TODO populate this at call time + values.add( unknown ); // TODO populate this at call time } getName () { diff --git a/src/ast/values.js b/src/ast/values.js index 6524984..e8e2870 100644 --- a/src/ast/values.js +++ b/src/ast/values.js @@ -5,5 +5,22 @@ export const FUNCTION = { FUNCTION: true, toString: () => '[[FUNCTION]]' }; export const NUMBER = { NUMBER: true, toString: () => '[[NUMBER]]' }; export const OBJECT = { OBJECT: true, toString: () => '[[OBJECT]]' }; 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 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(); diff --git a/test/form/_tk/_config.js b/test/form/_tk/_config.js index 700dff7..f4b9a36 100644 --- a/test/form/_tk/_config.js +++ b/test/form/_tk/_config.js @@ -1,3 +1,3 @@ module.exports = { - // solo: true + solo: true }; diff --git a/test/form/empty-if-statement/_config.js b/test/form/empty-if-statement/_config.js index 87d4156..abea889 100644 --- a/test/form/empty-if-statement/_config.js +++ b/test/form/empty-if-statement/_config.js @@ -1,4 +1,3 @@ module.exports = { - solo: true, description: 'removes an empty if statement' }; diff --git a/test/form/relative-external-with-global/_expected/amd.js b/test/form/relative-external-with-global/_expected/amd.js index 538e97a..ce7a063 100644 --- a/test/form/relative-external-with-global/_expected/amd.js +++ b/test/form/relative-external-with-global/_expected/amd.js @@ -6,6 +6,6 @@ define(['./lib/throttle.js'], function (throttle) { 'use strict'; console.log( '.' ); }, 500 ); - window.addEventListener( 'mousemove', throttle ); + window.addEventListener( 'mousemove', fn ); -}); \ No newline at end of file +}); diff --git a/test/form/relative-external-with-global/_expected/cjs.js b/test/form/relative-external-with-global/_expected/cjs.js index 1b74d56..66db588 100644 --- a/test/form/relative-external-with-global/_expected/cjs.js +++ b/test/form/relative-external-with-global/_expected/cjs.js @@ -8,4 +8,4 @@ const fn = throttle( () => { console.log( '.' ); }, 500 ); -window.addEventListener( 'mousemove', throttle ); \ No newline at end of file +window.addEventListener( 'mousemove', fn ); diff --git a/test/form/relative-external-with-global/_expected/es.js b/test/form/relative-external-with-global/_expected/es.js index fe8f7cf..a62d1ed 100644 --- a/test/form/relative-external-with-global/_expected/es.js +++ b/test/form/relative-external-with-global/_expected/es.js @@ -4,4 +4,4 @@ const fn = throttle( () => { console.log( '.' ); }, 500 ); -window.addEventListener( 'mousemove', throttle ); \ No newline at end of file +window.addEventListener( 'mousemove', fn ); diff --git a/test/form/relative-external-with-global/_expected/iife.js b/test/form/relative-external-with-global/_expected/iife.js index a0efcee..fa8b31d 100644 --- a/test/form/relative-external-with-global/_expected/iife.js +++ b/test/form/relative-external-with-global/_expected/iife.js @@ -7,6 +7,6 @@ console.log( '.' ); }, 500 ); - window.addEventListener( 'mousemove', throttle ); + window.addEventListener( 'mousemove', fn ); }(Lib.throttle)); diff --git a/test/form/relative-external-with-global/_expected/umd.js b/test/form/relative-external-with-global/_expected/umd.js index 5ab1989..f59c807 100644 --- a/test/form/relative-external-with-global/_expected/umd.js +++ b/test/form/relative-external-with-global/_expected/umd.js @@ -10,6 +10,6 @@ console.log( '.' ); }, 500 ); - window.addEventListener( 'mousemove', throttle ); + window.addEventListener( 'mousemove', fn ); }))); diff --git a/test/form/relative-external-with-global/main.js b/test/form/relative-external-with-global/main.js index 750ac95..a62d1ed 100644 --- a/test/form/relative-external-with-global/main.js +++ b/test/form/relative-external-with-global/main.js @@ -4,4 +4,4 @@ const fn = throttle( () => { console.log( '.' ); }, 500 ); -window.addEventListener( 'mousemove', throttle ); +window.addEventListener( 'mousemove', fn );