UNPKG

@andrewray/glsl-deparser

Version:

through stream that translates glsl-parser AST nodes into working glsl code

481 lines (402 loc) 10.5 kB
module.exports = deparse_string; var WSManager = require("./ws"); var types = { binary: deparse_binary, break: deparse_break, builtin: deparse_builtin, continue: deparse_continue, decl: deparse_decl, decllist: deparse_decllist, discard: deparse_discard, "do-while": deparse_do_while, expr: deparse_expr, forloop: deparse_forloop, function: deparse_function, functionargs: deparse_functionargs, ident: deparse_ident, if: deparse_if, keyword: deparse_keyword, literal: deparse_literal, precision: deparse_precision, preprocessor: deparse_preprocessor, return: deparse_return, stmt: deparse_stmt, stmtlist: deparse_stmtlist, struct: deparse_struct, assign: deparse_assign, unary: deparse_unary, whileloop: deparse_whileloop, operator: deparse_operator, group: deparse_group, suffix: deparse_suffix, call: deparse_call, quantifier: deparse_quantifier, ternary: deparse_ternary }; var needs_semicolon = { decl: true, return: true, break: true, continue: true, discard: true, precision: true, expr: true, "do-while": true, struct: true }; // semi-globals var output = [], ws; function deparse_string(ast, with_whitespace, indent) { with_whitespace = with_whitespace === undefined ? true : with_whitespace; var whitespace = new WSManager(with_whitespace, indent || " "); // reuse the old array. output.length = 0; // reassign the semi-global "ws" ws = whitespace; deparse(ast); return output.join(""); } function deparse(n) { return types[n.type](n); } function deparse_suffix(node) { deparse(node.children[0]); output.push(node.data); } function deparse_binary(node) { var is_bracket = node.data === "["; deparse(node.children[0]); !is_bracket && output.push(ws.optional(" ")); output.push(node.data); !is_bracket && output.push(ws.optional(" ")); deparse(node.children[1]); if (is_bracket) { output.push("]"); } } function deparse_break(node) { output.push("break"); } function deparse_builtin(node) { output.push(node.data); } function deparse_continue(node) { output.push("continue"); } function deparse_decl(node) { // it's five long var len = node.children.length, len_minus_one = len - 1; for (var i = 0; i < len; ++i) { if (node.children[i].type !== "placeholder") { deparse(node.children[i]); if (i !== len_minus_one) { output.push(ws.required(" ")); } } } return; if (node.children.length === 2) { deparse(node.children[0]); output.push(ws.required(" ")); deparse(node.children[1]); return; } if (node.qualified) { deparse(node.children[0]), output.push(ws.required(" ")); } deparse(node.children[1]); output.push(ws.required(" ")); deparse(node.children[2]); } function deparse_decllist(node) { for (var i = 0, len = node.children.length; i < len; ++i) { if (i > 0) { if (node.children[i].type !== "ident") { if (node.children[i].type !== "quantifier") { output.push(ws.optional(" ")); output.push("="); output.push(ws.optional(" ")); } } else { output.push(","); output.push(ws.optional(" ")); } } deparse(node.children[i]); } } function deparse_discard(node) { output.push("discard"); } function deparse_do_while(node) { var is_stmtlist = node.children[0].type === "stmtlist"; output.push("do"); if (is_stmtlist) { output.push(ws.optional(" ")); } else { ws.indent(); output.push(ws.enabled ? ws.optional("\n") : ws.required(" ")); } deparse(node.children[0]); if (is_stmtlist) { output.push(ws.optional(" ")); } else { ws.dedent(); output.push(ws.optional("\n")); } output.push("while("); deparse(node.children[1]); output.push(")"); } function deparse_expr(node) { node.children.length && deparse(node.children[0]); } function deparse_forloop(node) { var is_stmtlist = node.children[3].type === "stmtlist"; output.push("for("); deparse(node.children[0]); output.push(";"); output.push(ws.optional(" ")); deparse(node.children[1]); output.push(";"); output.push(ws.optional(" ")); deparse(node.children[2]); output.push(")"); if (is_stmtlist) { output.push(ws.optional(" ")); } else { ws.indent(); } deparse(node.children[3]); if (!is_stmtlist) { ws.dedent(); } } function deparse_function(node) { deparse(node.children[0]); output.push("("); deparse(node.children[1]); output.push(")"); if (node.children[2]) { output.push(ws.optional(" ")); deparse(node.children[2]); } } function deparse_functionargs(node) { var len = node.children.length, len_minus_one = len - 1; for (var i = 0; i < len; ++i) { deparse(node.children[i]); if (i !== len_minus_one) { output.push(","); output.push(ws.optional(" ")); } } } function deparse_ident(node) { output.push(node.data); } function deparse_if(node) { var needs_indent = true; for (var j = 1; j < 4; ++j) { if (output[output.length - j] === "else") { output.length = output.length - j; output.push("else "); break; } else if (/[^\s]/.test(output[output.length - j])) { break; } } var is_first_stmt = node.children[1].type === "stmt", has_second = node.children[2], is_second_stmt = has_second && node.children[2].children[0].type !== "stmtlist"; output.push("if("); deparse(node.children[0]); output.push(")"); if (is_first_stmt) { needs_indent && ws.indent(); output.push(ws.enabled ? ws.optional("\n") : ws.required(" ")); } else { output.push(ws.optional(" ")); } deparse(node.children[1]); if (is_first_stmt) { needs_indent && ws.dedent(); output.push(ws.optional("\n")); } if (has_second) { var is_if_stmt = node.children[2].children[0].type === "if"; if (output[output.length - 1] === "}") { output.push(ws.optional(" ")); } output.push("else"); if (is_second_stmt) { !is_if_stmt && ws.indent(); output.push(ws.enabled ? ws.optional("\n") : ws.required(" ")); } else { output.push(ws.optional(" ")); } deparse(node.children[2]); if (is_second_stmt) { !is_if_stmt && ws.dedent(); output.push(ws.optional("\n")); } } } function deparse_keyword(node) { output.push(node.token.data); } function deparse_literal(node) { output.push(node.data); } function deparse_precision(node) { var len = node.children.length, len_minus_one = len - 1; output.push("precision"); output.push(ws.required(" ")); for (var i = 0; i < len; ++i) { deparse(node.children[i]); if (i !== len_minus_one) { output.push(ws.required(" ")); } } } function deparse_preprocessor(node) { var level = ws.level; ws.level = 0; if (output[output.length - 1] !== "\n") output.push(ws.required("\n")); output.push(node.token.data); output.push(ws.required("\n")); ws.level = level; } function deparse_return(node) { output.push("return"); if (node.children[0]) { output.push(ws.required(" ")); deparse(node.children[0]); } } function deparse_stmt(node) { if (!node.children.length) return; var has_child = node.children.length > 0, semicolon = has_child ? needs_semicolon[node.children[0].type] : "", needs_newline = true; if (has_child && node.children[0].type === "decl") { if ( node.children[0].children.length > 5 && node.children[0].children[5].type === "function" ) { semicolon = !node.children[0].children[5].children[2]; } } if (has_child && node.children[0].type === "stmtlist") { needs_newline = false; } var last = output[output.length - 1]; if (!last || last.charAt(0) !== "\n") { needs_newline && output.push(ws.optional("\n")); } deparse(node.children[0]); if (semicolon) output.push(";"); } function deparse_stmtlist(node) { var has_parent = !!node.parent; if (has_parent) { output.push("{"); ws.indent(); output.push(ws.optional("\n")); } for (var i = 0, len = node.children.length; i < len; ++i) { deparse(node.children[i]); } if (has_parent) { ws.dedent(); output.push(ws.optional("\n")); output.push("}"); } } function deparse_struct(node) { output.push("struct"); output.push(ws.required(" ")); deparse(node.children[0]); output.push(ws.optional(" ")); output.push("{"); ws.indent(); output.push(ws.optional("\n")); var len = node.children.length, len_minus_one = len - 1; for (var i = 1, len = node.children.length; i < len; ++i) { deparse(node.children[i]); if (node.children[i].type !== "preprocessor") { output.push(";"); } if (i !== len_minus_one) { output.push(ws.optional("\n")); } } ws.dedent(); output.push(ws.optional("\n")); output.push("}"); } function deparse_assign(node) { deparse(node.children[0]); output.push(ws.optional(" ")); output.push(node.token.data); output.push(ws.optional(" ")); deparse(node.children[1]); } function deparse_unary(node) { output.push(node.data); deparse(node.children[0]); } function deparse_whileloop(node) { var is_stmtlist = node.children[1].type === "stmtlist"; output.push("while("); deparse(node.children[0]); output.push(")"); output.push(is_stmtlist ? ws.optional(" ") : ws.required(" ")); deparse(node.children[1]); } function deparse_call(node) { var len = node.children.length, len_minus_one = len - 1; deparse(node.children[0]); output.push("("); for (var i = 1; i < len; ++i) { deparse(node.children[i]); if (i !== len_minus_one) { output.push(","); output.push(ws.optional(" ")); } } output.push(")"); } function deparse_operator(node) { deparse(node.children[0]); output.push(node.data); deparse(node.children[1]); } function deparse_group(node) { output.push("("); deparse(node.children[0]); output.push(")"); } function deparse_quantifier(node) { output.push("["); if (node.children[0]) deparse(node.children[0]); output.push("]"); } function deparse_ternary(node) { deparse(node.children[0]); output.push(ws.optional(" ")); output.push("?"); output.push(ws.optional(" ")); deparse(node.children[1]); output.push(ws.optional(" ")); output.push(":"); output.push(ws.optional(" ")); deparse(node.children[2]); }