optimize generated code for if statements

Instead of walking elseif statements recursively, collect all the
conditions and blocks into a single if block
pull/28/head
Arpad Borsos 8 years ago
parent fd9dc9033a
commit 64f8e77999
No known key found for this signature in database
GPG Key ID: 908EDF65263368B4

@ -1,23 +0,0 @@
import counter from '../utils/counter.js';
export default {
enter ( generator ) {
const name = generator.current.name.replace( 'If', 'Else' );
generator.push({
name,
localElementDepth: 0,
initStatements: [],
updateStatements: [],
teardownStatements: [],
counter: counter()
});
},
leave ( generator ) {
generator.addRenderer( generator.current );
generator.pop();
}
};

@ -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();
}
};

@ -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';
@ -10,7 +9,6 @@ export default {
Comment,
EachBlock,
Element,
ElseBlock,
IfBlock,
MustacheTag,
Text

Loading…
Cancel
Save