diff --git a/lib/nodes.js b/lib/nodes.js index cd2a31ce..9e259c84 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -469,16 +469,14 @@ if (this.variable === 'super') { return this.compile_super(args, o); } - // "$@prefix${@variable.compile(o)}($args)" - return this.prefix + this.variable.compile(o) + '(' + args + ')'; + return this.prefix + (this.variable.compile(o)) + "(" + args + ")"; }; // Compile a call against the superclass's implementation of the current function. CallNode.prototype.compile_super = function compile_super(args, o) { - var arg_part, meth, methname; + var meth, methname; methname = o.scope.method.name; - arg_part = args.length ? ', ' + args : ''; - meth = o.scope.method.proto ? o.scope.method.proto + '.__superClass__.' + methname : methname + '.__superClass__.constructor'; - return meth + '.call(this' + arg_part + ')'; + meth = o.scope.method.proto ? (o.scope.method.proto) + ".__superClass__." + methname : methname + ".__superClass__.constructor"; + return meth + ".call(this" + (args.length ? ', ' : '') + args + ")"; }; // Compile a function call being passed variable arguments. CallNode.prototype.compile_splat = function compile_splat(o) { @@ -488,7 +486,7 @@ if (obj.match(/\(/)) { temp = o.scope.free_variable(); obj = temp; - meth = '(' + temp + ' = ' + this.variable.source + ')' + this.variable.last; + meth = "(" + temp + " = " + (this.variable.source) + ")" + (this.variable.last); } args = (function() { _a = []; _b = this.args; @@ -496,13 +494,13 @@ arg = _b[i]; _a.push((function() { code = arg.compile(o); - code = arg instanceof SplatNode ? code : '[' + code + ']'; - return i === 0 ? code : '.concat(' + code + ')'; + code = arg instanceof SplatNode ? code : "[" + code + "]"; + return i === 0 ? code : ".concat(" + code + ")"; }).call(this)); } return _a; }).call(this); - return this.prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')'; + return this.prefix + meth + ".apply(" + obj + ", " + (args.join('')) + ")"; }; return CallNode; }).call(this); @@ -553,7 +551,9 @@ __extends(IndexNode, BaseNode); IndexNode.prototype.type = 'Index'; IndexNode.prototype.compile_node = function compile_node(o) { - return '[' + this.index.compile(o) + ']'; + var idx; + idx = this.index.compile(o); + return "[" + idx + "]"; }; return IndexNode; }).call(this); @@ -568,10 +568,15 @@ __extends(RangeNode, BaseNode); RangeNode.prototype.type = 'Range'; RangeNode.prototype.compile_variables = function compile_variables(o) { + var _a, _b, from, to; this.indent = o.indent; - this.from_var = o.scope.free_variable(); - this.to_var = o.scope.free_variable(); - return this.from_var + ' = ' + this.from.compile(o) + '; ' + this.to_var + ' = ' + this.to.compile(o) + ";\n" + this.idt(); + _a = [o.scope.free_variable(), o.scope.free_variable()]; + this.from_var = _a[0]; + this.to_var = _a[1]; + _b = [this.from.compile(o), this.to.compile(o)]; + from = _b[0]; + to = _b[1]; + return this.from_var + " = " + from + "; " + this.to_var + " = " + to + ";\n" + (this.idt()); }; RangeNode.prototype.compile_node = function compile_node(o) { var compare, equals, idx, incr, intro, step, vars; @@ -580,13 +585,13 @@ } idx = del(o, 'index'); step = del(o, 'step'); - vars = idx + ' = ' + this.from_var; + vars = idx + " = " + this.from_var; step = step ? step.compile(o) : '1'; equals = this.exclusive ? '' : '='; - intro = '(' + this.from_var + ' <= ' + this.to_var + ' ? ' + idx; - compare = intro + ' <' + equals + ' ' + this.to_var + ' : ' + idx + ' >' + equals + ' ' + this.to_var + ')'; - incr = intro + ' += ' + step + ' : ' + idx + ' -= ' + step + ')'; - return vars + '; ' + compare + '; ' + incr; + intro = "(" + this.from_var + " <= " + this.to_var + " ? " + idx; + compare = intro + " <" + equals + " " + this.to_var + " : " + idx + " >" + equals + " " + this.to_var + ")"; + incr = intro + " += " + step + " : " + idx + " -= " + step + ")"; + return vars + "; " + compare + "; " + incr; }; // Expand the range into the equivalent array, if it's not being used as // part of a comprehension, slice, or splice. @@ -619,7 +624,7 @@ from = this.range.from.compile(o); to = this.range.to.compile(o); plus_part = this.range.exclusive ? '' : ' + 1'; - return ".slice(" + from + ', ' + to + plus_part + ')'; + return ".slice(" + from + ", " + to + plus_part + ")"; }; return SliceNode; }).call(this); @@ -668,7 +673,7 @@ }).call(this); props = props.join(''); inner = props ? '\n' + props + '\n' + this.idt() : ''; - return '{' + inner + '}'; + return "{" + inner + "}"; }; return ObjectNode; }).call(this); @@ -737,19 +742,19 @@ _a.push((function() { code = obj.compile(o); if (obj instanceof CommentNode) { - return '\n' + code + '\n' + o.indent; + return "\n" + code + "\n" + (o.indent); } else if (i === this.objects.length - 1) { return code; } else { - return code + ', '; + return code + ", "; } }).call(this)); } return _a; }).call(this); objects = objects.join(''); - ending = objects.indexOf('\n') >= 0 ? "\n" + this.idt() + ']' : ']'; - return '[' + objects + ending; + ending = objects.indexOf('\n') >= 0 ? "\n" + (this.idt()) + "]" : ']'; + return "[" + objects + ending; }; return ArrayNode; }).call(this); @@ -818,21 +823,22 @@ this.value.proto = proto; } } + val = this.value.compile(o); if (this.context === 'object') { - return name + ': ' + this.value.compile(o); + return name + ": " + val; } if (!(this.is_value() && this.variable.has_properties())) { o.scope.find(name); } - val = name + ' = ' + this.value.compile(o); + val = name + " = " + val; if (stmt) { - return this.idt() + val + ';'; + return (this.idt()) + val + ";"; } if (!top || o.returns) { - val = '(' + val + ')'; + val = "(" + val + ")"; } if (o.returns) { - val = this.idt() + 'return ' + val; + val = (this.idt()) + "return " + val; } return val; }; @@ -843,7 +849,7 @@ var _a, _b, _c, access_class, assigns, code, i, idx, obj, val, val_var, value; val_var = o.scope.free_variable(); value = this.value.is_statement() ? ClosureNode.wrap(this.value) : this.value; - assigns = [this.idt() + val_var + ' = ' + value.compile(o) + ';']; + assigns = [(this.idt()) + val_var + " = " + (value.compile(o)) + ";"]; o.top = true; o.as_statement = true; _a = this.variable.base.objects; @@ -868,12 +874,12 @@ } code = assigns.join("\n"); if (o.returns) { - code += '\n' + this.idt() + 'return ' + this.variable.compile(o) + ';'; + code += "\n" + (this.idt()) + "return " + (this.variable.compile(o)) + ";"; } return code; }; AssignNode.prototype.compile_splice = function compile_splice(o) { - var from, l, name, plus, range, to; + var from, l, name, plus, range, to, val; name = this.variable.compile(merge(o, { only_first: true })); @@ -882,7 +888,8 @@ plus = range.exclusive ? '' : ' + 1'; from = range.from.compile(o); to = range.to.compile(o) + ' - ' + from + plus; - return name + '.splice.apply(' + name + ', [' + from + ', ' + to + '].concat(' + this.value.compile(o) + '))'; + val = this.value.compile(o); + return name + ".splice.apply(" + name + ", [" + from + ", " + to + "].concat(" + val + "))"; }; return AssignNode; }).call(this); @@ -925,17 +932,17 @@ param = _e[_f]; (o.scope.parameter(param)); } - code = this.body.expressions.length ? '\n' + this.body.compile_with_declarations(o) + '\n' : ''; + code = this.body.expressions.length ? "\n" + (this.body.compile_with_declarations(o)) + "\n" : ''; name_part = this.name ? ' ' + this.name : ''; - func = 'function' + (this.bound ? '' : name_part) + '(' + params.join(', ') + ') {' + code + this.idt(this.bound ? 1 : 0) + '}'; + func = "function" + (this.bound ? '' : name_part) + "(" + (params.join(', ')) + ") {" + code + (this.idt(this.bound ? 1 : 0)) + "}"; if (top && !this.bound) { - func = '(' + func + ')'; + func = "(" + func + ")"; } if (!(this.bound)) { return func; } - inner = '(function' + name_part + '() {\n' + this.idt(2) + 'return __func.apply(__this, arguments);\n' + this.idt(1) + '});'; - return '(function(__this) {\n' + this.idt(1) + 'var __func = ' + func + ';\n' + this.idt(1) + 'return ' + inner + '\n' + this.idt() + '})(this)'; + inner = "(function" + name_part + "() {\n" + (this.idt(2)) + "return __func.apply(__this, arguments);\n" + (this.idt(1)) + "});"; + return "(function(__this) {\n" + (this.idt(1)) + "var __func = " + func + ";\n" + (this.idt(1)) + "return " + inner + "\n" + (this.idt()) + "})(this)"; }; CodeNode.prototype.top_sensitive = function top_sensitive() { return true; @@ -954,9 +961,9 @@ return _a; }; CodeNode.prototype.toString = function toString(idt) { - var _a, _b, _c, _d, child; + var _a, _b, _c, _d, child, children; idt = idt || ''; - return '\n' + idt + this.type + (function() { + children = (function() { _a = []; _b = this.real_children(); for (_c = 0, _d = _b.length; _c < _d; _c++) { child = _b[_c]; @@ -964,6 +971,7 @@ } return _a; }).call(this).join(''); + return "\n" + idt + children; }; return CodeNode; }).call(this); @@ -987,10 +995,10 @@ var name; name = this.name.compile(o); o.scope.find(name); - return name + ' = Array.prototype.slice.call(arguments, ' + this.index + ')'; + return name + " = Array.prototype.slice.call(arguments, " + this.index + ")"; }; SplatNode.prototype.compile_value = function compile_value(o, name, index) { - return "Array.prototype.slice.call(" + name + ', ' + index + ')'; + return "Array.prototype.slice.call(" + name + ", " + index + ")"; }; return SplatNode; }).call(this); @@ -1021,20 +1029,20 @@ set = ''; if (!top) { rvar = o.scope.free_variable(); - set = this.idt() + rvar + ' = [];\n'; + set = (this.idt()) + rvar + " = [];\n"; if (this.body) { this.body = PushNode.wrap(rvar, this.body); } } - post = returns ? '\n' + this.idt() + 'return ' + rvar + ';' : ''; - pre = set + this.idt() + 'while (' + cond + ')'; + post = returns ? "\n" + (this.idt()) + "return " + rvar + ";" : ''; + pre = set + (this.idt()) + "while (" + cond + ")"; if (!this.body) { - return pre + ' null;' + post; + return pre + " null;" + post; } if (this.filter) { this.body = Expressions.wrap([new IfNode(this.filter, this.body)]); } - return pre + ' {\n' + this.body.compile(o) + '\n' + this.idt() + '}' + post; + return pre + " {\n" + (this.body.compile(o)) + "\n" + (this.idt()) + "}" + post; }; return WhileNode; }).call(this); @@ -1083,19 +1091,23 @@ if (this.operator === '?') { return this.compile_existence(o); } - return this.first.compile(o) + ' ' + this.operator + ' ' + this.second.compile(o); + return [this.first.compile(o), this.operator, this.second.compile(o)].join(' '); }; // Mimic Python's chained comparisons. See: // http://docs.python.org/reference/expressions.html#notin OpNode.prototype.compile_chain = function compile_chain(o) { - var _a, shared; + var _a, _b, first, second, shared; shared = this.first.unwrap().second; if (shared instanceof CallNode) { _a = shared.compile_reference(o); this.first.second = _a[0]; shared = _a[1]; } - return '(' + this.first.compile(o) + ') && (' + shared.compile(o) + ' ' + this.operator + ' ' + this.second.compile(o) + ')'; + _b = [this.first.compile(o), this.second.compile(o), shared.compile(o)]; + first = _b[0]; + second = _b[1]; + shared = _b[2]; + return "(" + first + ") && (" + shared + " " + this.operator + " " + second + ")"; }; OpNode.prototype.compile_assignment = function compile_assignment(o) { var _a, first, second; @@ -1106,16 +1118,17 @@ o.scope.find(first); } if (this.operator === '?=') { - return first + ' = ' + ExistenceNode.compile_test(o, this.first) + ' ? ' + first + ' : ' + second; + return first + " = " + (ExistenceNode.compile_test(o, this.first)) + " ? " + first + " : " + second; } - return first + ' = ' + first + ' ' + this.operator.substr(0, 2) + ' ' + second; + return first + " = " + first + " " + (this.operator.substr(0, 2)) + " " + second; }; OpNode.prototype.compile_existence = function compile_existence(o) { - var _a, first, second; + var _a, first, second, test; _a = [this.first.compile(o), this.second.compile(o)]; first = _a[0]; second = _a[1]; - return ExistenceNode.compile_test(o, this.first) + ' ? ' + first + ' : ' + second; + test = ExistenceNode.compile_test(o, this.first); + return test + " ? " + first + " : " + second; }; OpNode.prototype.compile_unary = function compile_unary(o) { var parts, space; @@ -1139,15 +1152,16 @@ __extends(TryNode, BaseNode); TryNode.prototype.type = 'Try'; TryNode.prototype.compile_node = function compile_node(o) { - var catch_part, error_part, finally_part; + var attempt_part, catch_part, error_part, finally_part; o.indent = this.idt(1); o.top = true; - error_part = this.error ? ' (' + this.error.compile(o) + ') ' : ' '; - catch_part = (this.recovery || '') && ' catch' + error_part + '{\n' + this.recovery.compile(o) + '\n' + this.idt() + '}'; + attempt_part = this.attempt.compile(o); + error_part = this.error ? " (" + (this.error.compile(o)) + ") " : ' '; + catch_part = ((this.recovery || '') && ' catch') + error_part + "{\n" + (this.recovery.compile(o)) + "\n" + (this.idt()) + "}"; finally_part = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o, { returns: null - })) + '\n' + this.idt() + '}'; - return this.idt() + 'try {\n' + this.attempt.compile(o) + '\n' + this.idt() + '}' + catch_part + finally_part; + })) + "\n" + (this.idt()) + "}"; + return (this.idt()) + "try {\n" + attempt_part + "\n" + (this.idt()) + "}" + catch_part + finally_part; }; return TryNode; }).call(this); @@ -1161,7 +1175,7 @@ __extends(ThrowNode, BaseNode); ThrowNode.prototype.type = 'Throw'; ThrowNode.prototype.compile_node = function compile_node(o) { - return this.idt() + 'throw ' + this.expression.compile(o) + ';'; + return (this.idt()) + "throw " + (this.expression.compile(o)) + ";"; }; return ThrowNode; }).call(this); @@ -1180,7 +1194,7 @@ return ExistenceNode; }).call(this); ExistenceNode.compile_test = function compile_test(o, variable) { - var _a, _b, first, second; + var _a, _b, _c, first, second; _a = [variable, variable]; first = _a[0]; second = _a[1]; @@ -1189,7 +1203,10 @@ first = _b[0]; second = _b[1]; } - return '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)'; + _c = [first.compile(o), second.compile(o)]; + first = _c[0]; + second = _c[1]; + return "(typeof " + first + " !== \"undefined\" && " + second + " !== null)"; }; // An extra set of parentheses, specified explicitly in the source. exports.ParentheticalNode = (function() { @@ -1212,7 +1229,7 @@ if (code.substr(l - 1, 1) === ';') { code = code.substr(o, l - 1); } - return '(' + code + ')'; + return "(" + code + ")"; }; return ParentheticalNode; }).call(this); @@ -1264,20 +1281,21 @@ if (range) { index_var = scope.free_variable(); source_part = source.compile_variables(o); - for_part = index_var + ' = 0, ' + source.compile(merge(o, { + for_part = source.compile(merge(o, { index: ivar, step: this.step - })) + ', ' + index_var + '++'; + })); + for_part = index_var + " = 0, " + for_part + ", " + index_var + "++"; } else { index_var = null; - source_part = svar + ' = ' + this.source.compile(o) + ';\n' + this.idt(); + source_part = svar + " = " + (this.source.compile(o)) + ";\n" + (this.idt()); if (name) { - var_part = body_dent + name + ' = ' + svar + '[' + ivar + '];\n'; + var_part = body_dent + name + " = " + svar + "[" + ivar + "];\n"; } if (!this.object) { lvar = scope.free_variable(); - step_part = this.step ? ivar + ' += ' + this.step.compile(o) : ivar + '++'; - for_part = ivar + ' = 0, ' + lvar + ' = ' + svar + '.length; ' + ivar + ' < ' + lvar + '; ' + step_part; + step_part = this.step ? ivar + " += " + (this.step.compile(o)) : ivar + "++"; + for_part = ivar + " = 0, " + lvar + " = " + svar + ".length; " + ivar + " < " + lvar + "; " + step_part; } } set_result = rvar ? this.idt() + rvar + ' = []; ' : this.idt(); @@ -1303,18 +1321,18 @@ } if (this.object) { o.scope.assign('__hasProp', 'Object.prototype.hasOwnProperty', true); - for_part = ivar + ' in ' + svar + ') { if (__hasProp.call(' + svar + ', ' + ivar + ')'; + for_part = ivar + " in " + svar + ") { if (__hasProp.call(" + svar + ", " + ivar + ")"; } if (!(top_level)) { - return_result = '\n' + this.idt() + return_result + ';'; + return_result = "\n" + (this.idt()) + return_result + ";"; } body = body.compile(merge(o, { indent: body_dent, top: true })); - vars = range ? name : name + ', ' + ivar; + vars = range ? name : name + ", " + ivar; close = this.object ? '}}\n' : '}\n'; - return set_result + source_part + 'for (' + for_part + ') {\n' + var_part + body + '\n' + this.idt() + close + this.idt() + return_result; + return set_result + (source_part) + "for (" + for_part + ") {\n" + var_part + body + "\n" + (this.idt()) + close + (this.idt()) + return_result; }; return ForNode; }).call(this); @@ -1430,16 +1448,16 @@ o.top = true; if_dent = child ? '' : this.idt(); com_dent = child ? this.idt() : ''; - prefix = this.comment ? this.comment.compile(cond_o) + '\n' + com_dent : ''; + prefix = this.comment ? (this.comment.compile(cond_o)) + "\n" + com_dent : ''; body = Expressions.wrap([this.body]).compile(o); - if_part = prefix + if_dent + 'if (' + this.compile_condition(cond_o) + ') {\n' + body + '\n' + this.idt() + '}'; + if_part = prefix + (if_dent) + "if (" + (this.compile_condition(cond_o)) + ") {\n" + body + "\n" + (this.idt()) + "}"; if (!(this.else_body)) { return if_part; } else_part = this.is_chain() ? ' else ' + this.else_body.compile(merge(o, { indent: this.idt(), chain_child: true - })) : ' else {\n' + Expressions.wrap([this.else_body]).compile(o) + '\n' + this.idt() + '}'; + })) : " else {\n" + (Expressions.wrap([this.else_body]).compile(o)) + "\n" + (this.idt()) + "}"; return if_part + else_part; }; // Compile the IfNode into a ternary operator. @@ -1447,7 +1465,7 @@ var else_part, if_part; if_part = this.condition.compile(o) + ' ? ' + this.body.compile(o); else_part = this.else_body ? this.else_body.compile(o) : 'null'; - return if_part + ' : ' + else_part; + return if_part + " : " + else_part; }; return IfNode; }).call(this); diff --git a/src/nodes.coffee b/src/nodes.coffee index 4d165c57..b6de32f5 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -336,18 +336,16 @@ exports.CallNode: class CallNode extends BaseNode return @compile_splat(o) if @args[@args.length - 1] instanceof SplatNode args: (arg.compile(o) for arg in @args).join(', ') return @compile_super(args, o) if @variable is 'super' - # "$@prefix${@variable.compile(o)}($args)" - @prefix + @variable.compile(o) + '(' + args + ')' + "$@prefix${@variable.compile(o)}($args)" # Compile a call against the superclass's implementation of the current function. compile_super: (args, o) -> methname: o.scope.method.name - arg_part: if args.length then ', ' + args else '' meth: if o.scope.method.proto - o.scope.method.proto + '.__superClass__.' + methname + "${o.scope.method.proto}.__superClass__.$methname" else - methname + '.__superClass__.constructor' - meth + '.call(this' + arg_part + ')' + "$methname.__superClass__.constructor" + "$meth.call(this${ if args.length then ', ' else '' }$args)" # Compile a function call being passed variable arguments. compile_splat: (o) -> @@ -356,12 +354,12 @@ exports.CallNode: class CallNode extends BaseNode if obj.match(/\(/) temp: o.scope.free_variable() obj: temp - meth: '(' + temp + ' = ' + @variable.source + ')' + @variable.last + meth: "($temp = ${ @variable.source })${ @variable.last }" args: for arg, i in @args code: arg.compile o - code: if arg instanceof SplatNode then code else '[' + code + ']' - if i is 0 then code else '.concat(' + code + ')' - @prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')' + code: if arg instanceof SplatNode then code else "[$code]" + if i is 0 then code else ".concat($code)" + "$@prefix$meth.apply($obj, ${ args.join('') })" # Node to extend an object's prototype with an ancestor object. @@ -414,7 +412,8 @@ exports.IndexNode: class IndexNode extends BaseNode @soak_node: tag is 'soak' compile_node: (o) -> - '[' + @index.compile(o) + ']' + idx: @index.compile o + "[$idx]" # A range literal. Ranges can be used to extract portions (slices) of arrays, @@ -427,22 +426,22 @@ exports.RangeNode: class RangeNode extends BaseNode @exclusive: !!exclusive compile_variables: (o) -> - @indent: o.indent - @from_var: o.scope.free_variable() - @to_var: o.scope.free_variable() - @from_var + ' = ' + @from.compile(o) + '; ' + @to_var + ' = ' + @to.compile(o) + ";\n" + @idt() + @indent: o.indent + [@from_var, @to_var]: [o.scope.free_variable(), o.scope.free_variable()] + [from, to]: [@from.compile(o), @to.compile(o)] + "$@from_var = $from; $@to_var = $to;\n${@idt()}" compile_node: (o) -> return @compile_array(o) unless o.index idx: del o, 'index' step: del o, 'step' - vars: idx + ' = ' + @from_var + vars: "$idx = $@from_var" step: if step then step.compile(o) else '1' equals: if @exclusive then '' else '=' - intro: '(' + @from_var + ' <= ' + @to_var + ' ? ' + idx - compare: intro + ' <' + equals + ' ' + @to_var + ' : ' + idx + ' >' + equals + ' ' + @to_var + ')' - incr: intro + ' += ' + step + ' : ' + idx + ' -= ' + step + ')' - vars + '; ' + compare + '; ' + incr + intro: "($@from_var <= $@to_var ? $idx" + compare: "$intro <$equals $@to_var : $idx >$equals $@to_var)" + incr: "$intro += $step : $idx -= $step)" + "$vars; $compare; $incr" # Expand the range into the equivalent array, if it's not being used as # part of a comprehension, slice, or splice. @@ -468,7 +467,7 @@ exports.SliceNode: class SliceNode extends BaseNode from: @range.from.compile(o) to: @range.to.compile(o) plus_part: if @range.exclusive then '' else ' + 1' - ".slice(" + from + ', ' + to + plus_part + ')' + ".slice($from, $to$plus_part)" # An object literal. @@ -493,7 +492,7 @@ exports.ObjectNode: class ObjectNode extends BaseNode indent + prop.compile(o) + join props: props.join('') inner: if props then '\n' + props + '\n' + @idt() else '' - '{' + inner + '}' + "{$inner}" # A class literal, including optional superclass and constructor. @@ -534,7 +533,7 @@ exports.ClassNode: class ClassNode extends BaseNode props: if props.empty() then '' else props.compile(o) + '\n' extension: if extension then @idt() + extension.compile(o) + ';\n' else '' returns: if ret then '\n' + @idt() + 'return ' + @variable.compile(o) + ';' else '' - construct + extension + props + returns + "$construct$extension$props$returns" statement ClassNode @@ -551,14 +550,14 @@ exports.ArrayNode: class ArrayNode extends BaseNode objects: for obj, i in @objects code: obj.compile(o) if obj instanceof CommentNode - '\n' + code + '\n' + o.indent + "\n$code\n${o.indent}" else if i is @objects.length - 1 code else - code + ', ' + "$code, " objects: objects.join('') - ending: if objects.indexOf('\n') >= 0 then "\n" + @idt() + ']' else ']' - '[' + objects + ending + ending: if objects.indexOf('\n') >= 0 then "\n${@idt()}]" else ']' + "[$objects$ending" # A faux-node that is never created by the grammar, but is used during @@ -618,12 +617,13 @@ exports.AssignNode: class AssignNode extends BaseNode if @value instanceof CodeNode @value.name: last if last.match(IDENTIFIER) @value.proto: proto if proto - return name + ': ' + @value.compile(o) if @context is 'object' - o.scope.find(name) unless @is_value() and @variable.has_properties() - val: name + ' = ' + @value.compile(o) - return @idt() + val + ';' if stmt - val: '(' + val + ')' if not top or o.returns - val: @idt() + 'return ' + val if o.returns + val: @value.compile o + return "$name: $val" if @context is 'object' + o.scope.find name unless @is_value() and @variable.has_properties() + val: "$name = $val" + return "${@idt()}$val;" if stmt + val: "($val)" if not top or o.returns + val: "${@idt()}return $val" if o.returns val # Implementation of recursive pattern matching, when assigning array or @@ -632,7 +632,7 @@ exports.AssignNode: class AssignNode extends BaseNode compile_pattern_match: (o) -> val_var: o.scope.free_variable() value: if @value.is_statement() then ClosureNode.wrap(@value) else @value - assigns: [@idt() + val_var + ' = ' + value.compile(o) + ';'] + assigns: ["${@idt()}$val_var = ${ value.compile(o) };"] o.top: true o.as_statement: true for obj, i in @variable.base.objects @@ -646,7 +646,7 @@ exports.AssignNode: class AssignNode extends BaseNode val: new ValueNode(literal(val_var), [new access_class(idx)]) assigns.push(new AssignNode(obj, val).compile(o)) code: assigns.join("\n") - code += '\n' + @idt() + 'return ' + @variable.compile(o) + ';' if o.returns + code += "\n${@idt()}return ${ @variable.compile(o) };" if o.returns code compile_splice: (o) -> @@ -656,7 +656,8 @@ exports.AssignNode: class AssignNode extends BaseNode plus: if range.exclusive then '' else ' + 1' from: range.from.compile(o) to: range.to.compile(o) + ' - ' + from + plus - name + '.splice.apply(' + name + ', [' + from + ', ' + to + '].concat(' + @value.compile(o) + '))' + val: @value.compile(o) + "$name.splice.apply($name, [$from, $to].concat($val))" # A function definition. The only node that creates a new Scope. @@ -684,13 +685,13 @@ exports.CodeNode: class CodeNode extends BaseNode @body.unshift(splat) params: (param.compile(o) for param in @params) (o.scope.parameter(param)) for param in params - code: if @body.expressions.length then '\n' + @body.compile_with_declarations(o) + '\n' else '' + code: if @body.expressions.length then "\n${ @body.compile_with_declarations(o) }\n" else '' name_part: if @name then ' ' + @name else '' - func: 'function' + (if @bound then '' else name_part) + '(' + params.join(', ') + ') {' + code + @idt(if @bound then 1 else 0) + '}' - func: '(' + func + ')' if top and not @bound + func: "function${ if @bound then '' else name_part }(${ params.join(', ') }) {$code${@idt(if @bound then 1 else 0)}}" + func: "($func)" if top and not @bound return func unless @bound - inner: '(function' + name_part + '() {\n' + @idt(2) + 'return __func.apply(__this, arguments);\n' + @idt(1) + '});' - '(function(__this) {\n' + @idt(1) + 'var __func = ' + func + ';\n' + @idt(1) + 'return ' + inner + '\n' + @idt() + '})(this)' + inner: "(function$name_part() {\n${@idt(2)}return __func.apply(__this, arguments);\n${@idt(1)}});" + "(function(__this) {\n${@idt(1)}var __func = $func;\n${@idt(1)}return $inner\n${@idt()}})(this)" top_sensitive: -> true @@ -704,7 +705,8 @@ exports.CodeNode: class CodeNode extends BaseNode toString: (idt) -> idt ||= '' - '\n' + idt + @type + (child.toString(idt + TAB) for child in @real_children()).join('') + children: (child.toString(idt + TAB) for child in @real_children()).join('') + "\n$idt$children" # A splat, either as a parameter to a function, an argument to a call, @@ -722,10 +724,10 @@ exports.SplatNode: class SplatNode extends BaseNode compile_param: (o) -> name: @name.compile(o) o.scope.find name - name + ' = Array.prototype.slice.call(arguments, ' + @index + ')' + "$name = Array.prototype.slice.call(arguments, $@index)" compile_value: (o, name, index) -> - "Array.prototype.slice.call(" + name + ', ' + index + ')' + "Array.prototype.slice.call($name, $index)" # A while loop, the only sort of low-level loop exposed by CoffeeScript. From @@ -753,13 +755,13 @@ exports.WhileNode: class WhileNode extends BaseNode set: '' if not top rvar: o.scope.free_variable() - set: @idt() + rvar + ' = [];\n' + set: "${@idt()}$rvar = [];\n" @body: PushNode.wrap(rvar, @body) if @body - post: if returns then '\n' + @idt() + 'return ' + rvar + ';' else '' - pre: set + @idt() + 'while (' + cond + ')' - return pre + ' null;' + post if not @body + post: if returns then "\n${@idt()}return $rvar;" else '' + pre: "$set${@idt()}while ($cond)" + return "$pre null;$post" if not @body @body: Expressions.wrap([new IfNode(@filter, @body)]) if @filter - pre + ' {\n' + @body.compile(o) + '\n' + @idt() + '}' + post + "$pre {\n${ @body.compile(o) }\n${@idt()}}$post" statement WhileNode @@ -801,24 +803,26 @@ exports.OpNode: class OpNode extends BaseNode return @compile_assignment(o) if @ASSIGNMENT.indexOf(@operator) >= 0 return @compile_unary(o) if @is_unary() return @compile_existence(o) if @operator is '?' - @first.compile(o) + ' ' + @operator + ' ' + @second.compile(o) + [@first.compile(o), @operator, @second.compile(o)].join ' ' # Mimic Python's chained comparisons. See: # http://docs.python.org/reference/expressions.html#notin compile_chain: (o) -> shared: @first.unwrap().second [@first.second, shared]: shared.compile_reference(o) if shared instanceof CallNode - '(' + @first.compile(o) + ') && (' + shared.compile(o) + ' ' + @operator + ' ' + @second.compile(o) + ')' + [first, second, shared]: [@first.compile(o), @second.compile(o), shared.compile(o)] + "($first) && ($shared $@operator $second)" compile_assignment: (o) -> [first, second]: [@first.compile(o), @second.compile(o)] o.scope.find(first) if first.match(IDENTIFIER) - return first + ' = ' + ExistenceNode.compile_test(o, @first) + ' ? ' + first + ' : ' + second if @operator is '?=' - first + ' = ' + first + ' ' + @operator.substr(0, 2) + ' ' + second + return "$first = ${ ExistenceNode.compile_test(o, @first) } ? $first : $second" if @operator is '?=' + "$first = $first ${ @operator.substr(0, 2) } $second" compile_existence: (o) -> [first, second]: [@first.compile(o), @second.compile(o)] - ExistenceNode.compile_test(o, @first) + ' ? ' + first + ' : ' + second + test: ExistenceNode.compile_test(o, @first) + "$test ? $first : $second" compile_unary: (o) -> space: if @PREFIX_OPERATORS.indexOf(@operator) >= 0 then ' ' else '' @@ -839,10 +843,11 @@ exports.TryNode: class TryNode extends BaseNode compile_node: (o) -> o.indent: @idt(1) o.top: true - error_part: if @error then ' (' + @error.compile(o) + ') ' else ' ' - catch_part: (@recovery or '') and ' catch' + error_part + '{\n' + @recovery.compile(o) + '\n' + @idt() + '}' - finally_part: (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o, {returns: null})) + '\n' + @idt() + '}' - @idt() + 'try {\n' + @attempt.compile(o) + '\n' + @idt() + '}' + catch_part + finally_part + attempt_part: @attempt.compile(o) + error_part: if @error then " (${ @error.compile(o) }) " else ' ' + catch_part: "${ (@recovery or '') and ' catch' }$error_part{\n${ @recovery.compile(o) }\n${@idt()}}" + finally_part: (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o, {returns: null})) + "\n${@idt()}}" + "${@idt()}try {\n$attempt_part\n${@idt()}}$catch_part$finally_part" statement TryNode @@ -855,7 +860,7 @@ exports.ThrowNode: class ThrowNode extends BaseNode @children: [@expression: expression] compile_node: (o) -> - @idt() + 'throw ' + @expression.compile(o) + ';' + "${@idt()}throw ${@expression.compile(o)};" statement ThrowNode, true @@ -874,7 +879,8 @@ ExistenceNode.compile_test: (o, variable) -> [first, second]: [variable, variable] if variable instanceof CallNode or (variable instanceof ValueNode and variable.has_properties()) [first, second]: variable.compile_reference(o) - '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)' + [first, second]: [first.compile(o), second.compile(o)] + "(typeof $first !== \"undefined\" && $second !== null)" # An extra set of parentheses, specified explicitly in the source. @@ -892,7 +898,7 @@ exports.ParentheticalNode: class ParentheticalNode extends BaseNode return code if @is_statement() l: code.length code: code.substr(o, l-1) if code.substr(l-1, 1) is ';' - '(' + code + ')' + "($code)" # The replacement for the for loop is an array comprehension (that compiles) @@ -921,10 +927,10 @@ exports.ForNode: class ForNode extends BaseNode range: @source instanceof ValueNode and @source.base instanceof RangeNode and not @source.properties.length source: if range then @source.base else @source scope: o.scope - name: @name and @name.compile(o) - index: @index and @index.compile(o) - name_found: name and scope.find(name) - index_found: index and scope.find(index) + name: @name and @name.compile o + index: @index and @index.compile o + name_found: name and scope.find name + index_found: index and scope.find index body_dent: @idt(1) rvar: scope.free_variable() unless top_level svar: scope.free_variable() @@ -933,16 +939,17 @@ exports.ForNode: class ForNode extends BaseNode body: Expressions.wrap([@body]) if range index_var: scope.free_variable() - source_part: source.compile_variables(o) - for_part: index_var + ' = 0, ' + source.compile(merge(o, {index: ivar, step: @step})) + ', ' + index_var + '++' + source_part: source.compile_variables o + for_part: source.compile merge o, {index: ivar, step: @step} + for_part: "$index_var = 0, $for_part, $index_var++" else index_var: null - source_part: svar + ' = ' + @source.compile(o) + ';\n' + @idt() - var_part: body_dent + name + ' = ' + svar + '[' + ivar + '];\n' if name + source_part: "$svar = ${ @source.compile(o) };\n${@idt()}" + var_part: "$body_dent$name = $svar[$ivar];\n" if name if not @object lvar: scope.free_variable() - step_part: if @step then ivar + ' += ' + @step.compile(o) else ivar + '++' - for_part: ivar + ' = 0, ' + lvar + ' = ' + svar + '.length; ' + ivar + ' < ' + lvar + '; ' + step_part + step_part: if @step then "$ivar += ${ @step.compile(o) }" else "$ivar++" + for_part: "$ivar = 0, $lvar = $svar.length; $ivar < $lvar; $step_part" set_result: if rvar then @idt() + rvar + ' = []; ' else @idt() return_result: rvar or '' body: ClosureNode.wrap(body, true) if top_level and @contains (n) -> n instanceof CodeNode @@ -955,12 +962,12 @@ exports.ForNode: class ForNode extends BaseNode body: Expressions.wrap([new IfNode(@filter, body)]) if @object o.scope.assign('__hasProp', 'Object.prototype.hasOwnProperty', true) - for_part: ivar + ' in ' + svar + ') { if (__hasProp.call(' + svar + ', ' + ivar + ')' - return_result: '\n' + @idt() + return_result + ';' unless top_level + for_part: "$ivar in $svar) { if (__hasProp.call($svar, $ivar)" + return_result: "\n${@idt()}$return_result;" unless top_level body: body.compile(merge(o, {indent: body_dent, top: true})) - vars: if range then name else name + ', ' + ivar + vars: if range then name else "$name, $ivar" close: if @object then '}}\n' else '}\n' - set_result + source_part + 'for (' + for_part + ') {\n' + var_part + body + '\n' + @idt() + close + @idt() + return_result + "$set_result${source_part}for ($for_part) {\n$var_part$body\n${@idt()}$close${@idt()}$return_result" statement ForNode @@ -1045,18 +1052,18 @@ exports.IfNode: class IfNode extends BaseNode o.top: true if_dent: if child then '' else @idt() com_dent: if child then @idt() else '' - prefix: if @comment then @comment.compile(cond_o) + '\n' + com_dent else '' + prefix: if @comment then "${ @comment.compile(cond_o) }\n$com_dent" else '' body: Expressions.wrap([@body]).compile(o) - if_part: prefix + if_dent + 'if (' + @compile_condition(cond_o) + ') {\n' + body + '\n' + @idt() + '}' + if_part: "$prefix${if_dent}if (${ @compile_condition(cond_o) }) {\n$body\n${@idt()}}" return if_part unless @else_body else_part: if @is_chain() ' else ' + @else_body.compile(merge(o, {indent: @idt(), chain_child: true})) else - ' else {\n' + Expressions.wrap([@else_body]).compile(o) + '\n' + @idt() + '}' - if_part + else_part + " else {\n${ Expressions.wrap([@else_body]).compile(o) }\n${@idt()}}" + "$if_part$else_part" # Compile the IfNode into a ternary operator. compile_ternary: (o) -> if_part: @condition.compile(o) + ' ? ' + @body.compile(o) else_part: if @else_body then @else_body.compile(o) else 'null' - if_part + ' : ' + else_part + "$if_part : $else_part"