Skip to content

Commit

Permalink
Cleaning up technical debt in GLSL->GLSL compiler.
Browse files Browse the repository at this point in the history
This commit is an attempt to clean up the horrible technical debt that
has accumulated in the print_program method in the glsl compiler.

And by that, I mean, I rewrote the function from scratch.

This isn't a perfect replacement, and there are currently some
regressions which are evident by running through some of the demos, but
this is a much clearer approach, and I think will make further
development on the compiler much more pleasant.

This relates to issues #260 and #261.
  • Loading branch information
Aeva Palecek committed Mar 19, 2017
1 parent 441e756 commit 9a418f6
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 238 deletions.
239 changes: 1 addition & 238 deletions src/gl_ast/ast.block.js
Expand Up @@ -23,7 +23,7 @@ please.gl.ast.Block = function (stream) {
// it will include the entire function definition.
please.gl.ast.Block.prototype.print = function () {
if (this.type === "global") {
return this.__print_program();
return please.gl.ast.build_program(this);
}

var flat = please.gl.ast.flatten(this.data);
Expand All @@ -43,243 +43,6 @@ please.gl.ast.Block.prototype.print = function () {
};


//
please.gl.ast.Block.prototype.__print_program = function (is_include) {
// reset 'rewrites' and 'enums' dictionaries
this.rewrite = {};
this.enums = {};

var out = "";
var globals = {};
var methods = [];
var hoists = [];
var extensions = [];
var structs_by_name = {};
var structs = [];

var globals_printed = is_include;

var find_hoists = function (methods, hoists) {
var found = [];
ITER(m, methods) {
var method = methods[m];
if (method.name !== "main") {
found.push(method.generate_hoist());
}
}
return please.gl.__reduce_hoists(hoists.concat(found));
}

var append_global = function(global) {
if (globals[global.name] === undefined) {
globals[global.name] = global;
}
else {
var composite = please.gl.__check_for_contradicting_globals(
globals[global.name], global);
globals[global.name] = composite;
}
};

if (!is_include && this.inclusions.length > 0) {
// First, combine all of the globals and hoist them to the top
// of the generated file.
var ext_ast = {};
var imports = this.all_includes();

var append_struct = function(struct) {
var previous = structs_by_name[struct.name];
if (previous) {
please.gl.__cmp_structs(previous, struct);
}
else {
structs_by_name[struct.name] = struct;
structs.push(struct);
}
};

ITER(i, imports) {
var other = ext_ast[imports[i]] = please.access(imports[i]).__ast;
other.globals.map(append_global);
other.structs.map(append_struct);
ITER(m, other.methods) {
methods.push(other.methods[m]);
}
ITER(h, other.hoists) {
hoists.push(other.hoists[h]);
}
ITER(e, other.extensions) {
extensions.push(other.extensions[e]);
}
}
this.globals.map(append_global);
this.structs.map(append_struct);

methods = methods.concat(this.methods);
please.gl.__validate_functions(methods);
hoists = hoists.concat(this.hoists);
extensions = extensions.concat(this.extensions);

// write the extension macros first
ITER(e, extensions) {
out += extensions[e].print();
}

// Append any struct definitions to the top
ITER(s, structs) {
out += structs[s].print();
}

// Append the collection of globals to the output buffer.
ITER_PROPS(name, globals) {
out += globals[name].print();
}
globals_printed = true;

// Generate function prototypes for all methods, validate the
// resulting concatination, and print the to the output buffer.
hoists = find_hoists(methods, hoists);
out += "\n// Geneerated and hoisted function prototypes follow:\n"
ITER(h, hoists) {
if (hoists[h].name !== "main") {
out += hoists[h].print();
}
}

// Pass globals to the curve macro and append the result.
var curve_functions = please.gl.macros.curve(globals);
if (curve_functions.length > 0) {
out += this.banner("CURVE MACRO", true);
out += curve_functions;
out += this.banner("CURVE MACRO", false);
}

// Now, append the contents of each included file sans globals.
ITER(i, imports) {
var name = imports[i];
out += this.include_banner(name, true);
out += ext_ast[name].__print_program(true);
out += this.include_banner(name, false);
}
}
else {
methods = methods.concat(this.methods);
please.gl.__validate_functions(methods);
}

if (!is_include && this.inclusions.length==0) {
// collect available globals
this.globals.map(append_global);

// print out structs
ITER(s, this.structs) {
out += this.structs[s].print();
}
// if applicable, print out hoists
hoists = find_hoists(methods, hoists);
if (hoists.length > 0) {
out += "\n// Generated and hoisted function prototypes follow:\n"
ITER(h, hoists) {
out += hoists[h].print();
}
}
}

if (!is_include && methods.length > 0) {
// find and print virtual globals
var virtuals = [];
ITER(m, methods) {
virtuals = virtuals.concat(methods[m].dynamic_globals);
}
ITER(v, virtuals) {
var global = virtuals[v];
if (globals[global.name]) {
// check for possible error, otherwise just continue
please.gl.__check_for_contradicting_globals(
globals[global.name], global);
continue;
}
if (global.rewrite) {
this.rewrite[global.name] = global.rewrite;
}
if (global.enum) {
var check = global.enum;
var name = global.rewrite || global.name;
if (check.constructor == Array) {
this.enums[name] = check;
}
else if (check.constructor == please.gl.ast.Block) {
this.enums[name] = check.enumerate_plugins(methods);
}
}
var found = null;
ITER(s, this.globals) {
if (this.globals[s].name == global.name) {
this.globals[s] = please.gl.__check_for_contradicting_globals(this.globals[s], global);
found = true;
break;
}
}
if (!found) {
out += global.print();
}
};
}

// Now, append the contents of this ast tree sans globals and
// explicit function prototypes.
ITER(i, this.data) {
var token = this.data[i]
var last_token = this.data[i-1] || null;
if (token.constructor == please.gl.ast.Global) {
if (globals_printed) {
out += "/* " + token.print().trim() + " */\n";
}
else {
out += token.print();
}
}
else if (token.constructor == please.gl.ast.FunctionPrototype) {
out += "// " + token.print();
}
else if (token.constructor != please.gl.ast.Block &&
token.constructor != please.gl.ast.Comment &&
token.print) {
// This will catch Invocation tokens. Since the include
// macro actually just leaves them in, they won't show up
// in the program's final output because of this.
continue;
}
else if (token.constructor == please.gl.ast.Block &&
token.macro == "swappable") {
out += please.gl.macros.rewrite_swappable(token, methods);
}
else if (token.constructor == please.gl.ast.Struct) {
out += "/*\n" + token.print() + "\n*/\n";
}
else if (token.type == "function" && token.name == "main") {
// macro hook for adding things to the main() call
out += please.gl.macros.main_prefix_hook(globals, token);
}
else if (token.print) {
out += token.print();
}
else if (token == ";") {
if (last_token && last_token.is_include_macro) {
// *SIIIIIIIIIIIIIGH*
continue;
}
out += token + "\n";
}
else {
out += token;
}
};

return out;
};


//
please.gl.ast.Block.prototype.include_banner = function (uri, begin) {
var header = "INCLUDED FILE: " + uri;
Expand Down

0 comments on commit 9a418f6

Please sign in to comment.