Skip to content

Commit

Permalink
Merge pull request #28 from Swatinem/optimize_if
Browse files Browse the repository at this point in the history
optimize generated code for if statements
  • Loading branch information
Rich-Harris authored Nov 30, 2016
2 parents 6860507 + 64f8e77 commit 5a2e5c2
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 121 deletions.
23 changes: 0 additions & 23 deletions compiler/generate/visitors/ElseBlock.js

This file was deleted.

166 changes: 70 additions & 96 deletions compiler/generate/visitors/IfBlock.js
Original file line number Diff line number Diff line change
@@ -1,125 +1,99 @@
import deindent from '../utils/deindent.js';
import counter from '../utils/counter.js';

// collect all the conditions and blocks in the if/elseif/else chain
function generateBlock ( generator, node, name ) {
// walk the children here
generator.push({
useAnchor: true,
name,
target: 'target',
localElementDepth: 0,

initStatements: [],
updateStatements: [],
teardownStatements: [],

counter: counter()
});
node.children.forEach( generator.visit );
//generator.visit( node.children );
generator.addRenderer( generator.current );
generator.pop();
// unset the children, to avoid them being visited again
node.children = [];
}
function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
generator.addSourcemapLocations( node.expression );
const name = `${_name}_${i}`;

const conditionsAndBlocks = [{
condition: generator.contextualise( node.expression ).snippet,
block: name
}];
generateBlock( generator, node, name );

if ( node.else && node.else.children.length === 1 &&
node.else.children[0].type === 'IfBlock' ) {
conditionsAndBlocks.push(
...getConditionsAndBlocks( generator, node.else.children[0], _name, i + 1 ) );
} else {
const name = `${_name}_${i + 1}`;
conditionsAndBlocks.push({
condition: null,
block: node.else ? name : null,
});
if (node.else) {
generateBlock( generator, node.else, name );
}
}
return conditionsAndBlocks;
}

export default {
enter ( generator, node ) {
const i = generator.counters.if++;
const name = `ifBlock_${i}`;
const renderer = `renderIfBlock_${i}`;

const elseName = `elseBlock_${i}`;
const elseRenderer = `renderElseBlock_${i}`;
const { params, target } = generator.current;
const name = `ifBlock_${i}`;
const getBlock = `getBlock_${i}`;
const currentBlock = `currentBlock_${i}`;

generator.addSourcemapLocations( node.expression );
const { snippet } = generator.contextualise( node.expression );
const conditionsAndBlocks = getConditionsAndBlocks( generator, node, `renderIfBlock_${i}` );

generator.current.initStatements.push( deindent`
var ${name}_anchor = document.createComment( ${JSON.stringify( `#if ${generator.source.slice( node.expression.start, node.expression.end )}` )} );
${generator.appendToTarget( `${name}_anchor` )};
` );
if ( node.else ) {
generator.current.initStatements.push( deindent`
var ${name} = null;
var ${elseName} = null;
if ( ${snippet} ) {
${name} = ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
} else {
${elseName} = ${elseRenderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
}
` );
} else {
generator.current.initStatements.push( deindent`
var ${name} = ${snippet} ? ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor ) : null;
` );
}

const ifTrue = [ deindent`
if ( !${name } ) {
${name} = ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
} else {
${name}.update( changed, ${generator.current.params} );
}
` ];

if ( node.else ) {
ifTrue.push( deindent`
if ( ${elseName } ) {
${elseName}.teardown( true );
${elseName} = null;
}
` );
}

const ifFalse = [ deindent`
if ( ${name} ) {
${name}.teardown( true );
${name} = null;
function ${getBlock} ( ${params} ) {
${conditionsAndBlocks.map( ({ condition, block }) => {
return `${condition ? `if ( ${condition} ) ` : ''}return ${block};`;
} ).join( '\n' )}
}
` ];

if ( node.else ) {
ifFalse.push( deindent`
if ( !${elseName } ) {
${elseName} = ${elseRenderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
} else {
${elseName}.update( changed, ${generator.current.params} );
}
` );
}
let update = deindent`
if ( ${snippet} ) {
${ifTrue.join( '\n\n' )}
}
var ${currentBlock} = ${getBlock}( ${params} );
var ${name} = ${currentBlock} && ${currentBlock}( ${params}, component, ${target}, ${name}_anchor );
` );

else {
${ifFalse.join( '\n\n' )}
generator.current.updateStatements.push( deindent`
var _${currentBlock} = ${currentBlock};
${currentBlock} = ${getBlock}( ${params} );
if ( _${currentBlock} === ${currentBlock} && ${name}) {
${name}.update( changed, ${params} );
} else {
if ( ${name} ) ${name}.teardown( true );
${name} = ${currentBlock} && ${currentBlock}( ${params}, component, ${target}, ${name}_anchor );
}
`;

if ( node.else ) {
update += `\nif ( ${elseName} ) ${elseName}.update( changed, ${generator.current.params} );`;
}

generator.current.updateStatements.push( update );
` );

const teardownStatements = [
`if ( ${name} ) ${name}.teardown( detach );`
];

if ( node.else ) {
teardownStatements.push( `if ( ${elseName} ) ${elseName}.teardown( detach );` );
}

if ( generator.current.localElementDepth === 0 ) {
teardownStatements.push( `if ( detach ) ${name}_anchor.parentNode.removeChild( ${name}_anchor );` );
}

generator.current.teardownStatements.push( teardownStatements.join( '\n' ) );

generator.push({
useAnchor: true,
name: renderer,
target: 'target',
localElementDepth: 0,

initStatements: [],
updateStatements: [],
teardownStatements: [],

counter: counter()
});
},

leave ( generator, node ) {
generator.addRenderer( generator.current );

if ( node.else ) {
generator.visit( node.else );
}

generator.pop();
}
};
2 changes: 0 additions & 2 deletions compiler/generate/visitors/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Comment from './Comment.js';
import EachBlock from './EachBlock.js';
import Element from './Element.js';
import ElseBlock from './ElseBlock.js';
import IfBlock from './IfBlock.js';
import MustacheTag from './MustacheTag.js';
import Text from './Text.js';
Expand All @@ -10,7 +9,6 @@ export default {
Comment,
EachBlock,
Element,
ElseBlock,
IfBlock,
MustacheTag,
Text
Expand Down

0 comments on commit 5a2e5c2

Please sign in to comment.