code generator finally seems to work properly
This commit is contained in:
27
lib/ast.js
27
lib/ast.js
@@ -9,7 +9,7 @@ function DEFNODE(type, props, methods, base) {
|
|||||||
code += "this." + props[i] + " = props." + props[i] + ";";
|
code += "this." + props[i] + " = props." + props[i] + ";";
|
||||||
}
|
}
|
||||||
if (methods && methods.initialize)
|
if (methods && methods.initialize)
|
||||||
code += "this.initialize();"
|
code += "this.initialize();";
|
||||||
code += " } }";
|
code += " } }";
|
||||||
var ctor = new Function(code)();
|
var ctor = new Function(code)();
|
||||||
if (base) {
|
if (base) {
|
||||||
@@ -36,7 +36,7 @@ var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_be
|
|||||||
var AST_Node = DEFNODE("Node", "start end", {
|
var AST_Node = DEFNODE("Node", "start end", {
|
||||||
clone: function() {
|
clone: function() {
|
||||||
return new this.CTOR(this);
|
return new this.CTOR(this);
|
||||||
},
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
var AST_Directive = DEFNODE("Directive", "value", {
|
var AST_Directive = DEFNODE("Directive", "value", {
|
||||||
@@ -47,16 +47,6 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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.",
|
|
||||||
});
|
|
||||||
|
|
||||||
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.",
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ loops ]----- */
|
/* -----[ loops ]----- */
|
||||||
|
|
||||||
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label statement", {
|
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label statement", {
|
||||||
@@ -78,11 +68,14 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
|||||||
|
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Do = DEFNODE("Do", "condition", {
|
var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_While = DEFNODE("While", "condition", {
|
var AST_Do = DEFNODE("Do", null, {
|
||||||
}, AST_Statement);
|
}, AST_DWLoop);
|
||||||
|
|
||||||
|
var AST_While = DEFNODE("While", null, {
|
||||||
|
}, AST_DWLoop);
|
||||||
|
|
||||||
var AST_For = DEFNODE("For", "init condition step", {
|
var AST_For = DEFNODE("For", "init condition step", {
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
@@ -152,7 +145,7 @@ var AST_Switch = DEFNODE("Switch", "expression", {
|
|||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_SwitchBlock = DEFNODE("SwitchBlock", null, {
|
var AST_SwitchBlock = DEFNODE("SwitchBlock", null, {
|
||||||
}, AST_Bracketed);
|
}, AST_BlockStatement);
|
||||||
|
|
||||||
var AST_SwitchBranch = DEFNODE("SwitchBranch", "body", {
|
var AST_SwitchBranch = DEFNODE("SwitchBranch", "body", {
|
||||||
});
|
});
|
||||||
@@ -177,7 +170,7 @@ var AST_Finally = DEFNODE("Finally", "body", {
|
|||||||
|
|
||||||
/* -----[ VAR/CONST ]----- */
|
/* -----[ VAR/CONST ]----- */
|
||||||
|
|
||||||
var AST_Definitions = DEFNODE("Definitions", "definitions inline", {
|
var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_Var = DEFNODE("Var", null, {
|
var AST_Var = DEFNODE("Var", null, {
|
||||||
|
|||||||
@@ -19,13 +19,15 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
var filename = process.argv[2];
|
var filename = process.argv[2];
|
||||||
console.time("parse");
|
//console.time("parse");
|
||||||
var ast = parse(fs.readFileSync(filename, "utf8"));
|
var ast = parse(fs.readFileSync(filename, "utf8"));
|
||||||
console.timeEnd("parse");
|
//console.timeEnd("parse");
|
||||||
|
|
||||||
|
//console.time("generate");
|
||||||
var stream = OutputStream({ beautify: true });
|
var stream = OutputStream({ beautify: true });
|
||||||
ast.print(stream);
|
ast.print(stream);
|
||||||
console.log(stream.get());
|
//console.timeEnd("generate");
|
||||||
|
sys.puts(stream.get());
|
||||||
|
|
||||||
// console.time("walk");
|
// console.time("walk");
|
||||||
// var w = new TreeWalker(function(node){
|
// var w = new TreeWalker(function(node){
|
||||||
|
|||||||
449
lib/output.js
449
lib/output.js
@@ -8,7 +8,8 @@ function OutputStream(options) {
|
|||||||
ascii_only : false,
|
ascii_only : false,
|
||||||
inline_script : false,
|
inline_script : false,
|
||||||
width : 80,
|
width : 80,
|
||||||
beautify : true
|
beautify : true,
|
||||||
|
scope_style : "negate"
|
||||||
});
|
});
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
@@ -63,11 +64,8 @@ function OutputStream(options) {
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
function make_indent(line) {
|
function make_indent(back) {
|
||||||
if (line == null)
|
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
|
||||||
line = "";
|
|
||||||
line = repeat_string(" ", options.indent_start + indentation) + line;
|
|
||||||
return line;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function last_char() {
|
function last_char() {
|
||||||
@@ -77,11 +75,14 @@ function OutputStream(options) {
|
|||||||
/* -----[ beautification/minification ]----- */
|
/* -----[ beautification/minification ]----- */
|
||||||
|
|
||||||
var might_need_space = false;
|
var might_need_space = false;
|
||||||
|
var might_need_semicolon = false;
|
||||||
|
var last = null;
|
||||||
|
|
||||||
function print(str) {
|
function print(str) {
|
||||||
|
last = str;
|
||||||
str = String(str);
|
str = String(str);
|
||||||
|
var ch = str.charAt(0);
|
||||||
if (might_need_space) {
|
if (might_need_space) {
|
||||||
var ch = str.charAt(0);
|
|
||||||
if ((is_identifier_char(last_char())
|
if ((is_identifier_char(last_char())
|
||||||
&& (is_identifier_char(ch) || ch == "\\"))
|
&& (is_identifier_char(ch) || ch == "\\"))
|
||||||
||
|
||
|
||||||
@@ -91,8 +92,16 @@ function OutputStream(options) {
|
|||||||
current_col++;
|
current_col++;
|
||||||
current_pos++;
|
current_pos++;
|
||||||
}
|
}
|
||||||
|
might_need_space = false;
|
||||||
|
}
|
||||||
|
if (might_need_semicolon) {
|
||||||
|
if (";{}".indexOf(ch) < 0 && !/[;]$/.test(OUTPUT)) {
|
||||||
|
OUTPUT += ";";
|
||||||
|
current_col++;
|
||||||
|
current_pos++;
|
||||||
|
}
|
||||||
|
might_need_semicolon = false;
|
||||||
}
|
}
|
||||||
might_need_space = false;
|
|
||||||
var a = str.split(/\r?\n/), n = a.length;
|
var a = str.split(/\r?\n/), n = a.length;
|
||||||
current_line += n;
|
current_line += n;
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
@@ -110,9 +119,9 @@ function OutputStream(options) {
|
|||||||
might_need_space = true;
|
might_need_space = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var indent = options.beautify ? function() {
|
var indent = options.beautify ? function(half) {
|
||||||
if (options.beautify) {
|
if (options.beautify) {
|
||||||
print(make_indent());
|
print(make_indent(half ? 0.5 : 0));
|
||||||
}
|
}
|
||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
@@ -129,6 +138,12 @@ function OutputStream(options) {
|
|||||||
print("\n");
|
print("\n");
|
||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
|
var semicolon = options.beautify ? function() {
|
||||||
|
print(";");
|
||||||
|
} : function() {
|
||||||
|
might_need_semicolon = true;
|
||||||
|
};
|
||||||
|
|
||||||
function next_indent() {
|
function next_indent() {
|
||||||
return indentation + options.indent_level;
|
return indentation + options.indent_level;
|
||||||
};
|
};
|
||||||
@@ -156,15 +171,12 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function with_square(cont) {
|
function with_square(cont) {
|
||||||
print("[");
|
print("[");
|
||||||
var ret = with_indent(current_col, cont);
|
//var ret = with_indent(current_col, cont);
|
||||||
|
var ret = cont();
|
||||||
print("]");
|
print("]");
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
function semicolon() {
|
|
||||||
print(";");
|
|
||||||
};
|
|
||||||
|
|
||||||
function comma() {
|
function comma() {
|
||||||
print(",");
|
print(",");
|
||||||
space();
|
space();
|
||||||
@@ -184,6 +196,7 @@ function OutputStream(options) {
|
|||||||
space : space,
|
space : space,
|
||||||
comma : comma,
|
comma : comma,
|
||||||
colon : colon,
|
colon : colon,
|
||||||
|
last : function() { return last },
|
||||||
semicolon : semicolon,
|
semicolon : semicolon,
|
||||||
print_name : function(name) { print(make_name(name)) },
|
print_name : function(name) { print(make_name(name)) },
|
||||||
print_string : function(str) { print(encode_string(str)) },
|
print_string : function(str) { print(encode_string(str)) },
|
||||||
@@ -191,57 +204,170 @@ function OutputStream(options) {
|
|||||||
with_block : with_block,
|
with_block : with_block,
|
||||||
with_parens : with_parens,
|
with_parens : with_parens,
|
||||||
with_square : with_square,
|
with_square : with_square,
|
||||||
options : function() { return options },
|
options : function(opt) { return options[opt] },
|
||||||
line : function() { return current_line },
|
line : function() { return current_line },
|
||||||
col : function() { return current_col },
|
col : function() { return current_col },
|
||||||
pos : function() { return current_pos },
|
pos : function() { return current_pos },
|
||||||
push_node : function(node) { stack.push(node) },
|
push_node : function(node) { stack.push(node) },
|
||||||
pop_node : function() { return stack.pop() },
|
pop_node : function() { return stack.pop() },
|
||||||
stack : function() { return stack },
|
stack : function() { return stack },
|
||||||
parent : function() { return stack[stack.length - 2] }
|
parent : function(n) {
|
||||||
|
return stack[stack.length - 2 - (n || 0)];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -----[ code generators ]----- */
|
/* -----[ code generators ]----- */
|
||||||
|
|
||||||
(function(DEFPRINT){
|
(function(){
|
||||||
|
|
||||||
|
/* -----[ utils ]----- */
|
||||||
|
|
||||||
|
function DEFPRINT(nodetype, generator) {
|
||||||
|
nodetype.DEFMETHOD("print", function(stream){
|
||||||
|
var self = this;
|
||||||
|
stream.push_node(self);
|
||||||
|
if (self.needs_parens(stream)) {
|
||||||
|
stream.with_parens(function(){
|
||||||
|
generator(self, stream);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
generator(self, stream);
|
||||||
|
}
|
||||||
|
stream.pop_node();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function PARENS(nodetype, func) {
|
||||||
|
nodetype.DEFMETHOD("needs_parens", func);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -----[ PARENTHESES ]----- */
|
||||||
|
|
||||||
|
PARENS(AST_Node, function(){
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// a function expression needs parens around it when it's provably
|
||||||
|
// the first token to appear in a statement.
|
||||||
|
PARENS(AST_Lambda, function(output){
|
||||||
|
return first_in_statement(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
// same goes for an object literal, because otherwise it would be
|
||||||
|
// interpreted as a block of code.
|
||||||
|
PARENS(AST_Object, function(output){
|
||||||
|
return first_in_statement(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Defun inherits from Lambda, but we don't want parens here.
|
||||||
|
PARENS(AST_Defun, function(){
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
PARENS(AST_Seq, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
return p instanceof AST_Call
|
||||||
|
|| p instanceof AST_Binary
|
||||||
|
|| p instanceof AST_VarDef
|
||||||
|
|| p instanceof AST_Dot
|
||||||
|
|| p instanceof AST_Array
|
||||||
|
|| p instanceof AST_ObjectProperty
|
||||||
|
|| p instanceof AST_Conditional;
|
||||||
|
});
|
||||||
|
|
||||||
|
PARENS(AST_Binary, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_Call && p.expression === this)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_Unary)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_Binary) {
|
||||||
|
var po = p.operator, pp = PRECEDENCE[po];
|
||||||
|
var so = this.operator, sp = PRECEDENCE[so];
|
||||||
|
if (pp > sp
|
||||||
|
|| (pp == sp
|
||||||
|
&& this === p.right
|
||||||
|
&& !(so == po &&
|
||||||
|
(so == "*" ||
|
||||||
|
so == "&&" ||
|
||||||
|
so == "||")))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.operator == "in") {
|
||||||
|
// the “NoIn” stuff :-\
|
||||||
|
// UglifyJS 1.3.3 misses this one.
|
||||||
|
if ((p instanceof AST_For || p instanceof AST_ForIn) && p.init === this)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_VarDef) {
|
||||||
|
var v = output.parent(1), p2 = output.parent(2);
|
||||||
|
if ((p2 instanceof AST_For || p2 instanceof AST_ForIn) && p2.init === v)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PARENS(AST_New, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_Dot && no_constructor_parens(this, output))
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
function assign_and_conditional_paren_rules(output) {
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_Unary)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_Binary && !(p instanceof AST_Assign))
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_Call && p.expression === this)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_Conditional && p.condition === this)
|
||||||
|
return true;
|
||||||
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
PARENS(AST_Conditional, assign_and_conditional_paren_rules);
|
||||||
|
PARENS(AST_Assign, assign_and_conditional_paren_rules);
|
||||||
|
|
||||||
|
/* -----[ PRINTERS ]----- */
|
||||||
|
|
||||||
DEFPRINT(AST_Directive, function(self, output){
|
DEFPRINT(AST_Directive, function(self, output){
|
||||||
output.print_string(self.value);
|
output.print_string(self.value);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Debugger, function(self, output){
|
DEFPRINT(AST_Debugger, function(self, output){
|
||||||
output.print_string("debugger");
|
output.print("debugger");
|
||||||
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Parenthesized, function(self, output){
|
|
||||||
output.with_parens(function(){
|
/* -----[ statements ]----- */
|
||||||
self.expression.print(output);
|
|
||||||
});
|
function display_body(body, is_toplevel, output) {
|
||||||
});
|
body.forEach(function(stmt){
|
||||||
DEFPRINT(AST_Bracketed, function(self, output){
|
if (!(stmt instanceof AST_EmptyStatement)) {
|
||||||
if (self.body.length > 0) output.with_block(function(){
|
|
||||||
self.body.forEach(function(stmt){
|
|
||||||
output.indent();
|
output.indent();
|
||||||
stmt.print(output);
|
stmt.print(output);
|
||||||
output.newline();
|
output.newline();
|
||||||
});
|
if (is_toplevel) output.newline();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
else output.print("{}");
|
};
|
||||||
});
|
|
||||||
/* -----[ statements ]----- */
|
|
||||||
DEFPRINT(AST_Statement, function(self, output){
|
DEFPRINT(AST_Statement, function(self, output){
|
||||||
if (self.body instanceof AST_Node) {
|
if (self.body instanceof AST_Node) {
|
||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
} else {
|
} else {
|
||||||
self.body.forEach(function(stmt){
|
display_body(self.body, self instanceof AST_Toplevel, output);
|
||||||
stmt.print(output);
|
|
||||||
output.newline();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_LabeledStatement, function(self, output){
|
DEFPRINT(AST_LabeledStatement, function(self, output){
|
||||||
output.print(self.label + ":");
|
self.label.print(output);
|
||||||
output.space();
|
output.colon();
|
||||||
self.statement.print(output);
|
self.statement.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_SimpleStatement, function(self, output){
|
DEFPRINT(AST_SimpleStatement, function(self, output){
|
||||||
@@ -249,7 +375,10 @@ function OutputStream(options) {
|
|||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_BlockStatement, function(self, output){
|
DEFPRINT(AST_BlockStatement, function(self, output){
|
||||||
AST_Bracketed.prototype.print.call(self, output);
|
if (self.body.length > 0) output.with_block(function(){
|
||||||
|
display_body(self.body, false, output);
|
||||||
|
});
|
||||||
|
else output.print("{}");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_EmptyStatement, function(self, output){
|
DEFPRINT(AST_EmptyStatement, function(self, output){
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
@@ -260,8 +389,20 @@ function OutputStream(options) {
|
|||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
output.space();
|
output.space();
|
||||||
output.print("while");
|
output.print("while");
|
||||||
self.condition.print(output);
|
output.space();
|
||||||
self.semicolon();
|
output.with_parens(function(){
|
||||||
|
self.condition.print(output);
|
||||||
|
});
|
||||||
|
output.semicolon();
|
||||||
|
});
|
||||||
|
DEFPRINT(AST_While, function(self, output){
|
||||||
|
output.print("while");
|
||||||
|
output.space();
|
||||||
|
output.with_parens(function(){
|
||||||
|
self.condition.print(output);
|
||||||
|
});
|
||||||
|
output.space();
|
||||||
|
self.body.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_For, function(self, output){
|
DEFPRINT(AST_For, function(self, output){
|
||||||
output.print("for");
|
output.print("for");
|
||||||
@@ -269,17 +410,17 @@ function OutputStream(options) {
|
|||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
if (self.init) {
|
if (self.init) {
|
||||||
self.init.print(output);
|
self.init.print(output);
|
||||||
output.semicolon();
|
output.print(";");
|
||||||
output.space();
|
output.space();
|
||||||
} else {
|
} else {
|
||||||
output.semicolon();
|
output.print(";");
|
||||||
}
|
}
|
||||||
if (self.condition) {
|
if (self.condition) {
|
||||||
self.condition.print(output);
|
self.condition.print(output);
|
||||||
output.semicolon();
|
output.print(";");
|
||||||
output.space();
|
output.space();
|
||||||
} else {
|
} else {
|
||||||
output.semicolon();
|
output.print(";");
|
||||||
}
|
}
|
||||||
if (self.step) {
|
if (self.step) {
|
||||||
self.step.print(output);
|
self.step.print(output);
|
||||||
@@ -312,11 +453,15 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ functions ]----- */
|
/* -----[ functions ]----- */
|
||||||
DEFPRINT(AST_Lambda, function(self, output){
|
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
|
||||||
output.print("function");
|
var self = this;
|
||||||
output.space();
|
if (!nokeyword) {
|
||||||
|
output.print("function");
|
||||||
|
}
|
||||||
if (self.name) {
|
if (self.name) {
|
||||||
|
output.space();
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
}
|
}
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
@@ -328,11 +473,17 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Lambda, function(self, output){
|
||||||
|
self._do_print(output);
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ exits ]----- */
|
/* -----[ exits ]----- */
|
||||||
AST_Exit.DEFMETHOD("_do_print", function(output, kind){
|
AST_Exit.DEFMETHOD("_do_print", function(output, kind){
|
||||||
output.print(kind);
|
output.print(kind);
|
||||||
output.space();
|
if (this.value) {
|
||||||
this.value.print(output);
|
output.space();
|
||||||
|
this.value.print(output);
|
||||||
|
}
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Return, function(self, output){
|
DEFPRINT(AST_Return, function(self, output){
|
||||||
@@ -341,6 +492,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Throw, function(self, output){
|
DEFPRINT(AST_Throw, function(self, output){
|
||||||
self._do_print(output, "throw");
|
self._do_print(output, "throw");
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ loop control ]----- */
|
/* -----[ loop control ]----- */
|
||||||
AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
|
AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
|
||||||
output.print(kind);
|
output.print(kind);
|
||||||
@@ -356,6 +508,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Continue, function(self, output){
|
DEFPRINT(AST_Continue, function(self, output){
|
||||||
self._do_print(output, "continue");
|
self._do_print(output, "continue");
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ if ]----- */
|
/* -----[ if ]----- */
|
||||||
DEFPRINT(AST_If, function(self, output){
|
DEFPRINT(AST_If, function(self, output){
|
||||||
output.print("if");
|
output.print("if");
|
||||||
@@ -366,10 +519,13 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self.consequent.print(output);
|
self.consequent.print(output);
|
||||||
if (self.alternative) {
|
if (self.alternative) {
|
||||||
|
output.space();
|
||||||
|
output.print("else");
|
||||||
output.space();
|
output.space();
|
||||||
self.alternative.print(output);
|
self.alternative.print(output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ switch ]----- */
|
/* -----[ switch ]----- */
|
||||||
DEFPRINT(AST_Switch, function(self, output){
|
DEFPRINT(AST_Switch, function(self, output){
|
||||||
output.print("switch");
|
output.print("switch");
|
||||||
@@ -380,16 +536,28 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
});
|
});
|
||||||
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
|
DEFPRINT(AST_SwitchBlock, function(self, output){
|
||||||
this.body.forEach(function(stmt){
|
if (self.body.length > 0) output.with_block(function(){
|
||||||
output.indent();
|
self.body.forEach(function(stmt, i){
|
||||||
stmt.print(output);
|
if (i) output.newline();
|
||||||
output.newline();
|
output.indent(true);
|
||||||
|
stmt.print(output);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
else output.print("{}");
|
||||||
|
});
|
||||||
|
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
|
||||||
|
if (this.body.length > 0) {
|
||||||
|
output.newline();
|
||||||
|
this.body.forEach(function(stmt){
|
||||||
|
output.indent();
|
||||||
|
stmt.print(output);
|
||||||
|
output.newline();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Default, function(self, output){
|
DEFPRINT(AST_Default, function(self, output){
|
||||||
output.print("default:");
|
output.print("default:");
|
||||||
output.newline();
|
|
||||||
self._do_print_body(output);
|
self._do_print_body(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Case, function(self, output){
|
DEFPRINT(AST_Case, function(self, output){
|
||||||
@@ -397,9 +565,9 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
output.print(":");
|
output.print(":");
|
||||||
output.newline();
|
|
||||||
self._do_print_body(output);
|
self._do_print_body(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ exceptions ]----- */
|
/* -----[ exceptions ]----- */
|
||||||
DEFPRINT(AST_Try, function(self, output){
|
DEFPRINT(AST_Try, function(self, output){
|
||||||
output.print("try");
|
output.print("try");
|
||||||
@@ -417,6 +585,10 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Catch, function(self, output){
|
DEFPRINT(AST_Catch, function(self, output){
|
||||||
output.print("catch");
|
output.print("catch");
|
||||||
output.space();
|
output.space();
|
||||||
|
output.with_parens(function(){
|
||||||
|
self.argname.print(output);
|
||||||
|
});
|
||||||
|
output.space();
|
||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Finally, function(self, output){
|
DEFPRINT(AST_Finally, function(self, output){
|
||||||
@@ -424,6 +596,7 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ var/const ]----- */
|
/* -----[ var/const ]----- */
|
||||||
AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
|
AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
|
||||||
output.print(kind);
|
output.print(kind);
|
||||||
@@ -432,7 +605,11 @@ function OutputStream(options) {
|
|||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
def.print(output);
|
def.print(output);
|
||||||
});
|
});
|
||||||
if (!this.inline) output.semicolon();
|
var p = output.parent();
|
||||||
|
var in_for = p instanceof AST_For || p instanceof AST_ForIn;
|
||||||
|
var avoid_semicolon = in_for && p.init === this;
|
||||||
|
if (!avoid_semicolon)
|
||||||
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Var, function(self, output){
|
DEFPRINT(AST_Var, function(self, output){
|
||||||
self._do_print(output, "var");
|
self._do_print(output, "var");
|
||||||
@@ -449,16 +626,24 @@ function OutputStream(options) {
|
|||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ other expressions ]----- */
|
/* -----[ other expressions ]----- */
|
||||||
DEFPRINT(AST_Call, function(self, output){
|
DEFPRINT(AST_Call, function(self, output){
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
|
if (self instanceof AST_New && no_constructor_parens(self, output))
|
||||||
|
return;
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
self.args.forEach(function(arg, i){
|
self.args.forEach(function(expr, i){
|
||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
arg.print(output);
|
expr.print(output);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
function no_constructor_parens(self, output) {
|
||||||
|
return (self.args.length == 0
|
||||||
|
// && !output.options("beautify")
|
||||||
|
);
|
||||||
|
};
|
||||||
DEFPRINT(AST_New, function(self, output){
|
DEFPRINT(AST_New, function(self, output){
|
||||||
output.print("new");
|
output.print("new");
|
||||||
output.space();
|
output.space();
|
||||||
@@ -470,7 +655,12 @@ function OutputStream(options) {
|
|||||||
self.second.print(output);
|
self.second.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Dot, function(self, output){
|
DEFPRINT(AST_Dot, function(self, output){
|
||||||
self.expression.print(output);
|
var expr = self.expression;
|
||||||
|
expr.print(output);
|
||||||
|
if (expr instanceof AST_Number) {
|
||||||
|
if (!/[xa-f.]/i.test(output.last()))
|
||||||
|
output.print(".");
|
||||||
|
}
|
||||||
output.print(".");
|
output.print(".");
|
||||||
output.print_name(self.property);
|
output.print_name(self.property);
|
||||||
});
|
});
|
||||||
@@ -488,43 +678,12 @@ function OutputStream(options) {
|
|||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
output.print(self.operator);
|
output.print(self.operator);
|
||||||
});
|
});
|
||||||
AST_Binary.DEFMETHOD("_do_print", function(output){
|
|
||||||
this.left.print(output);
|
|
||||||
output.space();
|
|
||||||
output.print(this.operator);
|
|
||||||
output.space();
|
|
||||||
this.right.print(output);
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_Binary, function(self, output){
|
DEFPRINT(AST_Binary, function(self, output){
|
||||||
var p = output.parent();
|
self.left.print(output);
|
||||||
if (p instanceof AST_Binary) {
|
output.space();
|
||||||
var po = p.operator, pp = PRECEDENCE[po];
|
output.print(self.operator);
|
||||||
var so = self.operator, sp = PRECEDENCE[so];
|
output.space();
|
||||||
if (pp > sp
|
self.right.print(output);
|
||||||
|| (pp == sp
|
|
||||||
&& self === p.right
|
|
||||||
&& !(so == po &&
|
|
||||||
(so == "*" ||
|
|
||||||
so == "&&" ||
|
|
||||||
so == "||")))) {
|
|
||||||
output.with_parens(function(){
|
|
||||||
self._do_print(output);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self._do_print(output);
|
|
||||||
});
|
|
||||||
// XXX: this is quite similar as for AST_Binary, except for the parens.
|
|
||||||
DEFPRINT(AST_Assign, function(self, output){
|
|
||||||
var p = output.parent();
|
|
||||||
if (p instanceof AST_Binary) {
|
|
||||||
output.with_parens(function(){
|
|
||||||
self._do_print(output);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self._do_print(output);
|
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Conditional, function(self, output){
|
DEFPRINT(AST_Conditional, function(self, output){
|
||||||
self.condition.print(output);
|
self.condition.print(output);
|
||||||
@@ -532,9 +691,11 @@ function OutputStream(options) {
|
|||||||
output.print("?");
|
output.print("?");
|
||||||
output.space();
|
output.space();
|
||||||
self.consequent.print(output);
|
self.consequent.print(output);
|
||||||
|
output.space();
|
||||||
output.colon();
|
output.colon();
|
||||||
self.alternative.print(output);
|
self.alternative.print(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ literals ]----- */
|
/* -----[ literals ]----- */
|
||||||
DEFPRINT(AST_Array, function(self, output){
|
DEFPRINT(AST_Array, function(self, output){
|
||||||
output.with_square(function(){
|
output.with_square(function(){
|
||||||
@@ -547,24 +708,43 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Object, function(self, output){
|
DEFPRINT(AST_Object, function(self, output){
|
||||||
if (self.properties.length > 0) output.with_block(function(){
|
if (self.properties.length > 0) output.with_block(function(){
|
||||||
self.properties.forEach(function(prop, i){
|
self.properties.forEach(function(prop, i){
|
||||||
if (i) output.comma();
|
if (i) {
|
||||||
|
output.comma();
|
||||||
|
output.newline();
|
||||||
|
}
|
||||||
output.indent();
|
output.indent();
|
||||||
prop.print(output);
|
prop.print(output);
|
||||||
output.newline();
|
|
||||||
});
|
});
|
||||||
|
output.newline();
|
||||||
});
|
});
|
||||||
else output.print("{}");
|
else output.print("{}");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
||||||
output.print_name(self.key);
|
var key = self.key;
|
||||||
|
if (output.options("quote_keys")) {
|
||||||
|
output.print_string(key);
|
||||||
|
} else if ((typeof key == "number"
|
||||||
|
|| !output.options("beautify")
|
||||||
|
&& +key + "" == key)
|
||||||
|
&& parseFloat(key) >= 0) {
|
||||||
|
output.print(make_num(key));
|
||||||
|
} else if (!is_identifier(key)) {
|
||||||
|
output.print_string(key);
|
||||||
|
} else {
|
||||||
|
output.print_name(key);
|
||||||
|
}
|
||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectSetter, function(self, output){
|
DEFPRINT(AST_ObjectSetter, function(self, output){
|
||||||
throw "not yet done";
|
output.print("set");
|
||||||
|
output.space();
|
||||||
|
self.func._do_print(output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectGetter, function(self, output){
|
DEFPRINT(AST_ObjectGetter, function(self, output){
|
||||||
throw "not yet done";
|
output.print("get");
|
||||||
|
output.space();
|
||||||
|
self.func._do_print(output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Symbol, function(self, output){
|
DEFPRINT(AST_Symbol, function(self, output){
|
||||||
output.print_name(self.name);
|
output.print_name(self.name);
|
||||||
@@ -581,16 +761,69 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_String, function(self, output){
|
DEFPRINT(AST_String, function(self, output){
|
||||||
output.print_string(self.getValue());
|
output.print_string(self.getValue());
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Number, function(self, output){
|
||||||
|
output.print(make_num(self.getValue()));
|
||||||
|
});
|
||||||
DEFPRINT(AST_RegExp, function(self, output){
|
DEFPRINT(AST_RegExp, function(self, output){
|
||||||
output.print("/");
|
output.print("/");
|
||||||
output.print(self.pattern);
|
output.print(self.pattern);
|
||||||
output.print("/");
|
output.print("/");
|
||||||
if (self.mods) output.print(self.mods);
|
if (self.mods) output.print(self.mods);
|
||||||
});
|
});
|
||||||
})(function DEF(nodetype, generator) {
|
|
||||||
nodetype.DEFMETHOD("print", function(stream){
|
// return true if the node at the top of the stack (that means the
|
||||||
stream.push_node(this);
|
// innermost node in the current output) is lexically the first in
|
||||||
generator(this, stream);
|
// a statement.
|
||||||
stream.pop_node();
|
function first_in_statement(output) {
|
||||||
});
|
var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
|
||||||
});
|
while (i > 0) {
|
||||||
|
if (p instanceof AST_Statement) return true;
|
||||||
|
if ((p instanceof AST_Seq && p.first === node) ||
|
||||||
|
(p instanceof AST_Call && p.expression === node) ||
|
||||||
|
(p instanceof AST_Dot && p.expression === node) ||
|
||||||
|
(p instanceof AST_Sub && p.expression === node) ||
|
||||||
|
(p instanceof AST_Conditional && p.condition === node) ||
|
||||||
|
(p instanceof AST_Binary && p.first === node) ||
|
||||||
|
(p instanceof AST_Assign && p.first === node) ||
|
||||||
|
(p instanceof AST_UnaryPostfix && p.expression === node))
|
||||||
|
{
|
||||||
|
node = p;
|
||||||
|
p = a[--i];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function best_of(a) {
|
||||||
|
var best = a[0], len = best.length;
|
||||||
|
for (var i = 1; i < a.length; ++i) {
|
||||||
|
if (a[i].length < len) {
|
||||||
|
best = a[i];
|
||||||
|
len = best.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
};
|
||||||
|
|
||||||
|
function make_num(num) {
|
||||||
|
var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
|
||||||
|
if (Math.floor(num) === num) {
|
||||||
|
if (num >= 0) {
|
||||||
|
a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
|
||||||
|
"0" + num.toString(8)); // same.
|
||||||
|
} else {
|
||||||
|
a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
|
||||||
|
"-0" + (-num).toString(8)); // same.
|
||||||
|
}
|
||||||
|
if ((m = /^(.*?)(0+)$/.exec(num))) {
|
||||||
|
a.push(m[1] + "e" + m[2].length);
|
||||||
|
}
|
||||||
|
} else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
|
||||||
|
a.push(m[2] + "e-" + (m[1].length + m[2].length),
|
||||||
|
str.substr(str.indexOf(".")));
|
||||||
|
}
|
||||||
|
return best_of(a);
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|||||||
34
lib/parse.js
34
lib/parse.js
@@ -166,6 +166,14 @@ function is_unicode_connector_punctuation(ch) {
|
|||||||
return UNICODE.connector_punctuation.test(ch);
|
return UNICODE.connector_punctuation.test(ch);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function is_identifier(name) {
|
||||||
|
return /^[a-z_$][a-z0-9_$]*$/i.test(name)
|
||||||
|
&& name != "this"
|
||||||
|
&& !HOP(KEYWORDS_ATOM, name)
|
||||||
|
&& !HOP(RESERVED_WORDS, name)
|
||||||
|
&& !HOP(KEYWORDS, name);
|
||||||
|
};
|
||||||
|
|
||||||
function is_identifier_start(ch) {
|
function is_identifier_start(ch) {
|
||||||
return ch == "$" || ch == "_" || is_letter(ch);
|
return ch == "$" || ch == "_" || is_letter(ch);
|
||||||
};
|
};
|
||||||
@@ -695,11 +703,10 @@ function parse($TEXT, exigent_mode) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function parenthesised() {
|
function parenthesised() {
|
||||||
return new AST_Parenthesized({
|
expect("(");
|
||||||
start : expect("("),
|
var exp = expression();
|
||||||
expression : expression(),
|
expect(")");
|
||||||
end : expect(")")
|
return exp;
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function embed_tokens(parser) {
|
function embed_tokens(parser) {
|
||||||
@@ -834,7 +841,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
S.labels.push(label);
|
S.labels.push(label);
|
||||||
var start = S.token, stat = statement();
|
var start = S.token, stat = statement();
|
||||||
S.labels.pop();
|
S.labels.pop();
|
||||||
return new AST_LabeledStatement({ statement: stat });
|
return new AST_LabeledStatement({ statement: stat, label: label });
|
||||||
};
|
};
|
||||||
|
|
||||||
function simple_statement() {
|
function simple_statement() {
|
||||||
@@ -866,9 +873,6 @@ function parse($TEXT, exigent_mode) {
|
|||||||
init = is("keyword", "var")
|
init = is("keyword", "var")
|
||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (init instanceof AST_Var) {
|
|
||||||
init.inline = true;
|
|
||||||
}
|
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Var && init.definitions.length > 1)
|
if (init instanceof AST_Var && init.definitions.length > 1)
|
||||||
croak("Only one variable declaration allowed in for..in loop");
|
croak("Only one variable declaration allowed in for..in loop");
|
||||||
@@ -932,7 +936,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
return new AST_Bracketed({ body: a });
|
return new AST_BlockStatement({ body: a });
|
||||||
})()
|
})()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -997,7 +1001,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
function try_() {
|
function try_() {
|
||||||
var body = new AST_Bracketed({
|
var body = new AST_BlockStatement({
|
||||||
start : S.token,
|
start : S.token,
|
||||||
body : block_(),
|
body : block_(),
|
||||||
end : prev()
|
end : prev()
|
||||||
@@ -1011,7 +1015,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
bcatch = new AST_Catch({
|
bcatch = new AST_Catch({
|
||||||
start : start,
|
start : start,
|
||||||
argname : name,
|
argname : name,
|
||||||
body : new AST_Bracketed({
|
body : new AST_BlockStatement({
|
||||||
start : S.token,
|
start : S.token,
|
||||||
body : block_(),
|
body : block_(),
|
||||||
end : prev()
|
end : prev()
|
||||||
@@ -1024,7 +1028,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
next();
|
next();
|
||||||
bfinally = new AST_Finally({
|
bfinally = new AST_Finally({
|
||||||
start : start,
|
start : start,
|
||||||
body : new AST_Bracketed({
|
body : new AST_BlockStatement({
|
||||||
start : S.token,
|
start : S.token,
|
||||||
body : block_(),
|
body : block_(),
|
||||||
end : prev()
|
end : prev()
|
||||||
@@ -1191,7 +1195,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
var type = start.type;
|
var type = start.type;
|
||||||
var name = as_property_name();
|
var name = as_property_name();
|
||||||
if (type == "name" && !is("punc", ":")) {
|
if (type == "name" && !is("punc", ":")) {
|
||||||
if (name.name == "get") {
|
if (name == "get") {
|
||||||
a.push(new AST_ObjectGetter({
|
a.push(new AST_ObjectGetter({
|
||||||
start : start,
|
start : start,
|
||||||
name : name,
|
name : name,
|
||||||
@@ -1200,7 +1204,7 @@ function parse($TEXT, exigent_mode) {
|
|||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (name.name == "set") {
|
if (name == "set") {
|
||||||
a.push(new AST_ObjectSetter({
|
a.push(new AST_ObjectSetter({
|
||||||
start : start,
|
start : start,
|
||||||
name : name,
|
name : name,
|
||||||
|
|||||||
Reference in New Issue
Block a user