From 7afadff2683b845fa90d0c6d302c834dbe361749 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sat, 10 Sep 2016 19:44:28 -0400 Subject: [PATCH] handle body-less for loops etc --- src/ast/Node.js | 8 +++-- src/ast/nodes/ArrowFunctionExpression.js | 4 +-- src/ast/nodes/ForInStatement.js | 17 +++++++++-- src/ast/nodes/ForOfStatement.js | 17 +++++++++-- src/ast/nodes/ForStatement.js | 29 ++++++++++--------- test/form/body-less-for-loops/_config.js | 3 ++ .../form/body-less-for-loops/_expected/amd.js | 16 ++++++++++ .../form/body-less-for-loops/_expected/cjs.js | 14 +++++++++ test/form/body-less-for-loops/_expected/es.js | 12 ++++++++ .../body-less-for-loops/_expected/iife.js | 17 +++++++++++ .../form/body-less-for-loops/_expected/umd.js | 20 +++++++++++++ test/form/body-less-for-loops/main.js | 12 ++++++++ 12 files changed, 144 insertions(+), 25 deletions(-) create mode 100644 test/form/body-less-for-loops/_config.js create mode 100644 test/form/body-less-for-loops/_expected/amd.js create mode 100644 test/form/body-less-for-loops/_expected/cjs.js create mode 100644 test/form/body-less-for-loops/_expected/es.js create mode 100644 test/form/body-less-for-loops/_expected/iife.js create mode 100644 test/form/body-less-for-loops/_expected/umd.js create mode 100644 test/form/body-less-for-loops/main.js diff --git a/src/ast/Node.js b/src/ast/Node.js index 0343f28..4f65871 100644 --- a/src/ast/Node.js +++ b/src/ast/Node.js @@ -3,7 +3,7 @@ import getLocation from '../utils/getLocation.js'; export default class Node { bind ( scope ) { - this.eachChild( child => child.bind( scope ) ); + this.eachChild( child => child.bind( this.scope || scope ) ); } eachChild ( callback ) { @@ -43,6 +43,8 @@ export default class Node { } hasEffects ( scope ) { + if ( this.scope ) scope = this.scope; + for ( const key of this.keys ) { const value = this[ key ]; @@ -61,7 +63,7 @@ export default class Node { } initialise ( scope ) { - this.eachChild( child => child.initialise( scope ) ); + this.eachChild( child => child.initialise( this.scope || scope ) ); } locate () { @@ -82,7 +84,7 @@ export default class Node { this.ran = true; this.eachChild( child => { - child.run( scope ); + child.run( this.scope || scope ); }); } diff --git a/src/ast/nodes/ArrowFunctionExpression.js b/src/ast/nodes/ArrowFunctionExpression.js index 257c7a3..8d9a3d2 100644 --- a/src/ast/nodes/ArrowFunctionExpression.js +++ b/src/ast/nodes/ArrowFunctionExpression.js @@ -18,6 +18,7 @@ export default class ArrowFunctionExpression extends Node { initialise ( scope ) { if ( this.body.type === 'BlockStatement' ) { this.body.createScope( scope ); + this.scope = this.body.scope; } else { this.scope = new Scope({ parent: scope, @@ -32,7 +33,6 @@ export default class ArrowFunctionExpression extends Node { } } - scope = this.scope || this.body.scope; - super.initialise( scope ); + super.initialise( this.scope ); } } diff --git a/src/ast/nodes/ForInStatement.js b/src/ast/nodes/ForInStatement.js index 0838aa1..1872b96 100644 --- a/src/ast/nodes/ForInStatement.js +++ b/src/ast/nodes/ForInStatement.js @@ -1,11 +1,22 @@ import Statement from './shared/Statement.js'; import assignTo from './shared/assignTo.js'; +import Scope from '../scopes/Scope.js'; import { STRING } from '../values.js'; export default class ForInStatement extends Statement { initialise ( scope ) { - this.body.createScope( scope ); - super.initialise( this.body.scope ); - assignTo( this.left, this.body.scope, STRING ); + if ( this.body.type === 'BlockStatement' ) { + this.body.createScope( scope ); + this.scope = this.body.scope; + } else { + this.scope = new Scope({ + parent: scope, + isBlockScope: true, + isLexicalBoundary: false + }); + } + + super.initialise( this.scope ); + assignTo( this.left, this.scope, STRING ); } } diff --git a/src/ast/nodes/ForOfStatement.js b/src/ast/nodes/ForOfStatement.js index e761433..a5225f8 100644 --- a/src/ast/nodes/ForOfStatement.js +++ b/src/ast/nodes/ForOfStatement.js @@ -1,11 +1,22 @@ import Statement from './shared/Statement.js'; import assignTo from './shared/assignTo.js'; +import Scope from '../scopes/Scope.js'; import { UNKNOWN } from '../values.js'; export default class ForOfStatement extends Statement { initialise ( scope ) { - this.body.createScope( scope ); - super.initialise( this.body.scope ); - assignTo( this.left, this.body.scope, UNKNOWN ); + if ( this.body.type === 'BlockStatement' ) { + this.body.createScope( scope ); + this.scope = this.body.scope; + } else { + this.scope = new Scope({ + parent: scope, + isBlockScope: true, + isLexicalBoundary: false + }); + } + + super.initialise( this.scope ); + assignTo( this.left, this.scope, UNKNOWN ); } } diff --git a/src/ast/nodes/ForStatement.js b/src/ast/nodes/ForStatement.js index 1d61b02..11e98e5 100644 --- a/src/ast/nodes/ForStatement.js +++ b/src/ast/nodes/ForStatement.js @@ -1,22 +1,23 @@ import Statement from './shared/Statement.js'; +import Scope from '../scopes/Scope.js'; export default class ForStatement extends Statement { - hasEffects () { - return super.hasEffects( this.body.scope ); - } - initialise ( scope ) { - this.body.createScope( scope ); - scope = this.body.scope; + if ( this.body.type === 'BlockStatement' ) { + this.body.createScope( scope ); + this.scope = this.body.scope; + } else { + this.scope = new Scope({ + parent: scope, + isBlockScope: true, + isLexicalBoundary: false + }); + } // can't use super, because we need to control the order - if ( this.init ) this.init.initialise( scope ); - if ( this.test ) this.test.initialise( scope ); - if ( this.update ) this.update.initialise( scope ); - this.body.initialise( scope ); - } - - run ( scope ) { - super.run( scope ); + if ( this.init ) this.init.initialise( this.scope ); + if ( this.test ) this.test.initialise( this.scope ); + if ( this.update ) this.update.initialise( this.scope ); + this.body.initialise( this.scope ); } } diff --git a/test/form/body-less-for-loops/_config.js b/test/form/body-less-for-loops/_config.js new file mode 100644 index 0000000..a748fa0 --- /dev/null +++ b/test/form/body-less-for-loops/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'supports body-less for loops' +}; diff --git a/test/form/body-less-for-loops/_expected/amd.js b/test/form/body-less-for-loops/_expected/amd.js new file mode 100644 index 0000000..464893d --- /dev/null +++ b/test/form/body-less-for-loops/_expected/amd.js @@ -0,0 +1,16 @@ +define(function () { 'use strict'; + + for ( let i = 0; i < 10; i += 1 ) console.log( i ); + for ( const letter of array ) console.log( letter ); + for ( const index in array ) console.log( index ); + + let i; + for ( i = 0; i < 10; i += 1 ) console.log( i ); + + let letter; + for ( letter of array ) console.log( letter ); + + let index; + for ( index in array ) console.log( index ); + +}); \ No newline at end of file diff --git a/test/form/body-less-for-loops/_expected/cjs.js b/test/form/body-less-for-loops/_expected/cjs.js new file mode 100644 index 0000000..f2e4fde --- /dev/null +++ b/test/form/body-less-for-loops/_expected/cjs.js @@ -0,0 +1,14 @@ +'use strict'; + +for ( let i = 0; i < 10; i += 1 ) console.log( i ); +for ( const letter of array ) console.log( letter ); +for ( const index in array ) console.log( index ); + +let i; +for ( i = 0; i < 10; i += 1 ) console.log( i ); + +let letter; +for ( letter of array ) console.log( letter ); + +let index; +for ( index in array ) console.log( index ); \ No newline at end of file diff --git a/test/form/body-less-for-loops/_expected/es.js b/test/form/body-less-for-loops/_expected/es.js new file mode 100644 index 0000000..63ee4e5 --- /dev/null +++ b/test/form/body-less-for-loops/_expected/es.js @@ -0,0 +1,12 @@ +for ( let i = 0; i < 10; i += 1 ) console.log( i ); +for ( const letter of array ) console.log( letter ); +for ( const index in array ) console.log( index ); + +let i; +for ( i = 0; i < 10; i += 1 ) console.log( i ); + +let letter; +for ( letter of array ) console.log( letter ); + +let index; +for ( index in array ) console.log( index ); \ No newline at end of file diff --git a/test/form/body-less-for-loops/_expected/iife.js b/test/form/body-less-for-loops/_expected/iife.js new file mode 100644 index 0000000..2214bd4 --- /dev/null +++ b/test/form/body-less-for-loops/_expected/iife.js @@ -0,0 +1,17 @@ +(function () { + 'use strict'; + + for ( let i = 0; i < 10; i += 1 ) console.log( i ); + for ( const letter of array ) console.log( letter ); + for ( const index in array ) console.log( index ); + + let i; + for ( i = 0; i < 10; i += 1 ) console.log( i ); + + let letter; + for ( letter of array ) console.log( letter ); + + let index; + for ( index in array ) console.log( index ); + +}()); \ No newline at end of file diff --git a/test/form/body-less-for-loops/_expected/umd.js b/test/form/body-less-for-loops/_expected/umd.js new file mode 100644 index 0000000..9840021 --- /dev/null +++ b/test/form/body-less-for-loops/_expected/umd.js @@ -0,0 +1,20 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + + for ( let i = 0; i < 10; i += 1 ) console.log( i ); + for ( const letter of array ) console.log( letter ); + for ( const index in array ) console.log( index ); + + let i; + for ( i = 0; i < 10; i += 1 ) console.log( i ); + + let letter; + for ( letter of array ) console.log( letter ); + + let index; + for ( index in array ) console.log( index ); + +}))); \ No newline at end of file diff --git a/test/form/body-less-for-loops/main.js b/test/form/body-less-for-loops/main.js new file mode 100644 index 0000000..3aa7b7e --- /dev/null +++ b/test/form/body-less-for-loops/main.js @@ -0,0 +1,12 @@ +for ( let i = 0; i < 10; i += 1 ) console.log( i ); +for ( const letter of array ) console.log( letter ); +for ( const index in array ) console.log( index ); + +let i; +for ( i = 0; i < 10; i += 1 ) console.log( i ); + +let letter; +for ( letter of array ) console.log( letter ); + +let index; +for ( index in array ) console.log( index );