From 7f273c3b89352c6fda528dfee17776cffcfe1fb4 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Thu, 16 Aug 2012 18:11:04 +0300 Subject: [PATCH] codegen and dropped the useless walker --- lib/ast.js | 264 ++--------------------------- lib/node.js | 16 +- lib/output.js | 455 ++++++++++++++++++++++++++++++++++++++++++++++---- lib/parse.js | 13 +- 4 files changed, 450 insertions(+), 298 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index b8b6b072..c5be5f6f 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -23,6 +23,9 @@ function DEFNODE(type, props, methods, base) { if (methods) for (i in methods) if (HOP(methods, i)) { ctor.prototype[i] = methods[i]; } + ctor.DEFMETHOD = function(name, method) { + this.prototype[name] = method; + }; return ctor; }; @@ -34,66 +37,33 @@ var AST_Node = DEFNODE("Node", "start end", { clone: function() { return new this.CTOR(this); }, - // XXX: what was this for? - // renew: function(args) { - // var ctor = this.CTOR, props = ctor.props; - // for (var i in props) if (!HOP(args, i)) args[i] = this[i]; - // return new ctor(args); - // }, - walk: function(w) { - w._visit(this); - } }, null); var AST_Directive = DEFNODE("Directive", "value", { - print: function(output) { - output.string(this.value); - } + }); var AST_Debugger = DEFNODE("Debugger", null, { - print: function(output) { - output.print("debugger"); - } + }); var AST_Parenthesized = DEFNODE("Parenthesized", "expression", { $documentation: "Represents an expression which is always parenthesized. Used for the \ conditions in IF/WHILE/DO and expression in SWITCH/WITH.", - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - }); - } }); var AST_Bracketed = DEFNODE("Bracketed", "body", { $documentation: "Represents a block of statements that are always included in brackets. \ Used for bodies of FUNCTION/TRY/CATCH/THROW/SWITCH.", - walk: function(w) { - w._visit(this, function(){ - this.body.forEach(function(stat){ - stat.walk(w); - }); - }); - } }); /* -----[ loops ]----- */ -var AST_Statement = DEFNODE("Statement", "label body", { - walk: function(w) { - w._visit(this, function(){ - if (this.label) this.label.walk(w); - if (this.body) { - if (this.body instanceof AST_Node) - this.body.walk(w); - else - this.walk_array(w); - } - }); - }, - walk_array: AST_Bracketed.prototype.walk +var AST_LabeledStatement = DEFNODE("LabeledStatement", "label statement", { + +}); + +var AST_Statement = DEFNODE("Statement", "body", { }); var AST_SimpleStatement = DEFNODE("SimpleStatement", null, { @@ -109,64 +79,23 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { }, AST_Statement); var AST_Do = DEFNODE("Do", "condition", { - walk: function(w) { - w._visit(this, function(){ - this.condition.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); var AST_While = DEFNODE("While", "condition", { - walk: function(w) { - w._visit(this, function(){ - this.condition.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); var AST_For = DEFNODE("For", "init condition step", { - walk: function(w) { - w._visit(this, function(){ - if (this.init) this.init.walk(w); - if (this.condition) this.condition.walk(w); - if (this.step) this.step.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); var AST_ForIn = DEFNODE("ForIn", "init name object", { - walk: function(w) { - w._visit(this, function(){ - if (this.init) this.init.walk(w); - this.object.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); var AST_With = DEFNODE("With", "expression", { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); /* -----[ functions ]----- */ var AST_Scope = DEFNODE("Scope", "identifiers", { - walk: function(w) { - w._visit(this, function(){ - if (this.identifiers) this.identifiers.forEach(function(el){ - el.walk(w); - }); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); var AST_Toplevel = DEFNODE("Toplevel", null, { @@ -174,15 +103,6 @@ var AST_Toplevel = DEFNODE("Toplevel", null, { }, AST_Scope); var AST_Lambda = DEFNODE("Lambda", "name argnames", { - walk: function(w) { - w._visit(this, function(){ - if (this.name) this.name.walk(w); - this.argnames.forEach(function(el){ - el.walk(w); - }); - AST_Scope.prototype.walk.call(this, w); - }); - } }, AST_Scope); var AST_Function = DEFNODE("Function", null, { @@ -200,11 +120,6 @@ var AST_Jump = DEFNODE("Jump", null, { }); var AST_Exit = DEFNODE("Exit", "value", { - walk: function(w) { - w._visit(this, function(){ - if (this.value) this.value.walk(w); - }); - } }, AST_Jump); var AST_Return = DEFNODE("Return", null, { @@ -216,11 +131,6 @@ var AST_Throw = DEFNODE("Throw", null, { }, AST_Exit); var AST_LoopControl = DEFNODE("LoopControl", "label", { - walk: function(w) { - w._visit(this, function(){ - if (this.label) this.label.walk(w); - }); - } }, AST_Jump); var AST_Break = DEFNODE("Break", null, { @@ -234,34 +144,17 @@ var AST_Continue = DEFNODE("Continue", null, { /* -----[ IF ]----- */ var AST_If = DEFNODE("If", "condition consequent alternative", { - walk: function(w) { - w._visit(this, function(){ - this.condition.walk(w); - this.consequent.walk(w); - if (this.alternative) this.alternative.walk(w); - }); - } }); /* -----[ SWITCH ]----- */ var AST_Switch = DEFNODE("Switch", "expression", { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_Statement); var AST_SwitchBlock = DEFNODE("SwitchBlock", null, { - walk : AST_Statement.prototype.walk, - walk_array : AST_Bracketed.prototype.walk }, AST_Bracketed); var AST_SwitchBranch = DEFNODE("SwitchBranch", "body", { - walk : AST_Statement.prototype.walk, - walk_array : AST_Bracketed.prototype.walk }); var AST_Default = DEFNODE("Default", null, { @@ -269,49 +162,22 @@ var AST_Default = DEFNODE("Default", null, { }, AST_SwitchBranch); var AST_Case = DEFNODE("Case", "expression", { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - AST_Statement.prototype.walk.call(this, w); - }); - } }, AST_SwitchBranch); /* -----[ EXCEPTIONS ]----- */ var AST_Try = DEFNODE("Try", "btry bcatch bfinally", { - walk: function(w) { - w._visit(this, function(){ - this.btry.walk(w); - if (this.bcatch) this.bcatch.walk(w); - if (this.bfinally) this.bfinally.walk(w); - }); - } }); var AST_Catch = DEFNODE("Catch", "argname body", { - walk: function(w) { - w._visit(this, function(){ - this.argname.walk(w); - this.body.walk(w); - }); - } }); -var AST_Finally = DEFNODE("Finally", null, { - -}, AST_Bracketed); +var AST_Finally = DEFNODE("Finally", "body", { +}); /* -----[ VAR/CONST ]----- */ var AST_Definitions = DEFNODE("Definitions", "definitions", { - walk: function(w) { - w._visit(this, function(){ - this.definitions.forEach(function(el){ - el.walk(w); - }); - }); - } }); var AST_Var = DEFNODE("Var", null, { @@ -323,25 +189,11 @@ var AST_Const = DEFNODE("Const", null, { }, AST_Definitions); var AST_VarDef = DEFNODE("VarDef", "name value", { - walk: function(w) { - w._visit(this, function(){ - this.name.walk(w); - if (this.value) this.value.walk(w); - }); - } }); /* -----[ OTHER ]----- */ var AST_Call = DEFNODE("Call", "expression args", { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - this.args.forEach(function(el){ - el.walk(w); - }); - }); - } }); var AST_New = DEFNODE("New", null, { @@ -349,12 +201,6 @@ var AST_New = DEFNODE("New", null, { }, AST_Call); var AST_Seq = DEFNODE("Seq", "first second", { - walk: function(w) { - w._visit(this, function(){ - this.first.walk(w); - this.second.walk(w); - }); - } }); var AST_PropAccess = DEFNODE("PropAccess", "expression property", { @@ -362,28 +208,12 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", { }); var AST_Dot = DEFNODE("Dot", null, { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - }); - } }, AST_PropAccess); var AST_Sub = DEFNODE("Sub", null, { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - this.property.walk(w); - }); - } }, AST_PropAccess); var AST_Unary = DEFNODE("Unary", "operator expression", { - walk: function(w) { - w._visit(this, function(){ - this.expression.walk(w); - }); - } }); var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { @@ -395,22 +225,9 @@ var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { }, AST_Unary); var AST_Binary = DEFNODE("Binary", "left operator right", { - walk: function(w) { - w._visit(this, function(){ - this.left.walk(w); - this.right.walk(w); - }); - } }); var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { - walk: function(w) { - w._visit(this, function(){ - this.condition.walk(w); - this.consequent.walk(w); - this.alternative.walk(w); - }); - } }); var AST_Assign = DEFNODE("Assign", null, { @@ -420,49 +237,20 @@ var AST_Assign = DEFNODE("Assign", null, { /* -----[ LITERALS ]----- */ var AST_Array = DEFNODE("Array", "elements", { - walk: function(w) { - w._visit(this, function(){ - this.elements.forEach(function(el){ - el.walk(w); - }); - }); - } }); var AST_Object = DEFNODE("Object", "properties", { - walk: function(w) { - w._visit(this, function(){ - this.properties.forEach(function(prop){ - prop.walk(w); - }); - }); - } }); var AST_ObjectProperty = DEFNODE("ObjectProperty"); var AST_ObjectKeyVal = DEFNODE("ObjectKeyval", "key value", { - walk: function(w) { - w._visit(this, function(){ - this.value.walk(w); - }); - } }, AST_ObjectProperty); var AST_ObjectSetter = DEFNODE("ObjectSetter", "name func", { - walk: function(w) { - w._visit(this, function(){ - this.func.walk(w); - }); - } }, AST_ObjectProperty); var AST_ObjectGetter = DEFNODE("ObjectGetter", "name func", { - walk: function(w) { - w._visit(this, function(){ - this.func.walk(w); - }); - } }, AST_ObjectProperty); var AST_Symbol = DEFNODE("Symbol", "name", { @@ -519,31 +307,3 @@ var AST_False = DEFNODE("False", null, { var AST_True = DEFNODE("True", null, { value: true }, AST_Atom); - -/* -----[ Walker ]----- */ - -function TreeWalker(visitor) { - this.stack = []; - if (visitor) this.visit = visitor; -}; - -TreeWalker.prototype = { - visit: function(node){}, - parent: function(n) { - if (n == null) n = 1; - return this.stack[this.stack.length - n]; - }, - find_parent: function(type) { - for (var a = this.stack, i = a.length; --i >= 0;) - if (a[i] instanceof type) return a[i]; - return null; - }, - _visit: function(node, descend) { - this.visit(node); - if (descend) { - this.stack.push(node); - descend.call(node); - this.stack.pop(); - } - } -}; diff --git a/lib/node.js b/lib/node.js index 571cdd80..9dba3c18 100755 --- a/lib/node.js +++ b/lib/node.js @@ -12,9 +12,9 @@ }; load_global("./utils.js"); - load_global("./output.js"); load_global("./ast.js"); load_global("./parse.js"); + load_global("./output.js"); /// @@ -23,11 +23,13 @@ var ast = parse(fs.readFileSync(filename, "utf8")); console.timeEnd("parse"); - console.time("walk"); - var w = new TreeWalker(function(node){ - console.log(node.TYPE + " [ start: " + node.start.line + ":" + node.start.col + ", end: " + node.end.line + ":" + node.end.col + "]"); - }); - ast.walk(w); - console.timeEnd("walk"); + // console.time("walk"); + // var w = new TreeWalker(function(node){ + // console.log(node.TYPE + " [ start: " + node.start.line + ":" + node.start.col + ", end: " + node.end.line + ":" + node.end.col + "] " + node.name); + // }); + // ast.walk(w); + // console.timeEnd("walk"); + + //console.log(JSON.stringify(ast)); })(); 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); + }); +}); diff --git a/lib/parse.js b/lib/parse.js index 2cd160fa..fdf44ce3 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -833,15 +833,12 @@ function parse($TEXT, exigent_mode) { expect(":"); S.labels.push(label); var start = S.token, stat = statement(); - if (exigent_mode && !(stat instanceof AST_LabeledStatement)) - unexpected(start); S.labels.pop(); - stat.label = label; - return stat; + return new AST_LabeledStatement({ statement: stat }); }; function simple_statement() { - return new AST_Statement({ body: prog1(expression, semicolon) }); + return new AST_SimpleStatement({ body: prog1(expression, semicolon) }); }; function break_cont(type) { @@ -1024,7 +1021,11 @@ function parse($TEXT, exigent_mode) { next(); bfinally = new AST_Finally({ start : start, - body : block_(), + body : new AST_Bracketed({ + start : S.token, + body : block_(), + end : prev() + }), end : prev() }); } -- 2.34.1