Merge branch 'master' into harmony-2.8.0
This commit is contained in:
50
lib/ast.js
50
lib/ast.js
@@ -81,7 +81,9 @@ function DEFNODE(type, props, methods, base) {
|
||||
ctor.DEFMETHOD = function(name, method) {
|
||||
this.prototype[name] = method;
|
||||
};
|
||||
exports["AST_" + type] = ctor;
|
||||
if (typeof exports !== "undefined") {
|
||||
exports["AST_" + type] = ctor;
|
||||
}
|
||||
return ctor;
|
||||
};
|
||||
|
||||
@@ -143,12 +145,13 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
||||
}, AST_Statement);
|
||||
|
||||
function walk_body(node, visitor) {
|
||||
if (node.body instanceof AST_Node) {
|
||||
node.body._walk(visitor);
|
||||
var body = node.body;
|
||||
if (body instanceof AST_Node) {
|
||||
body._walk(visitor);
|
||||
}
|
||||
else for (var i = 0, len = body.length; i < len; i++) {
|
||||
body[i]._walk(visitor);
|
||||
}
|
||||
else node.body.forEach(function(stat){
|
||||
stat._walk(visitor);
|
||||
});
|
||||
};
|
||||
|
||||
var AST_Block = DEFNODE("Block", "body", {
|
||||
@@ -474,9 +477,10 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator",
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
if (this.name) this.name._walk(visitor);
|
||||
this.argnames.forEach(function(arg){
|
||||
arg._walk(visitor);
|
||||
});
|
||||
var argnames = this.argnames;
|
||||
for (var i = 0, len = argnames.length; i < len; i++) {
|
||||
argnames[i]._walk(visitor);
|
||||
}
|
||||
walk_body(this, visitor);
|
||||
});
|
||||
}
|
||||
@@ -704,9 +708,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
this.definitions.forEach(function(def){
|
||||
def._walk(visitor);
|
||||
});
|
||||
var definitions = this.definitions;
|
||||
for (var i = 0, len = definitions.length; i < len; i++) {
|
||||
definitions[i]._walk(visitor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, AST_Statement);
|
||||
@@ -806,9 +811,10 @@ var AST_Call = DEFNODE("Call", "expression args", {
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
this.expression._walk(visitor);
|
||||
this.args.forEach(function(arg){
|
||||
arg._walk(visitor);
|
||||
});
|
||||
var args = this.args;
|
||||
for (var i = 0, len = args.length; i < len; i++) {
|
||||
args[i]._walk(visitor);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -979,9 +985,10 @@ var AST_Array = DEFNODE("Array", "elements", {
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
this.elements.forEach(function(el){
|
||||
el._walk(visitor);
|
||||
});
|
||||
var elements = this.elements;
|
||||
for (var i = 0, len = elements.length; i < len; i++) {
|
||||
elements[i]._walk(visitor);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -993,9 +1000,10 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
this.properties.forEach(function(prop){
|
||||
prop._walk(visitor);
|
||||
});
|
||||
var properties = this.properties;
|
||||
for (var i = 0, len = properties.length; i < len; i++) {
|
||||
properties[i]._walk(visitor);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
759
lib/compress.js
759
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -71,7 +71,7 @@ function OutputStream(options) {
|
||||
unescape_regexps : false,
|
||||
inline_script : false,
|
||||
width : 80,
|
||||
max_line_len : 32000,
|
||||
max_line_len : false,
|
||||
beautify : false,
|
||||
source_map : null,
|
||||
bracketize : false,
|
||||
@@ -232,6 +232,7 @@ function OutputStream(options) {
|
||||
|
||||
var might_need_space = false;
|
||||
var might_need_semicolon = false;
|
||||
var might_add_newline = 0;
|
||||
var last = null;
|
||||
|
||||
function last_char() {
|
||||
@@ -244,10 +245,22 @@ function OutputStream(options) {
|
||||
return char;
|
||||
};
|
||||
|
||||
function maybe_newline() {
|
||||
if (options.max_line_len && current_col > options.max_line_len)
|
||||
print("\n");
|
||||
};
|
||||
var ensure_line_len = options.max_line_len ? function() {
|
||||
if (current_col > options.max_line_len) {
|
||||
if (might_add_newline) {
|
||||
var left = OUTPUT.slice(0, might_add_newline);
|
||||
var right = OUTPUT.slice(might_add_newline);
|
||||
OUTPUT = left + "\n" + right;
|
||||
current_line++;
|
||||
current_pos++;
|
||||
current_col = right.length;
|
||||
}
|
||||
if (current_col > options.max_line_len) {
|
||||
AST_Node.warn("Output exceeds {max_line_len} characters", options);
|
||||
}
|
||||
}
|
||||
might_add_newline = 0;
|
||||
} : noop;
|
||||
|
||||
var requireSemicolonChars = makePredicate("( [ + * / - , .");
|
||||
|
||||
@@ -263,6 +276,7 @@ function OutputStream(options) {
|
||||
current_col++;
|
||||
current_pos++;
|
||||
} else {
|
||||
ensure_line_len();
|
||||
OUTPUT += "\n";
|
||||
current_pos++;
|
||||
current_line++;
|
||||
@@ -283,6 +297,7 @@ function OutputStream(options) {
|
||||
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
||||
var target_line = stack[stack.length - 1].start.line;
|
||||
while (current_line < target_line) {
|
||||
ensure_line_len();
|
||||
OUTPUT += "\n";
|
||||
current_pos++;
|
||||
current_line++;
|
||||
@@ -294,8 +309,9 @@ function OutputStream(options) {
|
||||
if (might_need_space) {
|
||||
var prev = last_char();
|
||||
if ((is_identifier_char(prev)
|
||||
&& (is_identifier_char(ch) || ch == "\\"))
|
||||
|| (/^[\+\-\/]$/.test(ch) && ch == prev))
|
||||
&& (is_identifier_char(ch) || ch == "\\"))
|
||||
|| (ch == "/" && ch == prev)
|
||||
|| ((ch == "+" || ch == "-") && ch == last))
|
||||
{
|
||||
OUTPUT += " ";
|
||||
current_col++;
|
||||
@@ -303,16 +319,16 @@ function OutputStream(options) {
|
||||
}
|
||||
might_need_space = false;
|
||||
}
|
||||
OUTPUT += str;
|
||||
current_pos += str.length;
|
||||
var a = str.split(/\r?\n/), n = a.length - 1;
|
||||
current_line += n;
|
||||
if (n == 0) {
|
||||
current_col += a[n].length;
|
||||
} else {
|
||||
current_col += a[0].length;
|
||||
if (n > 0) {
|
||||
ensure_line_len();
|
||||
current_col = a[n].length;
|
||||
}
|
||||
current_pos += str.length;
|
||||
last = str;
|
||||
OUTPUT += str;
|
||||
};
|
||||
|
||||
var star = function(){
|
||||
@@ -342,7 +358,10 @@ function OutputStream(options) {
|
||||
|
||||
var newline = options.beautify ? function() {
|
||||
print("\n");
|
||||
} : maybe_newline;
|
||||
} : options.max_line_len ? function() {
|
||||
ensure_line_len();
|
||||
might_add_newline = OUTPUT.length;
|
||||
} : noop;
|
||||
|
||||
var semicolon = options.beautify ? function() {
|
||||
print(";");
|
||||
@@ -419,6 +438,9 @@ function OutputStream(options) {
|
||||
} : noop;
|
||||
|
||||
function get() {
|
||||
if (might_add_newline) {
|
||||
ensure_line_len();
|
||||
}
|
||||
return OUTPUT;
|
||||
};
|
||||
|
||||
@@ -474,7 +496,6 @@ function OutputStream(options) {
|
||||
pos : function() { return current_pos },
|
||||
push_node : function(node) { stack.push(node) },
|
||||
pop_node : function() { return stack.pop() },
|
||||
stack : function() { return stack },
|
||||
parent : function(n) {
|
||||
return stack[stack.length - 2 - (n || 0)];
|
||||
}
|
||||
@@ -1113,7 +1134,10 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
output.print("else");
|
||||
output.space();
|
||||
force_statement(self.alternative, output);
|
||||
if (self.alternative instanceof AST_If)
|
||||
self.alternative.print(output);
|
||||
else
|
||||
force_statement(self.alternative, output);
|
||||
} else {
|
||||
self._do_print_body(output);
|
||||
}
|
||||
@@ -1669,30 +1693,6 @@ function OutputStream(options) {
|
||||
}
|
||||
};
|
||||
|
||||
// return true if the node at the top of the stack (that means the
|
||||
// innermost node in the current output) is lexically the first in
|
||||
// a statement.
|
||||
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 && p.body === node)
|
||||
return true;
|
||||
if ((p instanceof AST_Seq && p.car === node ) ||
|
||||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
|
||||
(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.left === node ) ||
|
||||
(p instanceof AST_UnaryPostfix && p.expression === node ))
|
||||
{
|
||||
node = p;
|
||||
p = a[--i];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// self should be AST_New. decide if we want to show parens or not.
|
||||
function need_constructor_parens(self, output) {
|
||||
// Always print parentheses with arguments
|
||||
|
||||
107
lib/parse.js
107
lib/parse.js
@@ -239,12 +239,11 @@ function JS_Parse_Error(message, filename, line, col, pos) {
|
||||
this.line = line;
|
||||
this.col = col;
|
||||
this.pos = pos;
|
||||
this.stack = new Error().stack;
|
||||
};
|
||||
|
||||
JS_Parse_Error.prototype.toString = function() {
|
||||
return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
|
||||
};
|
||||
JS_Parse_Error.prototype = Object.create(Error.prototype);
|
||||
JS_Parse_Error.prototype.constructor = JS_Parse_Error;
|
||||
JS_Parse_Error.prototype.name = "SyntaxError";
|
||||
configure_error_stack(JS_Parse_Error);
|
||||
|
||||
function js_error(message, filename, line, col, pos) {
|
||||
throw new JS_Parse_Error(message, filename, line, col, pos);
|
||||
@@ -404,13 +403,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
});
|
||||
if (prefix) num = prefix + num;
|
||||
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
||||
parse_error("SyntaxError: Legacy octal literals are not allowed in strict mode");
|
||||
parse_error("Legacy octal literals are not allowed in strict mode");
|
||||
}
|
||||
var valid = parse_js_number(num);
|
||||
if (!isNaN(valid)) {
|
||||
return token("num", valid);
|
||||
} else {
|
||||
parse_error("SyntaxError: Invalid syntax: " + num);
|
||||
parse_error("Invalid syntax: " + num);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -428,13 +427,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
if (peek() == "{") {
|
||||
next(true);
|
||||
if (peek() === "}")
|
||||
parse_error("SyntaxError: Expecting hex-character between {}");
|
||||
parse_error("Expecting hex-character between {}");
|
||||
while (peek() == "0") next(true); // No significance
|
||||
var result, length = find("}", true) - S.pos;
|
||||
// Avoid 32 bit integer overflow (1 << 32 === 1)
|
||||
// We know first character isn't 0 and thus out of range anyway
|
||||
if (length > 6 || (result = hex_bytes(length)) > 0x10FFFF) {
|
||||
parse_error("SyntaxError: Unicode reference out of bounce");
|
||||
parse_error("Unicode reference out of bounce");
|
||||
}
|
||||
next(true);
|
||||
return from_char_code(result);
|
||||
@@ -464,7 +463,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
// Parse
|
||||
if (ch === "0") return "\0";
|
||||
if (ch.length > 0 && next_token.has_directive("use strict"))
|
||||
parse_error("SyntaxError: Legacy octal escape sequences are not allowed in strict mode");
|
||||
parse_error("Legacy octal escape sequences are not allowed in strict mode");
|
||||
return String.fromCharCode(parseInt(ch, 8));
|
||||
}
|
||||
|
||||
@@ -473,18 +472,18 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
for (; n > 0; --n) {
|
||||
var digit = parseInt(next(true), 16);
|
||||
if (isNaN(digit))
|
||||
parse_error("SyntaxError: Invalid hex-character pattern in string");
|
||||
parse_error("Invalid hex-character pattern in string");
|
||||
num = (num << 4) | digit;
|
||||
}
|
||||
return num;
|
||||
};
|
||||
|
||||
var read_string = with_eof_error("SyntaxError: Unterminated string constant", function(quote_char){
|
||||
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
||||
var quote = next(), ret = "";
|
||||
for (;;) {
|
||||
var ch = next(true, true);
|
||||
if (ch == "\\") ch = read_escaped_char(true);
|
||||
else if (NEWLINE_CHARS(ch)) parse_error("SyntaxError: Unterminated string constant");
|
||||
else if (NEWLINE_CHARS(ch)) parse_error("Unterminated string constant");
|
||||
else if (ch == quote) break;
|
||||
ret += ch;
|
||||
}
|
||||
@@ -493,7 +492,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
return tok;
|
||||
});
|
||||
|
||||
var read_template_characters = with_eof_error("SyntaxError: Unterminated template", function(begin){
|
||||
var read_template_characters = with_eof_error("Unterminated template", function(begin){
|
||||
if (begin) {
|
||||
S.template_braces.push(S.brace_counter);
|
||||
}
|
||||
@@ -543,7 +542,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
return next_token;
|
||||
};
|
||||
|
||||
var skip_multiline_comment = with_eof_error("SyntaxError: Unterminated multiline comment", function(){
|
||||
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
|
||||
var regex_allowed = S.regex_allowed;
|
||||
var i = find("*/", true);
|
||||
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
|
||||
@@ -555,13 +554,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
return next_token;
|
||||
});
|
||||
|
||||
var read_name = with_eof_error("SyntaxError: Unterminated identifier name", function() {
|
||||
var read_name = with_eof_error("Unterminated identifier name", function() {
|
||||
var name = "", ch, escaped = false, hex;
|
||||
var read_escaped_identifier_char = function() {
|
||||
escaped = true;
|
||||
next();
|
||||
if (peek() !== "u") {
|
||||
parse_error("SyntaxError: Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}");
|
||||
parse_error("Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}");
|
||||
}
|
||||
return read_escaped_char();
|
||||
}
|
||||
@@ -570,7 +569,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
if ((name = peek()) === "\\") {
|
||||
name = read_escaped_identifier_char();
|
||||
if (!is_identifier_start(name)) {
|
||||
parse_error("SyntaxError: First identifier char is an invalid identifier char");
|
||||
parse_error("First identifier char is an invalid identifier char");
|
||||
}
|
||||
} else if (is_identifier_start(name)){
|
||||
next();
|
||||
@@ -583,7 +582,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
if ((ch = peek()) === "\\") {
|
||||
ch = read_escaped_identifier_char();
|
||||
if (!is_identifier_char(ch)) {
|
||||
parse_error("SyntaxError: Invalid escaped identifier char");
|
||||
parse_error("Invalid escaped identifier char");
|
||||
}
|
||||
} else {
|
||||
if (!is_identifier_char(ch)) {
|
||||
@@ -594,15 +593,15 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
name += ch;
|
||||
}
|
||||
if (RESERVED_WORDS(name) && escaped) {
|
||||
parse_error("SyntaxError: Escaped characters are not allowed in keywords");
|
||||
parse_error("Escaped characters are not allowed in keywords");
|
||||
}
|
||||
return name;
|
||||
});
|
||||
|
||||
var read_regexp = with_eof_error("SyntaxError: Unterminated regular expression", function(regexp){
|
||||
var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
|
||||
var prev_backslash = false, ch, in_class = false;
|
||||
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
||||
parse_error("SyntaxError: Unexpected line terminator");
|
||||
parse_error("Unexpected line terminator");
|
||||
} else if (prev_backslash) {
|
||||
regexp += "\\" + ch;
|
||||
prev_backslash = false;
|
||||
@@ -623,7 +622,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
try {
|
||||
return token("regexp", new RegExp(regexp, mods));
|
||||
} catch(e) {
|
||||
parse_error("SyntaxError: " + e.message);
|
||||
parse_error(e.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -752,7 +751,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
parse_error("SyntaxError: Unexpected character '" + ch + "'");
|
||||
parse_error("Unexpected character '" + ch + "'");
|
||||
};
|
||||
|
||||
next_token.next = next;
|
||||
@@ -914,14 +913,14 @@ function parse($TEXT, options) {
|
||||
function unexpected(token) {
|
||||
if (token == null)
|
||||
token = S.token;
|
||||
token_error(token, "SyntaxError: Unexpected token: " + token.type + " (" + token.value + ")");
|
||||
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
|
||||
};
|
||||
|
||||
function expect_token(type, val) {
|
||||
if (is(type, val)) {
|
||||
return next();
|
||||
}
|
||||
token_error(S.token, "SyntaxError: Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||
};
|
||||
|
||||
function expect(punc) { return expect_token("punc", punc); };
|
||||
@@ -1058,7 +1057,7 @@ function parse($TEXT, options) {
|
||||
|
||||
case "return":
|
||||
if (S.in_function == 0 && !options.bare_returns)
|
||||
croak("SyntaxError: 'return' outside of function");
|
||||
croak("'return' outside of function");
|
||||
return new AST_Return({
|
||||
value: ( is("punc", ";")
|
||||
? (next(), null)
|
||||
@@ -1075,7 +1074,7 @@ function parse($TEXT, options) {
|
||||
|
||||
case "throw":
|
||||
if (S.token.nlb)
|
||||
croak("SyntaxError: Illegal newline after 'throw'");
|
||||
croak("Illegal newline after 'throw'");
|
||||
return new AST_Throw({
|
||||
value: (tmp = expression(true), semicolon(), tmp)
|
||||
});
|
||||
@@ -1094,7 +1093,7 @@ function parse($TEXT, options) {
|
||||
|
||||
case "with":
|
||||
if (S.input.has_directive("use strict")) {
|
||||
croak("SyntaxError: Strict mode may not include a with statement");
|
||||
croak("Strict mode may not include a with statement");
|
||||
}
|
||||
return new AST_With({
|
||||
expression : parenthesised(),
|
||||
@@ -1115,14 +1114,14 @@ function parse($TEXT, options) {
|
||||
var label = as_symbol(AST_Label);
|
||||
if (label.name === "yield" && is_in_generator()) {
|
||||
// Ecma-262, 12.1.1 Static Semantics: Early Errors
|
||||
token_error(S.prev, "SyntaxError: Yield cannot be used as label inside generators");
|
||||
token_error(S.prev, "Yield cannot be used as label inside generators");
|
||||
}
|
||||
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
|
||||
// ECMA-262, 12.12: An ECMAScript program is considered
|
||||
// syntactically incorrect if it contains a
|
||||
// LabelledStatement that is enclosed by a
|
||||
// LabelledStatement with the same Identifier as label.
|
||||
croak("SyntaxError: Label " + label.name + " defined twice");
|
||||
croak("Label " + label.name + " defined twice");
|
||||
}
|
||||
expect(":");
|
||||
S.labels.push(label);
|
||||
@@ -1135,7 +1134,7 @@ function parse($TEXT, options) {
|
||||
label.references.forEach(function(ref){
|
||||
if (ref instanceof AST_Continue) {
|
||||
ref = ref.label.start;
|
||||
croak("SyntaxError: Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||
ref.line, ref.col, ref.pos);
|
||||
}
|
||||
});
|
||||
@@ -1155,11 +1154,11 @@ function parse($TEXT, options) {
|
||||
if (label != null) {
|
||||
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
|
||||
if (!ldef)
|
||||
croak("SyntaxError: Undefined label " + label.name);
|
||||
croak("Undefined label " + label.name);
|
||||
label.thedef = ldef;
|
||||
}
|
||||
else if (S.in_loop == 0)
|
||||
croak("SyntaxError: " + type.TYPE + " not inside a loop or switch");
|
||||
croak(type.TYPE + " not inside a loop or switch");
|
||||
semicolon();
|
||||
var stat = new type({ label: label });
|
||||
if (ldef) ldef.references.push(stat);
|
||||
@@ -1180,7 +1179,7 @@ function parse($TEXT, options) {
|
||||
if (is_in || is_of) {
|
||||
if ((init instanceof AST_Definitions) &&
|
||||
init.definitions.length > 1)
|
||||
croak("SyntaxError: Only one variable declaration allowed in for..in loop");
|
||||
croak("Only one variable declaration allowed in for..in loop");
|
||||
next();
|
||||
if (is_in) {
|
||||
return for_in(init);
|
||||
@@ -1232,7 +1231,7 @@ function parse($TEXT, options) {
|
||||
|
||||
var arrow_function = function(args) {
|
||||
if (S.token.nlb) {
|
||||
croak("SyntaxError: Unexpected newline before arrow (=>)");
|
||||
croak("Unexpected newline before arrow (=>)");
|
||||
}
|
||||
|
||||
expect_token("arrow", "=>");
|
||||
@@ -1302,7 +1301,7 @@ function parse($TEXT, options) {
|
||||
case "eval":
|
||||
case "yield":
|
||||
if (strict_mode) {
|
||||
token_error(token, "SyntaxError: Unexpected " + token.value + " identifier as parameter inside strict mode");
|
||||
token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1331,7 +1330,7 @@ function parse($TEXT, options) {
|
||||
},
|
||||
check_strict: function() {
|
||||
if (tracker.is_strict() && duplicate !== false) {
|
||||
token_error(duplicate, "SyntaxError: Parameter " + duplicate.value + " was used already");
|
||||
token_error(duplicate, "Parameter " + duplicate.value + " was used already");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1457,7 +1456,7 @@ function parse($TEXT, options) {
|
||||
}));
|
||||
next();
|
||||
} else {
|
||||
croak("SyntaxError: Invalid function parameter");
|
||||
croak("Invalid function parameter");
|
||||
}
|
||||
if (is("operator", "=") && is_expand === false) {
|
||||
used_parameters.mark_default_assignment(S.token);
|
||||
@@ -1568,7 +1567,7 @@ function parse($TEXT, options) {
|
||||
end: prev()
|
||||
});
|
||||
} else {
|
||||
croak("SyntaxError: Invalid function parameter");
|
||||
croak("Invalid function parameter");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1631,7 +1630,7 @@ function parse($TEXT, options) {
|
||||
function _yield_expression() {
|
||||
// Previous token must be keyword yield and not be interpret as an identifier
|
||||
if (!is_in_generator()) {
|
||||
croak("SyntaxError: Unexpected yield expression outside generator function",
|
||||
croak("Unexpected yield expression outside generator function",
|
||||
S.prev.line, S.prev.col, S.prev.pos);
|
||||
}
|
||||
var star = false;
|
||||
@@ -1747,7 +1746,7 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
if (!bcatch && !bfinally)
|
||||
croak("SyntaxError: Missing catch/finally blocks");
|
||||
croak("Missing catch/finally blocks");
|
||||
return new AST_Try({
|
||||
body : body,
|
||||
bcatch : bcatch,
|
||||
@@ -1872,7 +1871,7 @@ function parse($TEXT, options) {
|
||||
break;
|
||||
case "operator":
|
||||
if (!is_identifier_string(tok.value)) {
|
||||
croak("SyntaxError: Invalid getter/setter name: " + tok.value,
|
||||
croak("Invalid getter/setter name: " + tok.value,
|
||||
tok.line, tok.col, tok.pos);
|
||||
}
|
||||
ret = _make_symbol(AST_SymbolRef);
|
||||
@@ -1985,6 +1984,10 @@ function parse($TEXT, options) {
|
||||
});
|
||||
});
|
||||
|
||||
var create_accessor = embed_tokens(function() {
|
||||
return function_(AST_Accessor);
|
||||
});
|
||||
|
||||
var object_or_object_destructuring_ = embed_tokens(function() {
|
||||
var start = S.token, first = true, a = [];
|
||||
expect("{");
|
||||
@@ -2142,7 +2145,7 @@ function parse($TEXT, options) {
|
||||
key : name,
|
||||
quote : name instanceof AST_SymbolMethod ?
|
||||
property_token.quote : undefined,
|
||||
value : function_(AST_Accessor),
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
});
|
||||
}
|
||||
@@ -2156,7 +2159,7 @@ function parse($TEXT, options) {
|
||||
key : name,
|
||||
quote : name instanceof AST_SymbolMethod ?
|
||||
property_token.quote : undefined,
|
||||
value : function_(AST_Accessor),
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
});
|
||||
}
|
||||
@@ -2286,7 +2289,7 @@ function parse($TEXT, options) {
|
||||
}
|
||||
case "name":
|
||||
if (tmp.value === "yield" && S.input.has_directive("use strict") && !is_in_generator()) {
|
||||
token_error(tmp, "SyntaxError: Unexpected yield identifier inside strict mode");
|
||||
token_error(tmp, "Unexpected yield identifier inside strict mode");
|
||||
}
|
||||
case "string":
|
||||
case "num":
|
||||
@@ -2325,11 +2328,11 @@ function parse($TEXT, options) {
|
||||
|
||||
function as_symbol(type, noerror) {
|
||||
if (!is("name")) {
|
||||
if (!noerror) croak("SyntaxError: Name expected");
|
||||
if (!noerror) croak("Name expected");
|
||||
return null;
|
||||
}
|
||||
if (is("name", "yield") && S.input.has_directive("use strict")) {
|
||||
token_error(S.prev, "SyntaxError: Unexpected yield identifier inside strict mode");
|
||||
token_error(S.prev, "Unexpected yield identifier inside strict mode");
|
||||
}
|
||||
var sym = _make_symbol(type);
|
||||
next();
|
||||
@@ -2418,7 +2421,7 @@ function parse($TEXT, options) {
|
||||
|
||||
function make_unary(ctor, op, expr) {
|
||||
if ((op == "++" || op == "--") && !is_assignable(expr))
|
||||
croak("SyntaxError: Invalid use of " + op + " operator");
|
||||
croak("Invalid use of " + op + " operator");
|
||||
return new ctor({ operator: op, expression: expr });
|
||||
};
|
||||
|
||||
@@ -2482,7 +2485,7 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return _yield_expression();
|
||||
} else if (S.input.has_directive("use strict")) {
|
||||
token_error(S.token, "SyntaxError: Unexpected yield identifier inside strict mode")
|
||||
token_error(S.token, "Unexpected yield identifier inside strict mode")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2525,7 +2528,7 @@ function parse($TEXT, options) {
|
||||
// Only allow expansion as last element
|
||||
if (node.elements[i] instanceof AST_Expansion) {
|
||||
if (i + 1 !== node.elements.length) {
|
||||
token_error(node.elements[i].start, "SyntaxError: Spread must the be last element in destructuring array");
|
||||
token_error(node.elements[i].start, "Spread must the be last element in destructuring array");
|
||||
}
|
||||
node.elements[i].expression = walk(node.elements[i].expression);
|
||||
}
|
||||
@@ -2565,7 +2568,7 @@ function parse($TEXT, options) {
|
||||
end : prev()
|
||||
});
|
||||
}
|
||||
croak("SyntaxError: Invalid assignment");
|
||||
croak("Invalid assignment");
|
||||
}
|
||||
return left;
|
||||
};
|
||||
|
||||
@@ -174,6 +174,7 @@ function mangle_properties(ast, options) {
|
||||
// only function declarations after this line
|
||||
|
||||
function can_mangle(name) {
|
||||
if (!is_identifier(name)) return false;
|
||||
if (unmangleable.indexOf(name) >= 0) return false;
|
||||
if (reserved.indexOf(name) >= 0) return false;
|
||||
if (options.only_cache) {
|
||||
|
||||
65
lib/scope.js
65
lib/scope.js
@@ -53,7 +53,6 @@ function SymbolDef(scope, index, orig) {
|
||||
this.mangled_name = null;
|
||||
this.object_destructuring_arg = false;
|
||||
this.undeclared = false;
|
||||
this.constant = false;
|
||||
this.index = index;
|
||||
this.id = SymbolDef.next_id++;
|
||||
};
|
||||
@@ -105,15 +104,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
var scope = self.parent_scope = null;
|
||||
var labels = new Dictionary();
|
||||
var defun = null;
|
||||
var last_var_had_const_pragma = false;
|
||||
var nesting = 0;
|
||||
var in_destructuring = null;
|
||||
var in_export;
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
if (node.is_block_scope()) {
|
||||
var save_scope = scope;
|
||||
scope = new AST_Scope(node);
|
||||
scope.init_scope_vars(nesting);
|
||||
scope.init_scope_vars();
|
||||
scope.parent_scope = save_scope;
|
||||
if (!(node instanceof AST_Scope)) {
|
||||
scope.uses_with = save_scope.uses_with;
|
||||
@@ -131,13 +128,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
node.init_scope_vars(nesting);
|
||||
node.init_scope_vars();
|
||||
var save_scope = node.parent_scope = scope;
|
||||
var save_defun = defun;
|
||||
var save_labels = labels;
|
||||
defun = scope = node;
|
||||
labels = new Dictionary();
|
||||
++nesting; descend(); --nesting;
|
||||
descend();
|
||||
scope = save_scope;
|
||||
defun = save_defun;
|
||||
labels = save_labels;
|
||||
@@ -200,14 +197,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
// inside the class.
|
||||
(node.scope = defun.parent_scope).def_function(node, in_export);
|
||||
}
|
||||
else if (node instanceof AST_Var) {
|
||||
last_var_had_const_pragma = node.has_const_pragma();
|
||||
}
|
||||
else if (node instanceof AST_SymbolVar
|
||||
|| node instanceof AST_SymbolConst
|
||||
|| node instanceof AST_SymbolLet) {
|
||||
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export);
|
||||
def.constant = node instanceof AST_SymbolConst || last_var_had_const_pragma;
|
||||
def.destructuring = in_destructuring;
|
||||
def.init = tw.parent().value;
|
||||
}
|
||||
@@ -232,17 +225,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
var cls = null;
|
||||
var globals = self.globals = new Dictionary();
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
function isModified(node, level) {
|
||||
var parent = tw.parent(level);
|
||||
if (parent instanceof AST_Unary && (parent.operator === "++" || parent.operator === "--")
|
||||
|| parent instanceof AST_Assign && parent.left === node
|
||||
|| parent instanceof AST_Call && parent.expression === node) {
|
||||
return true;
|
||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||
return isModified(parent, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (node instanceof AST_Lambda) {
|
||||
var prev_func = func;
|
||||
func = node;
|
||||
@@ -273,21 +255,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
node.scope.uses_arguments = true;
|
||||
}
|
||||
if (!sym) {
|
||||
var g;
|
||||
if (globals.has(name)) {
|
||||
g = globals.get(name);
|
||||
} else {
|
||||
g = new SymbolDef(self, globals.size(), node);
|
||||
g.undeclared = true;
|
||||
g.global = true;
|
||||
globals.set(name, g);
|
||||
}
|
||||
sym = g;
|
||||
sym = self.def_global(node);
|
||||
}
|
||||
node.thedef = sym;
|
||||
if (isModified(node, 0)) {
|
||||
sym.modified = true;
|
||||
}
|
||||
node.reference(options);
|
||||
return true;
|
||||
}
|
||||
@@ -299,7 +269,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||
AST_Toplevel.DEFMETHOD("def_global", function(node){
|
||||
var globals = this.globals, name = node.name;
|
||||
if (globals.has(name)) {
|
||||
return globals.get(name);
|
||||
} else {
|
||||
var g = new SymbolDef(this, globals.size(), node);
|
||||
g.undeclared = true;
|
||||
g.global = true;
|
||||
globals.set(name, g);
|
||||
return g;
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
@@ -307,7 +290,6 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||
this.parent_scope = null; // the parent scope
|
||||
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
this.cname = -1; // the current index for mangling functions/variables
|
||||
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
||||
});
|
||||
|
||||
AST_Node.DEFMETHOD("is_block_scope", function(){
|
||||
@@ -338,15 +320,14 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
|
||||
var s = this.scope;
|
||||
while (s) {
|
||||
push_uniq(s.enclosed, def);
|
||||
if (s === def.scope) break;
|
||||
if (options.keep_fnames) {
|
||||
s.variables.each(function(d) {
|
||||
s.functions.each(function(d) {
|
||||
push_uniq(def.scope.enclosed, d);
|
||||
});
|
||||
}
|
||||
if (s === def.scope) break;
|
||||
s = s.parent_scope;
|
||||
}
|
||||
this.frame = this.scope.nesting - def.scope.nesting;
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("find_variable", function(name){
|
||||
@@ -455,12 +436,6 @@ AST_Symbol.DEFMETHOD("global", function(){
|
||||
return this.definition().global;
|
||||
});
|
||||
|
||||
AST_Var.DEFMETHOD("has_const_pragma", function() {
|
||||
var comments_before = this.start && this.start.comments_before;
|
||||
var lastComment = comments_before && comments_before[comments_before.length - 1];
|
||||
return lastComment && /@const\b/.test(lastComment.value);
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
||||
return defaults(options, {
|
||||
except : [],
|
||||
|
||||
42
lib/utils.js
42
lib/utils.js
@@ -78,13 +78,28 @@ function repeat_string(str, i) {
|
||||
return d;
|
||||
};
|
||||
|
||||
function configure_error_stack(fn) {
|
||||
Object.defineProperty(fn.prototype, "stack", {
|
||||
get: function() {
|
||||
var err = new Error(this.message);
|
||||
err.name = this.name;
|
||||
try {
|
||||
throw err;
|
||||
} catch(e) {
|
||||
return e.stack;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function DefaultsError(msg, defs) {
|
||||
Error.call(this, msg);
|
||||
this.msg = msg;
|
||||
this.message = msg;
|
||||
this.defs = defs;
|
||||
};
|
||||
DefaultsError.prototype = Object.create(Error.prototype);
|
||||
DefaultsError.prototype.constructor = DefaultsError;
|
||||
DefaultsError.prototype.name = "DefaultsError";
|
||||
configure_error_stack(DefaultsError);
|
||||
|
||||
DefaultsError.croak = function(msg, defs) {
|
||||
throw new DefaultsError(msg, defs);
|
||||
@@ -320,3 +335,26 @@ Dictionary.fromObject = function(obj) {
|
||||
function HOP(obj, prop) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||
}
|
||||
|
||||
// return true if the node at the top of the stack (that means the
|
||||
// innermost node in the current output) is lexically the first in
|
||||
// a statement.
|
||||
function first_in_statement(stack) {
|
||||
var node = stack.parent(-1);
|
||||
for (var i = 0, p; p = stack.parent(i); i++) {
|
||||
if (p instanceof AST_Statement && p.body === node)
|
||||
return true;
|
||||
if ((p instanceof AST_Seq && p.car === node ) ||
|
||||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
|
||||
(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.left === node ) ||
|
||||
(p instanceof AST_UnaryPostfix && p.expression === node ))
|
||||
{
|
||||
node = p;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user