diff options
Diffstat (limited to 'build/lib')
-rw-r--r-- | build/lib/parse-js.js | 40 | ||||
-rw-r--r-- | build/lib/process.js | 96 |
2 files changed, 91 insertions, 45 deletions
diff --git a/build/lib/parse-js.js b/build/lib/parse-js.js index 9f90dfeec..8edecb733 100644 --- a/build/lib/parse-js.js +++ b/build/lib/parse-js.js @@ -751,14 +751,17 @@ function parse($TEXT, exigent_mode, embed_tokens) { return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); }; - var statement = embed_tokens ? function() { - var start = S.token; - var ast = $statement.apply(this, arguments); - ast[0] = add_tokens(ast[0], start, prev()); - return ast; - } : $statement; - - function $statement() { + function maybe_embed_tokens(parser) { + if (embed_tokens) return function() { + var start = S.token; + var ast = parser.apply(this, arguments); + ast[0] = add_tokens(ast[0], start, prev()); + return ast; + }; + else return parser; + }; + + var statement = maybe_embed_tokens(function() { if (is("operator", "/")) { S.peeked = null; S.token = S.input(true); // force regexp @@ -852,7 +855,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { unexpected(); } } - }; + }); function labeled_statement(label) { S.labels.push(label); @@ -910,14 +913,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return as("for-in", init, lhs, obj, in_loop(statement)); }; - var function_ = embed_tokens ? function() { - var start = prev(); - var ast = $function_.apply(this, arguments); - ast[0] = add_tokens(ast[0], start, prev()); - return ast; - } : $function_; - - function $function_(in_statement) { + var function_ = maybe_embed_tokens(function(in_statement) { var name = is("name") ? prog1(S.token.value, next) : null; if (in_statement && !name) unexpected(); @@ -945,7 +941,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { S.in_loop = loop; return a; })()); - }; + }); function if_() { var cond = parenthesised(), body = statement(), belse; @@ -1053,7 +1049,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return subscripts(as("new", newexp, args), true); }; - function expr_atom(allow_calls) { + var expr_atom = maybe_embed_tokens(function(allow_calls) { if (is("operator", "new")) { next(); return new_(); @@ -1088,7 +1084,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return subscripts(prog1(atom, next), allow_calls); } unexpected(); - }; + }); function expr_list(closing, allow_trailing_comma, allow_empty) { var first = true, a = []; @@ -1228,7 +1224,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return left; }; - function expression(commas, no_in) { + var expression = maybe_embed_tokens(function(commas, no_in) { if (arguments.length == 0) commas = true; var expr = maybe_assign(no_in); @@ -1237,7 +1233,7 @@ function parse($TEXT, exigent_mode, embed_tokens) { return as("seq", expr, expression(true, no_in)); } return expr; - }; + }); function in_loop(cont) { try { diff --git a/build/lib/process.js b/build/lib/process.js index 09cbc2ad8..3878c8d62 100644 --- a/build/lib/process.js +++ b/build/lib/process.js @@ -75,6 +75,12 @@ function ast_walker(ast) { return a; }) ]; }; + function _block(statements) { + var out = [ this[0] ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; + }; var walkers = { "string": function(str) { return [ this[0], str ]; @@ -88,12 +94,8 @@ function ast_walker(ast) { "toplevel": function(statements) { return [ this[0], MAP(statements, walk) ]; }, - "block": function(statements) { - var out = [ this[0] ]; - if (statements != null) - out.push(MAP(statements, walk)); - return out; - }, + "block": _block, + "splice": _block, "var": _vardefs, "const": _vardefs, "try": function(t, c, f) { @@ -377,7 +379,9 @@ function ast_add_scope(ast) { }; function _lambda(name, args, body) { - return [ this[0], this[0] == "defun" ? define(name) : name, args, with_new_scope(function(){ + var is_defun = this[0] == "defun"; + return [ this[0], is_defun ? define(name) : name, args, with_new_scope(function(){ + if (!is_defun) define(name); MAP(args, define); return MAP(body, walk); })]; @@ -463,9 +467,22 @@ function ast_mangle(ast, options) { return scope.get_mangled(name, newMangle); }; + function get_define(name) { + // we always lookup a defined symbol for the current scope FIRST, so declared + // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value + if (!scope.has(name)) { + if (HOP(options.defines, name)) { + return options.defines[name]; + } + } + return null; + }; + function _lambda(name, args, body) { - if (name) name = get_mangled(name); + var is_defun = this[0] == "defun"; + if (is_defun && name) name = get_mangled(name); body = with_scope(body.scope, function(){ + if (!is_defun && name) name = get_mangled(name); args = MAP(args, function(name){ return get_mangled(name) }); return MAP(body, walk); }); @@ -507,7 +524,7 @@ function ast_mangle(ast, options) { "var": _vardefs, "const": _vardefs, "name": function(name) { - return [ this[0], get_mangled(name) ]; + return get_define(name) || [ this[0], get_mangled(name) ]; }, "try": function(t, c, f) { return [ this[0], @@ -583,11 +600,18 @@ function boolean_expr(expr) { }; function make_conditional(c, t, e) { + var make_real_conditional = function() { if (c[0] == "unary-prefix" && c[1] == "!") { - return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; + return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; } else { - return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ]; + return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ]; } + }; + // shortcut the conditional if the expression has a constant value + return when_constant(c, function(ast, val){ + warn_unreachable(val ? e : t); + return (val ? t : e); + }, make_real_conditional); }; function empty(b) { @@ -676,6 +700,18 @@ var when_constant = (function(){ || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) { expr[1] = expr[1].substr(0, 2); } + else if (no && expr[0] == "binary" + && (expr[1] == "||" || expr[1] == "&&")) { + // the whole expression is not constant but the lval may be... + try { + var lval = evaluate(expr[2]); + expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) || + (expr[1] == "||" && (lval ? lval : expr[3])) || + expr); + } catch(ex2) { + // IGNORE... lval is not constant + } + } return no ? no.call(expr, expr) : null; } else throw ex; @@ -751,9 +787,14 @@ function ast_squeeze(ast, options) { }; function _lambda(name, args, body) { - return [ this[0], name, args, with_scope(body.scope, function(){ - return tighten(MAP(body, walk), "lambda"); - }) ]; + var is_defun = this[0] == "defun"; + body = with_scope(body.scope, function(){ + var ret = tighten(MAP(body, walk), "lambda"); + if (!is_defun && name && !HOP(scope.refs, name)) + name = null; + return ret; + }); + return [ this[0], name, args, body ]; }; // we get here for blocks that have been already transformed. @@ -959,13 +1000,7 @@ function ast_squeeze(ast, options) { return [ branch[0] ? walk(branch[0]) : null, block ]; }) ]; }, - "function": function() { - var ret = _lambda.apply(this, arguments); - if (ret[1] && !HOP(scope.refs, ret[1])) { - ret[1] = null; - } - return ret; - }, + "function": _lambda, "defun": _lambda, "block": function(body) { if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]); @@ -1067,6 +1102,8 @@ function to_ascii(str) { }); }; +var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); + function gen_code(ast, options) { options = defaults(options, { indent_start : 0, @@ -1197,6 +1234,19 @@ function gen_code(ast, options) { return make_block_statements(statements) .join(newline + newline); }, + "splice": function(statements) { + var parent = $stack[$stack.length - 2][0]; + if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { + // we need block brackets in this case + return make_block.apply(this, arguments); + } else { + return MAP(make_block_statements(statements, true), + function(line, i) { + // the first line is already indented + return i > 0 ? indent(line) : line; + }).join(newline); + } + }, "block": make_block, "var": function(defs) { return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; @@ -1437,7 +1487,7 @@ function gen_code(ast, options) { return add_spaces([ out, make_block(body) ]); }; - function make_block_statements(statements) { + function make_block_statements(statements, noindent) { for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { var stat = statements[i]; var code = make(stat); @@ -1455,7 +1505,7 @@ function gen_code(ast, options) { a.push(code); } } - return MAP(a, indent); + return noindent ? a : MAP(a, indent); }; function make_switch_block(body) { |