Automatic inner functions

This commit is contained in:
Fazli Sapuan 2016-02-25 00:24:05 +08:00
parent 0f4de2c3e0
commit c2cbe2a1c4
6 changed files with 66 additions and 20 deletions

View File

@ -15,8 +15,9 @@ var functionBuilder = (function() {
///
/// [Constructor] Blank constructor, which initializes the properties
///
function functionBuilder() {
function functionBuilder(gpu) {
this.nodeMap = {};
this.gpu = gpu;
}
///
@ -24,14 +25,15 @@ var functionBuilder = (function() {
///
/// Creates the functionNode, and add it to the nodeMap
///
/// Parameters:
/// Parameters:
/// gpu - {GPU} The GPU instance
/// functionName - {String} Function name to assume, if its null, it attempts to extract from the function
/// jsFunction - {JS Function} JS Function to do conversion
/// jsFunction - {JS Function} JS Function to do conversion
/// paramTypeArray - {[String,...]} Parameter type array, assumes all parameters are "float" if null
/// returnType - {String} The return type, assumes "float" if null
///
function addFunction( functionName, jsFunction, paramTypeArray, returnType ) {
this.addFunctionNode( new functionNode( functionName, jsFunction, paramTypeArray, returnType ) );
this.addFunctionNode( new functionNode( this.gpu, functionName, jsFunction, paramTypeArray, returnType ) );
}
functionBuilder.prototype.addFunction = addFunction;
@ -40,7 +42,7 @@ var functionBuilder = (function() {
///
/// Add the funciton node directly
///
/// Parameters:
/// Parameters:
/// inNode - {functionNode} functionNode to add
///
function addFunctionNode( inNode ) {
@ -56,7 +58,7 @@ var functionBuilder = (function() {
/// This allow for "uneeded" functions to be automatically optimized out.
/// Note that the 0-index, is the starting function trace.
///
/// Parameters:
/// Parameters:
/// functionName - {String} Function name to trace from, default to "kernel"
/// retList - {[String,...]} Returning list of function names that is traced. Including itself.
///
@ -88,7 +90,7 @@ var functionBuilder = (function() {
///
/// Function: webglString_fromFunctionNames
///
/// Parameters:
/// Parameters:
/// functionList - {[String,...]} List of function to build the webgl string.
///
/// Returns:
@ -109,7 +111,7 @@ var functionBuilder = (function() {
///
/// Function: webglString
///
/// Parameters:
/// Parameters:
/// functionName - {String} Function name to trace from. If null, it returns the WHOLE builder stack
///
/// Returns:
@ -118,7 +120,7 @@ var functionBuilder = (function() {
function webglString(functionName) {
if(functionName) {
return this.webglString_fromFunctionNames( this.traceFunctionCalls(functionName, []).reverse() );
}
}
return this.webglString_fromFunctionNames(Object.keys(this.nodeMap));
}
functionBuilder.prototype.webglString = webglString;

View File

@ -31,12 +31,15 @@ var functionNode = (function() {
/// [Constructor] Builds the function with the given JS function, and argument type array.
///
/// Parameters:
/// gpu - {GPU} The GPU instance
/// functionName - {String} Function name to assume, if its null, it attempts to extract from the function
/// jsFunction - {JS Function} JS Function to do conversion
/// paramTypeArray - {[String,...]} Parameter type array, assumes all parameters are "float" if null
/// returnType - {String} The return type, assumes "float" if null
///
function functionNode( functionName, jsFunction, paramTypeArray, returnType ) {
function functionNode( gpu, functionName, jsFunction, paramTypeArray, returnType ) {
this.gpu = gpu;
//
// Internal vars setup

View File

@ -1,6 +1,8 @@
// Closure capture for the ast function, prevent collision with existing AST functions
var functionNode_webgl = (function() {
var gpu, jsFunctionString;
///
/// Function: functionNode_webgl
///
@ -13,6 +15,8 @@ var functionNode_webgl = (function() {
/// the converted webGL function string
///
function functionNode_webgl( inNode ) {
gpu = inNode.gpu;
jsFunctionString = inNode.jsFunctionString;
inNode.webglFunctionString_array = ast_generic( inNode.getJS_AST(), [], inNode );
inNode.webglFunctionString = inNode.webglFunctionString_array.join("").trim();
return inNode.webglFunctionString;
@ -49,6 +53,8 @@ var functionNode_webgl = (function() {
}
switch(ast.type) {
case "FunctionDeclaration":
return ast_FunctionDeclaration(ast, retArr, funcParam);
case "FunctionExpression":
return ast_FunctionExpression(ast, retArr, funcParam);
case "ReturnStatement":
@ -99,6 +105,38 @@ var functionNode_webgl = (function() {
}
}
/// Prases the abstract syntax tree, to its named function declartion
///
/// @param ast the AST object to parse
/// @param retArr return array string
/// @param funcParam FunctionNode, that tracks compilation state
///
/// @returns the appened retArr
function ast_FunctionDeclaration(ast, retArr, funcParam) {
// TODO: make this less hacky?
var lines = jsFunctionString.split(/\r?\n/);
var start = ast.loc.start;
var end = ast.loc.end;
var funcArr = [];
funcArr.push(lines[start.line-1].slice(start.column));
for (var i=start.line; i<end.line-1; i++) {
funcArr.push(lines[i]);
}
funcArr.push(lines[end.line-1].slice(0,end.column));
var funcStr = funcArr.join('\n');
// TODO: fix this evil!
eval('var funcObj = ' + funcStr);
gpu.addFunction(funcObj);
return retArr;
}
/// Prases the abstract syntax tree, to its named function
///
/// @param ast the AST object to parse
@ -126,6 +164,7 @@ var functionNode_webgl = (function() {
retArr.push( funcParam.paramType[i] );
retArr.push(" ");
retArr.push("user_");
retArr.push( funcParam.paramNames[i] );
}
@ -251,10 +290,8 @@ var functionNode_webgl = (function() {
retArr.push('uOutputDim.y');
} else if (idtNode.name == "gpu_dimensionsZ") {
retArr.push('uOutputDim.z');
} else if(funcParam.isRootKernel) {
retArr.push("user_"+idtNode.name);
} else {
retArr.push(idtNode.name);
retArr.push("user_"+idtNode.name);
}
return retArr;

View File

@ -150,7 +150,7 @@
var builder = this.functionBuilder;
var endianness = this.endianness;
var kernelNode = new functionNode("kernel", kernel);
var kernelNode = new functionNode(gpu, "kernel", kernel);
kernelNode.paramNames = [];
kernelNode.paramType = [];
kernelNode.isRootKernel = true;

View File

@ -43,7 +43,7 @@ var GPU = (function() {
this.programCache = {};
this.endianness = endianness();
this.functionBuilder = new functionBuilder();
this.functionBuilder = new functionBuilder(this);
this.functionBuilder.polyfillStandardFunctions();
}

View File

@ -8,6 +8,7 @@ QUnit.test( "hello_world: just return magic 42", function( assert ) {
// Create a function hello node
var node = new functionNode(
null,
"hello_world",
function() {
return 42;
@ -17,7 +18,7 @@ QUnit.test( "hello_world: just return magic 42", function( assert ) {
assert.notEqual( node, null, "class creation check" );
assert.notEqual( node.getJS_AST(), null, "AST fetch check" );
assert.equal(
assert.equal(
node.getWebglFunctionString().replace(/\s+/g,' '),
"float hello_world() { return 42.0; }",
"webgl function conversion check"
@ -34,6 +35,7 @@ QUnit.test( "hello_inner: call a funciton inside a function", function( assert )
// Create a function hello node
var node = new functionNode(
null,
"hello_inner",
function() {
return inner();
@ -43,7 +45,7 @@ QUnit.test( "hello_inner: call a funciton inside a function", function( assert )
assert.notEqual( node, null, "class creation check" );
assert.notEqual( node.getJS_AST(), null, "AST fetch check" );
assert.equal(
assert.equal(
node.getWebglFunctionString().replace(/\s+/g,' '),
"float hello_inner() { return inner(); }",
"webgl function conversion check"
@ -56,6 +58,7 @@ QUnit.test( "hello_inner: call a funciton inside a function", function( assert )
QUnit.test( "Math.round implementation: A function with arguments", function( assert ) {
// Math.round node
var node = new functionNode(
null,
"round",
function(a) {
return Math.floor( a + 0.5 );
@ -65,7 +68,7 @@ QUnit.test( "Math.round implementation: A function with arguments", function( as
assert.notEqual( node, null, "class creation check" );
assert.notEqual( node.getJS_AST(), null, "AST fetch check" );
assert.equal(
assert.equal(
node.getWebglFunctionString().replace(/\s+/g,' '),
"float round(float a) { return floor(a+0.5); }",
"webgl function conversion check"
@ -78,6 +81,7 @@ QUnit.test( "Math.round implementation: A function with arguments", function( as
QUnit.test( "Two arguments test", function( assert ) {
var node = new functionNode(
null,
"add_together",
function(a,b) {
return a+b;
@ -87,7 +91,7 @@ QUnit.test( "Two arguments test", function( assert ) {
assert.notEqual( node, null, "class creation check" );
assert.notEqual( node.getJS_AST(), null, "AST fetch check" );
assert.equal(
assert.equal(
node.getWebglFunctionString().replace(/\s+/g,' '),
"float add_together(float a, float b) { return a+b; }",
"webgl function conversion check"
@ -102,7 +106,7 @@ QUnit.test( "Automatic naming support", function( assert ) {
return 42;
}
// Create a function hello node
var node = new functionNode(null, hello_world);
var node = new functionNode(null, null, hello_world);
assert.notEqual( node, null, "class creation check" );
assert.equal( node.functionName, "hello_world" );
});