📄 Linker.js
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 15 |
🧱 Classes | 2 |
📊 Variables & Constants | 3 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 examples/jsm/transpiler/Linker.js
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
value |
any |
let/var | this.properties[ name ] |
✗ |
property |
string |
let/var | '' |
✗ |
current |
any |
let/var | node |
✗ |
Functions¶
Block.setProperty(name: any, value: any): void
¶
Parameters:
name
any
value
any
Returns: void
Block.getProperty(name: any): any
¶
Parameters:
name
any
Returns: any
Calls:
this.parent.getProperty
Code
Linker.addBlock(node: any): void
¶
Parameters:
node
any
Returns: void
Linker.removeBlock(node: any): void
¶
Parameters:
node
any
Returns: void
Code
Linker.processVariables(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.block.setProperty
this.processExpression
Code
Linker.processUniform(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.block.setProperty
Linker.processVarying(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.block.setProperty
Linker.evalProperty(node: any): string
¶
Parameters:
node
any
Returns: string
Code
Linker.processExpression(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.block.getProperty
this.evalProperty
property.linker.accesses.push
this.processExpression
property.linker.assignments.push
this.processForWhile
this.processSwitch
this.processVariables
this.processUniform
this.processVarying
this.processConditional
Internal Comments:
Code
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 );
}
}
}
}
Linker.processBody(body: any): void
¶
Parameters:
body
any
Returns: void
Calls:
this.processExpression
Code
Linker.processConditional(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.processExpression
this.processBody
Code
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;
}
}
Linker.processForWhile(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.processExpression
this.processBody
Code
Linker.processSwitch(switchNode: any): void
¶
Parameters:
switchNode
any
Returns: void
Calls:
this.processExpression
this.processBody
Code
Linker.processFunction(node: any): void
¶
Parameters:
node
any
Returns: void
Calls:
this.addBlock
this.block.setProperty
this.processBody
this.removeBlock
Code
Linker.process(ast: any): void
¶
Parameters:
ast
any
Returns: void
Calls:
this.addBlock
this.processFunction
this.processExpression
this.removeBlock
Code
Classes¶
Block
¶
Class Code
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;
}
}
Methods¶
setProperty(name: any, value: any): void
¶
getProperty(name: any): any
¶
Code
Linker
¶
Class Code
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 );
}
}
Methods¶
addBlock(node: any): void
¶
removeBlock(node: any): void
¶
Code
processVariables(node: any): void
¶
Code
processUniform(node: any): void
¶
processVarying(node: any): void
¶
evalProperty(node: any): string
¶
Code
processExpression(node: any): void
¶
Code
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: any): void
¶
Code
processConditional(node: any): void
¶
Code
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;
}
}