diff options
author | Mihai Bazon <mihai@bazon.net> | 2012-08-16 18:11:04 +0300 |
---|---|---|
committer | Mihai Bazon <mihai@bazon.net> | 2012-08-16 18:11:04 +0300 |
commit | 7f273c3b89352c6fda528dfee17776cffcfe1fb4 (patch) | |
tree | c140b56c5224e1f186a75ab22310b660a4fb7220 /lib/output.js | |
parent | c0ba9e29861ab08ad8a5131705f421e96d634f4b (diff) | |
download | tracifyjs-7f273c3b89352c6fda528dfee17776cffcfe1fb4.tar.gz tracifyjs-7f273c3b89352c6fda528dfee17776cffcfe1fb4.zip |
codegen and dropped the useless walker
Diffstat (limited to 'lib/output.js')
-rw-r--r-- | lib/output.js | 455 |
1 files changed, 422 insertions, 33 deletions
diff --git a/lib/output.js b/lib/output.js index cf17c3e6..52ab39d6 100644 --- a/lib/output.js +++ b/lib/output.js @@ -6,12 +6,16 @@ function OutputStream(options) { space_colon : false, ascii_only : false, inline_script : false, - width : 80 + width : 80, + beautify : true }); + function noop() {}; + var indentation = 0; var current_col = 0; var current_line = 0; + var current_pos = 0; var OUTPUT = ""; function to_ascii(str) { @@ -44,13 +48,6 @@ function OutputStream(options) { else return '"' + str.replace(/\x22/g, '\\"') + '"'; }; - function print(str) { - var a = str.split(/\r?\n/), n = a.length; - current_line += n; - current_col += a[n - 1].length; - OUTPUT += str; - }; - function encode_string(str) { var ret = make_string(str); if (options.inline_script) @@ -72,60 +69,452 @@ function OutputStream(options) { return line; }; - function with_indent(col, cont) { + function last_char() { + return OUTPUT.charAt(OUTPUT.length - 1); + }; + + /* -----[ beautification/minification ]----- */ + + var might_need_space = false; + + function print(str) { + if (might_need_space) { + var ch = str.charAt(0); + if ((is_identifier_char(last_char()) && (is_identifier_char(ch) || ch == "\\")) + || (/[\+\-]$/.test(OUTPUT) && /^[\+\-]/.test(str))) + { + OUTPUT += " "; + current_col++; + current_pos++; + } + } + might_need_space = false; + var a = str.split(/\r?\n/), n = a.length; + current_line += n; + current_col += a[n - 1].length; + current_pos += str.length; + OUTPUT += str; + }; + + var space = options.beautify ? function() { + print(" "); + } : function() { + might_need_space = true; + }; + + var indent = options.beautify ? function() { + if (options.beautify) { + print(make_indent()); + } + } : noop; + + var with_indent = options.beautify ? function(col, cont) { if (col === true) col = next_indent(); var save_indentation = indentation; indentation = col; var ret = cont(); indentation = save_indentation; return ret; - }; + } : function(col, cont) { return cont() }; - function indent() { - print(make_indent()); - }; - - function newline() { + var newline = options.indent ? function() { print("\n"); - }; + } : noop; function next_indent() { return indentation + options.indent_level; }; - function with_block(cont, beautify) { + function with_block(cont) { var ret; print("{"); + newline(); with_indent(next_indent(), function(){ - if (beautify) newline(); ret = cont(); - if (beautify) newline(); }); - if (beautify) indent(); + newline(); + indent(); print("}"); return ret; }; - function with_parens(cont, beautify) { + function with_parens(cont) { print("("); var ret = with_indent(current_col, cont); print(")"); return ret; }; + function with_square(cont) { + print("["); + var ret = with_indent(current_col, cont); + print("]"); + return ret; + }; + + function semicolon() { + print(";"); + }; + + function comma() { + print(","); + space(); + }; + + function colon() { + print(":"); + space(); + }; + return { - get : function() { return OUTPUT }, - indent : indent, - newline : newline, - print : print, - string : function(str) { print(encode_string(str)) }, - with_indent : with_indent, - with_block : with_block, - with_parens : with_parens, - options : function() { return options }, - line : function() { return current_line }, - col : function() { return current_col }, - pos : function() { return OUTPUT.length } + get : function() { return OUTPUT }, + indent : indent, + newline : newline, + print : print, + space : space, + comma : comma, + colon : colon, + print_name : function(name) { print(make_name(name)) }, + print_string : function(str) { print(encode_string(str)) }, + with_indent : with_indent, + with_block : with_block, + with_parens : with_parens, + with_square : with_square, + options : function() { return options }, + line : function() { return current_line }, + col : function() { return current_col }, + pos : function() { return current_pos } }; }; + +/* -----[ code generators ]----- */ + +(function(DEF){ + DEF(AST_Directive, function(self, output){ + output.print_string(self.value); + }); + DEF(AST_Debugger, function(self, output){ + output.print_string("debugger"); + }); + DEF(AST_Parenthesized, function(self, output){ + output.with_parens(function(){ + self.expression.print(output); + }); + }); + DEF(AST_Bracketed, function(self, output){ + output.with_block(function(){ + self.body.forEach(function(stmt){ + output.indent(); + stmt.print(output); + }); + }); + }); + /* -----[ statements ]----- */ + DEF(AST_LabeledStatement, function(self, output){ + output.print(self.label + ":"); + output.space(); + self.statement.print(output); + }); + DEF(AST_SimpleStatement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + DEF(AST_BlockStatement, function(self, output){ + AST_Bracketed.prototype.print.call(self, output); + }); + DEF(AST_EmptyStatement, function(self, output){ + // do nothing here? + // output.semicolon(); + }); + DEF(AST_Do, function(self, output){ + output.print("do"); + output.space(); + self.body.print(output); + output.space(); + output.print("while"); + self.condition.print(output); + self.semicolon(); + }); + DEF(AST_For, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + self.init.print(output); + output.semicolon(); + self.condition.print(output); + output.semicolon(); + self.step.print(output); + }); + output.space(); + self.body.print(output); + }); + DEF(AST_ForIn, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + if (self.init) { + self.init.print(output); + } else { + self.name.print(output); + } + output.print(" in "); + self.object.print(output); + }); + output.space(); + self.body.print(output); + }); + DEF(AST_With, function(self, output){ + output.print("with"); + output.space(); + output.with_parens(function(){ + self.expression.print(output); + }); + output.space(); + self.body.print(output); + }); + /* -----[ functions ]----- */ + DEF(AST_Lambda, function(self, output){ + output.print("function"); + output.space(); + if (self.name) { + self.name.print(output); + output.space(); + } + output.with_parens(function(){ + self.argnames.forEach(function(arg, i){ + if (i) output.comma(); + arg.print(output); + }); + }); + output.space(); + self.body.print(output); + }); + /* -----[ exits ]----- */ + AST_Exit.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + output.space(); + self.value.print(output); + output.semicolon(); + }); + DEF(AST_Return, function(self, output){ + self._do_print(output, "return"); + }); + DEF(AST_Throw, function(self, output){ + self._do_print(output, "throw"); + }); + /* -----[ loop control ]----- */ + AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (self.label) { + output.space(); + self.label.print(output); + } + output.semicolon(); + }); + DEF(AST_Break, function(self, output){ + self._do_print(output, "break"); + }); + DEF(AST_Continue, function(self, output){ + self._do_print(output, "continue"); + }); + /* -----[ if ]----- */ + DEF(AST_If, function(self, output){ + output.print("if"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); + }); + output.space(); + self.consequent.print(output); + if (self.alternative) { + output.space(); + self.alternative.print(output); + } + }); + /* -----[ switch ]----- */ + DEF(AST_Switch, function(self, output){ + output.print("switch"); + output.space(); + output.with_parens(function(){ + self.expression.print(output); + }); + output.space(); + self.body.print(output); + }); + AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){ + self.body.forEach(function(stmt){ + output.indent(); + stmt.print(output); + output.newline(); + }); + }); + DEF(AST_Default, function(self, output){ + output.print("default:"); + output.newline(); + self._do_print_body(output); + }); + DEF(AST_Case, function(self, output){ + output.print("case"); + output.space(); + self.expression.print(output); + output.print(":"); + output.newline(); + self._do_print_body(output); + }); + /* -----[ exceptions ]----- */ + DEF(AST_Try, function(self, output){ + output.print("try"); + output.space(); + self.btry.print(output); + if (self.bcatch) { + output.space(); + self.bcatch.print(output); + } + if (self.bfinally) { + output.space(); + self.bfinally.print(output); + } + }); + DEF(AST_Catch, function(self, output){ + output.print("catch"); + output.space(); + self.body.print(output); + }); + DEF(AST_Finally, function(self, output){ + output.print("finally"); + output.space(); + self.body.print(output); + }); + /* -----[ var/const ]----- */ + AST_Definitions.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + output.space(); + self.definitions.forEach(function(def, i){ + if (i) output.space(); + def.print(output); + }); + output.semicolon(); + }); + DEF(AST_Var, function(self, output){ + self._do_print(output, "var"); + }); + DEF(AST_Const, function(self, output){ + self._do_print(output, "const"); + }); + DEF(AST_VarDef, function(self, output){ + self.name.print(output); + if (self.value) { + output.space(); + output.print("="); + output.space(); + self.value.print(output); + } + }); + /* -----[ other expressions ]----- */ + DEF(AST_Call, function(self, output){ + self.expression.print(output); + output.with_parens(function(){ + self.args.forEach(function(arg, i){ + if (i) output.comma(); + arg.print(output); + }); + }); + }); + DEF(AST_New, function(self, output){ + output.print("new"); + output.space(); + AST_Call.prototype.print.call(self, output); + }); + DEF(AST_Seq, function(self, output){ + self.first.print(output); + output.comma(); + self.second.print(output); + }); + DEF(AST_Dot, function(self, output){ + self.expression.print(output); + output.print("."); + output.print_name(self.property); + }); + DEF(AST_Sub, function(self, output){ + self.expression.print(output); + output.print("["); + self.property.print(output); + output.print("]"); + }); + DEF(AST_UnaryPrefix, function(self, output){ + output.print(self.operator); + self.expression.print(output); + }); + DEF(AST_UnaryPostfix, function(self, output){ + self.expression.print(output); + output.print(self.operator); + }); + DEF(AST_Binary, function(self, output){ + self.left.print(output); + output.print(self.operator); + self.right.print(output); + }); + DEF(AST_Conditional, function(self, output){ + self.condition.print(output); + output.space(); + output.print("?"); + output.space(); + self.consequent.print(output); + output.colon(); + self.alternative.print(output); + }); + /* -----[ literals ]----- */ + DEF(AST_Array, function(self, output){ + output.with_square(function(){ + self.elements.forEach(function(exp, i){ + if (i) output.comma(); + exp.print(output); + }); + }); + }); + DEF(AST_Object, function(self, output){ + output.with_block(function(){ + self.properties.forEach(function(prop, i){ + if (i) output.comma(); + prop.print(output); + }); + }); + }); + DEF(AST_ObjectKeyVal, function(self, output){ + output.print_name(self.key); + output.colon(); + self.value.print(output); + }); + DEF(AST_ObjectSetter, function(self, output){ + throw "not yet done"; + }); + DEF(AST_ObjectGetter, function(self, output){ + throw "not yet done"; + }); + DEF(AST_Symbol, function(self, output){ + output.print_name(self.name); + }); + DEF(AST_This, function(self, output){ + output.print("this"); + }); + DEF(AST_Label, function(self, output){ + output.print_name(self.name); + }); + DEF(AST_Constant, function(self, output){ + output.print(self.getValue()); + }); + DEF(AST_String, function(self, output){ + output.print_string(self.getValue()); + }); + DEF(AST_RegExp, function(self, output){ + output.print("/"); + output.print(self.pattern); + output.print("/"); + if (self.mods) output.print(self.mods); + }); +})(function DEF(nodetype, generator) { + nodetype.DEFMETHOD("print", function(stream){ + generator(this, stream); + }); +}); |