| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- class Block {
- constructor( node, parent = null ) {
- this.node = node;
- this.parent = parent;
- this.properties = {};
- }
- setProperty( name, value ) {
- this.properties[ name ] = value;
- }
- getProperty( name ) {
- let value = this.properties[ name ];
- if ( value === undefined && this.parent !== null ) {
- value = this.parent.getProperty( name );
- }
- return value;
- }
- }
- class Linker {
- constructor() {
- this.block = null;
- }
- addBlock( node ) {
- this.block = new Block( node, this.block );
- }
- removeBlock( node ) {
- if ( this.block === null || this.block.node !== node ) {
- throw new Error( 'No block to remove or block mismatch.' );
- }
- this.block = this.block.parent;
- }
- processVariables( node ) {
- this.block.setProperty( node.name, node );
- if ( node.value ) {
- this.processExpression( node.value );
- }
- }
- processUniform( node ) {
- this.block.setProperty( node.name, node );
- }
- processVarying( node ) {
- this.block.setProperty( node.name, node );
- }
- evalProperty( node ) {
- let property = '';
- if ( node.isAccessor ) {
- property += node.property;
- }
- return property;
- }
- processExpression( node ) {
- if ( node.isAccessor ) {
- const property = this.block.getProperty( this.evalProperty( node ) );
- if ( property ) {
- node.linker.reference = property;
- property.linker.accesses.push( node );
- }
- } else if ( node.isNumber || node.isString ) {
- // Process primitive values
- } else if ( node.isOperator ) {
- this.processExpression( node.left );
- this.processExpression( node.right );
- if ( node.isAssignment ) {
- const property = this.block.getProperty( this.evalProperty( node.left ) );
- if ( property ) {
- property.linker.assignments.push( node );
- }
- }
- } else if ( node.isFunctionCall ) {
- for ( const param of node.params ) {
- this.processExpression( param );
- }
- } else if ( node.isReturn ) {
- if ( node.value ) this.processExpression( node.value );
- } else if ( node.isDiscard || node.isBreak || node.isContinue ) {
- // Process control flow
- } else if ( node.isAccessorElements ) {
- this.processExpression( node.object );
- for ( const element of node.elements ) {
- this.processExpression( element.value );
- }
- } else if ( node.isDynamicElement || node.isStaticElement ) {
- this.processExpression( node.value );
- } else if ( node.isFor || node.isWhile ) {
- this.processForWhile( node );
- } else if ( node.isSwitch ) {
- this.processSwitch( node );
- } else if ( node.isVariableDeclaration ) {
- this.processVariables( node );
- } else if ( node.isUniform ) {
- this.processUniform( node );
- } else if ( node.isVarying ) {
- this.processVarying( node );
- } else if ( node.isTernary ) {
- this.processExpression( node.cond );
- this.processExpression( node.left );
- this.processExpression( node.right );
- } else if ( node.isConditional ) {
- this.processConditional( node );
- } else if ( node.isUnary ) {
- this.processExpression( node.expression );
- if ( node.isAssignment ) {
- if ( node.parent.hasAssignment !== true ) {
- // optimize increment/decrement operator
- // to avoid creating a new variable
- node.after = false;
- }
- const property = this.block.getProperty( this.evalProperty( node.expression ) );
- if ( property ) {
- property.linker.assignments.push( node );
- }
- }
- }
- }
- processBody( body ) {
- for ( const statement of body ) {
- this.processExpression( statement );
- }
- }
- processConditional( node ) {
- this.processExpression( node.cond );
- this.processBody( node.body );
- let current = node;
- while ( current.elseConditional ) {
- if ( current.elseConditional.cond ) {
- this.processExpression( current.elseConditional.cond );
- }
- this.processBody( current.elseConditional.body );
- current = current.elseConditional;
- }
- }
- processForWhile( node ) {
- if ( node.initialization ) this.processExpression( node.initialization );
- if ( node.condition ) this.processExpression( node.condition );
- if ( node.afterthought ) this.processExpression( node.afterthought );
- this.processBody( node.body );
- }
- processSwitch( switchNode ) {
- this.processExpression( switchNode.discriminant );
- for ( const switchCase of switchNode.cases ) {
- if ( switchCase.isDefault !== true ) {
- for ( const condition of switchCase.conditions ) {
- this.processExpression( condition );
- }
- }
- this.processBody( switchCase.body );
- }
- }
- processFunction( node ) {
- this.addBlock( node );
- for ( const param of node.params ) {
- this.block.setProperty( param.name, param );
- }
- this.processBody( node.body );
- this.removeBlock( node );
- }
- process( ast ) {
- this.addBlock( ast );
- for ( const statement of ast.body ) {
- if ( statement.isFunctionDeclaration ) {
- this.processFunction( statement );
- } else {
- this.processExpression( statement );
- }
- }
- this.removeBlock( ast );
- }
- }
- export default Linker;
|