haml-more 0.4.0.a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. data/README.md +79 -0
  2. data/lib/haml/more/coffee_script.rb +137 -0
  3. data/lib/haml/more/content_for.rb +25 -0
  4. data/lib/haml/more.rb +45 -0
  5. data/lib/haml-more.rb +1 -0
  6. data/lib/sass/more.rb +16 -0
  7. data/lib/sass-more.rb +1 -0
  8. data/spec/sass/more_spec.rb +21 -0
  9. data/vendor/coffee-script/Cakefile +57 -0
  10. data/vendor/coffee-script/LICENSE +22 -0
  11. data/vendor/coffee-script/README +41 -0
  12. data/vendor/coffee-script/Rakefile +20 -0
  13. data/vendor/coffee-script/bin/cake +7 -0
  14. data/vendor/coffee-script/bin/coffee +7 -0
  15. data/vendor/coffee-script/documentation/coffee/aliases.coffee +9 -0
  16. data/vendor/coffee-script/documentation/coffee/arguments.coffee +4 -0
  17. data/vendor/coffee-script/documentation/coffee/array_comprehensions.coffee +7 -0
  18. data/vendor/coffee-script/documentation/coffee/assignment.coffee +2 -0
  19. data/vendor/coffee-script/documentation/coffee/cake_tasks.coffee +5 -0
  20. data/vendor/coffee-script/documentation/coffee/comparisons.coffee +5 -0
  21. data/vendor/coffee-script/documentation/coffee/conditionals.coffee +9 -0
  22. data/vendor/coffee-script/documentation/coffee/embedded.coffee +5 -0
  23. data/vendor/coffee-script/documentation/coffee/existence.coffee +8 -0
  24. data/vendor/coffee-script/documentation/coffee/expressions.coffee +9 -0
  25. data/vendor/coffee-script/documentation/coffee/expressions_assignment.coffee +1 -0
  26. data/vendor/coffee-script/documentation/coffee/expressions_comprehension.coffee +3 -0
  27. data/vendor/coffee-script/documentation/coffee/expressions_try.coffee +6 -0
  28. data/vendor/coffee-script/documentation/coffee/fat_arrow.coffee +6 -0
  29. data/vendor/coffee-script/documentation/coffee/functions.coffee +2 -0
  30. data/vendor/coffee-script/documentation/coffee/heredocs.coffee +5 -0
  31. data/vendor/coffee-script/documentation/coffee/multiple_return_values.coffee +5 -0
  32. data/vendor/coffee-script/documentation/coffee/object_comprehensions.coffee +4 -0
  33. data/vendor/coffee-script/documentation/coffee/object_extraction.coffee +13 -0
  34. data/vendor/coffee-script/documentation/coffee/objects_and_arrays.coffee +13 -0
  35. data/vendor/coffee-script/documentation/coffee/overview.coffee +29 -0
  36. data/vendor/coffee-script/documentation/coffee/parallel_assignment.coffee +4 -0
  37. data/vendor/coffee-script/documentation/coffee/range_comprehensions.coffee +6 -0
  38. data/vendor/coffee-script/documentation/coffee/scope.coffee +5 -0
  39. data/vendor/coffee-script/documentation/coffee/slices.coffee +6 -0
  40. data/vendor/coffee-script/documentation/coffee/soaks.coffee +1 -0
  41. data/vendor/coffee-script/documentation/coffee/splats.coffee +25 -0
  42. data/vendor/coffee-script/documentation/coffee/splices.coffee +5 -0
  43. data/vendor/coffee-script/documentation/coffee/strings.coffee +8 -0
  44. data/vendor/coffee-script/documentation/coffee/super.coffee +34 -0
  45. data/vendor/coffee-script/documentation/coffee/switch.coffee +10 -0
  46. data/vendor/coffee-script/documentation/coffee/try.coffee +7 -0
  47. data/vendor/coffee-script/documentation/coffee/while.coffee +10 -0
  48. data/vendor/coffee-script/documentation/css/docs.css +213 -0
  49. data/vendor/coffee-script/documentation/css/idle.css +63 -0
  50. data/vendor/coffee-script/documentation/css/logo.png +0 -0
  51. data/vendor/coffee-script/documentation/index.html.erb +967 -0
  52. data/vendor/coffee-script/documentation/js/aliases.js +14 -0
  53. data/vendor/coffee-script/documentation/js/arguments.js +8 -0
  54. data/vendor/coffee-script/documentation/js/array_comprehensions.js +26 -0
  55. data/vendor/coffee-script/documentation/js/assignment.js +5 -0
  56. data/vendor/coffee-script/documentation/js/cake_tasks.js +14 -0
  57. data/vendor/coffee-script/documentation/js/comparisons.js +5 -0
  58. data/vendor/coffee-script/documentation/js/conditionals.js +12 -0
  59. data/vendor/coffee-script/documentation/js/embedded.js +6 -0
  60. data/vendor/coffee-script/documentation/js/existence.js +7 -0
  61. data/vendor/coffee-script/documentation/js/expressions.js +13 -0
  62. data/vendor/coffee-script/documentation/js/expressions_assignment.js +4 -0
  63. data/vendor/coffee-script/documentation/js/expressions_comprehension.js +12 -0
  64. data/vendor/coffee-script/documentation/js/expressions_try.js +9 -0
  65. data/vendor/coffee-script/documentation/js/fat_arrow.js +15 -0
  66. data/vendor/coffee-script/documentation/js/functions.js +9 -0
  67. data/vendor/coffee-script/documentation/js/heredocs.js +4 -0
  68. data/vendor/coffee-script/documentation/js/intro.js +7 -0
  69. data/vendor/coffee-script/documentation/js/multiple_return_values.js +11 -0
  70. data/vendor/coffee-script/documentation/js/object_comprehensions.js +17 -0
  71. data/vendor/coffee-script/documentation/js/object_extraction.js +17 -0
  72. data/vendor/coffee-script/documentation/js/objects_and_arrays.js +10 -0
  73. data/vendor/coffee-script/documentation/js/overview.js +43 -0
  74. data/vendor/coffee-script/documentation/js/parallel_assignment.js +8 -0
  75. data/vendor/coffee-script/documentation/js/punctuation.js +8 -0
  76. data/vendor/coffee-script/documentation/js/range_comprehensions.js +21 -0
  77. data/vendor/coffee-script/documentation/js/scope.js +10 -0
  78. data/vendor/coffee-script/documentation/js/slices.js +6 -0
  79. data/vendor/coffee-script/documentation/js/soaks.js +4 -0
  80. data/vendor/coffee-script/documentation/js/splats.js +16 -0
  81. data/vendor/coffee-script/documentation/js/splices.js +5 -0
  82. data/vendor/coffee-script/documentation/js/strings.js +9 -0
  83. data/vendor/coffee-script/documentation/js/super.js +37 -0
  84. data/vendor/coffee-script/documentation/js/switch.js +18 -0
  85. data/vendor/coffee-script/documentation/js/try.js +10 -0
  86. data/vendor/coffee-script/documentation/js/while.js +22 -0
  87. data/vendor/coffee-script/documentation/underscore.html +627 -0
  88. data/vendor/coffee-script/examples/beautiful_code/binary_search.coffee +16 -0
  89. data/vendor/coffee-script/examples/beautiful_code/quicksort_runtime.coffee +13 -0
  90. data/vendor/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee +34 -0
  91. data/vendor/coffee-script/examples/blocks.coffee +57 -0
  92. data/vendor/coffee-script/examples/code.coffee +173 -0
  93. data/vendor/coffee-script/examples/computer_science/README +4 -0
  94. data/vendor/coffee-script/examples/computer_science/binary_search.coffee +25 -0
  95. data/vendor/coffee-script/examples/computer_science/bubble_sort.coffee +11 -0
  96. data/vendor/coffee-script/examples/computer_science/linked_list.coffee +106 -0
  97. data/vendor/coffee-script/examples/computer_science/luhn_algorithm.coffee +36 -0
  98. data/vendor/coffee-script/examples/computer_science/merge_sort.coffee +19 -0
  99. data/vendor/coffee-script/examples/computer_science/selection_sort.coffee +23 -0
  100. data/vendor/coffee-script/examples/poignant.coffee +186 -0
  101. data/vendor/coffee-script/examples/potion.coffee +205 -0
  102. data/vendor/coffee-script/examples/underscore.coffee +603 -0
  103. data/vendor/coffee-script/examples/web_server.coffee +12 -0
  104. data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences +24 -0
  105. data/vendor/coffee-script/extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +361 -0
  106. data/vendor/coffee-script/extras/CoffeeScript.tmbundle/info.plist +10 -0
  107. data/vendor/coffee-script/extras/EXTRAS +20 -0
  108. data/vendor/coffee-script/extras/coffee.vim +117 -0
  109. data/vendor/coffee-script/index.html +1847 -0
  110. data/vendor/coffee-script/lib/bin/cake +7 -0
  111. data/vendor/coffee-script/lib/bin/coffee +7 -0
  112. data/vendor/coffee-script/lib/cake.js +80 -0
  113. data/vendor/coffee-script/lib/coffee-script.js +61 -0
  114. data/vendor/coffee-script/lib/command_line.js +201 -0
  115. data/vendor/coffee-script/lib/grammar.js +564 -0
  116. data/vendor/coffee-script/lib/lexer.js +405 -0
  117. data/vendor/coffee-script/lib/narwhal.js +44 -0
  118. data/vendor/coffee-script/lib/nodes.js +1328 -0
  119. data/vendor/coffee-script/lib/optparse.js +117 -0
  120. data/vendor/coffee-script/lib/parser.js +536 -0
  121. data/vendor/coffee-script/lib/repl.js +32 -0
  122. data/vendor/coffee-script/lib/rewriter.js +383 -0
  123. data/vendor/coffee-script/lib/scope.js +114 -0
  124. data/vendor/coffee-script/package.json +7 -0
  125. data/vendor/coffee-script/src/cake.coffee +45 -0
  126. data/vendor/coffee-script/src/coffee-script.coffee +45 -0
  127. data/vendor/coffee-script/src/command_line.coffee +130 -0
  128. data/vendor/coffee-script/src/grammar.coffee +456 -0
  129. data/vendor/coffee-script/src/lexer.coffee +327 -0
  130. data/vendor/coffee-script/src/narwhal.coffee +42 -0
  131. data/vendor/coffee-script/src/nodes.coffee +1045 -0
  132. data/vendor/coffee-script/src/optparse.coffee +79 -0
  133. data/vendor/coffee-script/src/repl.coffee +23 -0
  134. data/vendor/coffee-script/src/rewriter.coffee +253 -0
  135. data/vendor/coffee-script/src/scope.coffee +75 -0
  136. data/vendor/coffee-script/test/test_arguments.coffee +34 -0
  137. data/vendor/coffee-script/test/test_array_comprehension.coffee +42 -0
  138. data/vendor/coffee-script/test/test_assignment.coffee +26 -0
  139. data/vendor/coffee-script/test/test_blocks.coffee +4 -0
  140. data/vendor/coffee-script/test/test_calling_super.coffee +42 -0
  141. data/vendor/coffee-script/test/test_chained_calls.coffee +25 -0
  142. data/vendor/coffee-script/test/test_destructuring_assignment.coffee +62 -0
  143. data/vendor/coffee-script/test/test_everything.coffee +29 -0
  144. data/vendor/coffee-script/test/test_exceptions.coffee +2 -0
  145. data/vendor/coffee-script/test/test_existence.coffee +81 -0
  146. data/vendor/coffee-script/test/test_expressions.coffee +30 -0
  147. data/vendor/coffee-script/test/test_fancy_if_statement.coffee +26 -0
  148. data/vendor/coffee-script/test/test_functions.coffee +80 -0
  149. data/vendor/coffee-script/test/test_funky_comments.coffee +25 -0
  150. data/vendor/coffee-script/test/test_heredocs.coffee +46 -0
  151. data/vendor/coffee-script/test/test_lexical_scope.coffee +10 -0
  152. data/vendor/coffee-script/test/test_literals.coffee +56 -0
  153. data/vendor/coffee-script/test/test_nested_comprehensions.coffee +11 -0
  154. data/vendor/coffee-script/test/test_newline_escaping.coffee +6 -0
  155. data/vendor/coffee-script/test/test_operations.coffee +18 -0
  156. data/vendor/coffee-script/test/test_range_comprehension.coffee +20 -0
  157. data/vendor/coffee-script/test/test_ranges_and_slices.coffee +16 -0
  158. data/vendor/coffee-script/test/test_splats.coffee +47 -0
  159. data/vendor/coffee-script/test/test_splices.coffee +5 -0
  160. data/vendor/coffee-script/test/test_switch.coffee +64 -0
  161. data/vendor/coffee-script/test/test_while.coffee +30 -0
  162. data/vendor/coffee-script/vendor/jison/Jakefile +31 -0
  163. data/vendor/coffee-script/vendor/jison/README.md +347 -0
  164. data/vendor/coffee-script/vendor/jison/bin/jison +3 -0
  165. data/vendor/coffee-script/vendor/jison/bin/json2jison +3 -0
  166. data/vendor/coffee-script/vendor/jison/examples/ansic.jison +415 -0
  167. data/vendor/coffee-script/vendor/jison/examples/basic.json +8 -0
  168. data/vendor/coffee-script/vendor/jison/examples/basic2.json +9 -0
  169. data/vendor/coffee-script/vendor/jison/examples/basic2_lex.json +16 -0
  170. data/vendor/coffee-script/vendor/jison/examples/basic_lex.json +15 -0
  171. data/vendor/coffee-script/vendor/jison/examples/calculator.jison +38 -0
  172. data/vendor/coffee-script/vendor/jison/examples/calculator.jisonlex +14 -0
  173. data/vendor/coffee-script/vendor/jison/examples/calculator.json +42 -0
  174. data/vendor/coffee-script/vendor/jison/examples/classy.json +105 -0
  175. data/vendor/coffee-script/vendor/jison/examples/classy_ast.json +126 -0
  176. data/vendor/coffee-script/vendor/jison/examples/dism.json +25 -0
  177. data/vendor/coffee-script/vendor/jison/examples/dism_lr0.json +26 -0
  178. data/vendor/coffee-script/vendor/jison/examples/json.js +80 -0
  179. data/vendor/coffee-script/vendor/jison/examples/json_ast.js +83 -0
  180. data/vendor/coffee-script/vendor/jison/examples/precedence.json +26 -0
  181. data/vendor/coffee-script/vendor/jison/examples/reduce_conflict.json +13 -0
  182. data/vendor/coffee-script/vendor/jison/lib/jison/bnf.js +43 -0
  183. data/vendor/coffee-script/vendor/jison/lib/jison/jisonlex.js +18 -0
  184. data/vendor/coffee-script/vendor/jison/lib/jison/json2jison.js +146 -0
  185. data/vendor/coffee-script/vendor/jison/lib/jison/lexer.js +224 -0
  186. data/vendor/coffee-script/vendor/jison/lib/jison/util/bnf-parser.js +383 -0
  187. data/vendor/coffee-script/vendor/jison/lib/jison/util/lex-parser.js +407 -0
  188. data/vendor/coffee-script/vendor/jison/lib/jison/util/set.js +94 -0
  189. data/vendor/coffee-script/vendor/jison/lib/jison/util/typal.js +90 -0
  190. data/vendor/coffee-script/vendor/jison/lib/jison.js +1414 -0
  191. data/vendor/coffee-script/vendor/jison/package.json +14 -0
  192. data/vendor/coffee-script/vendor/jison/src/bnf.jison +110 -0
  193. data/vendor/coffee-script/vendor/jison/src/bnf.jisonlex +25 -0
  194. data/vendor/coffee-script/vendor/jison/src/bnf.lex.json +24 -0
  195. data/vendor/coffee-script/vendor/jison/src/jisonlex.jison +129 -0
  196. data/vendor/coffee-script/vendor/jison/src/jisonlex.jisonlex +31 -0
  197. data/vendor/coffee-script/vendor/jison/src/jisonlex.lex.json +30 -0
  198. data/vendor/coffee-script/vendor/jison/tests/all-tests.js +8 -0
  199. data/vendor/coffee-script/vendor/jison/tests/grammar/bnf.js +91 -0
  200. data/vendor/coffee-script/vendor/jison/tests/grammar/bnf_parse.js +65 -0
  201. data/vendor/coffee-script/vendor/jison/tests/grammar/grammar-tests.js +10 -0
  202. data/vendor/coffee-script/vendor/jison/tests/grammar/json2jison.js +24 -0
  203. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/ansic.jisonlex +115 -0
  204. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.jisonlex +25 -0
  205. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/bnf.lex.json +24 -0
  206. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.jisonlex +31 -0
  207. data/vendor/coffee-script/vendor/jison/tests/grammar/lex/lex_grammar.lex.json +30 -0
  208. data/vendor/coffee-script/vendor/jison/tests/grammar/lex.jison +119 -0
  209. data/vendor/coffee-script/vendor/jison/tests/grammar/lex.js +58 -0
  210. data/vendor/coffee-script/vendor/jison/tests/grammar/lex_parse.js +117 -0
  211. data/vendor/coffee-script/vendor/jison/tests/lexer/lexer-tests.js +6 -0
  212. data/vendor/coffee-script/vendor/jison/tests/lexer/regexplexer.js +417 -0
  213. data/vendor/coffee-script/vendor/jison/tests/parser/actions.js +311 -0
  214. data/vendor/coffee-script/vendor/jison/tests/parser/api.js +236 -0
  215. data/vendor/coffee-script/vendor/jison/tests/parser/generator.js +196 -0
  216. data/vendor/coffee-script/vendor/jison/tests/parser/lalr.js +183 -0
  217. data/vendor/coffee-script/vendor/jison/tests/parser/lr0.js +72 -0
  218. data/vendor/coffee-script/vendor/jison/tests/parser/lr1.js +119 -0
  219. data/vendor/coffee-script/vendor/jison/tests/parser/parser-tests.js +14 -0
  220. data/vendor/coffee-script/vendor/jison/tests/parser/precedence.js +237 -0
  221. data/vendor/coffee-script/vendor/jison/tests/parser/slr.js +52 -0
  222. data/vendor/coffee-script/vendor/jison/tests/parser/tables.js +126 -0
  223. data/vendor/coffee-script/vendor/jison/tests/performance.js +110 -0
  224. data/vendor/coffee-script/vendor/jison/tests/setup.js +3 -0
  225. metadata +324 -0
@@ -0,0 +1,1328 @@
1
+ (function(){
2
+ var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, Node, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, inherit, merge, statement;
3
+ var __hasProp = Object.prototype.hasOwnProperty;
4
+ (typeof process !== "undefined" && process !== null) ? process.mixin(require('scope')) : (this.exports = this);
5
+ // Some helper functions
6
+ // Tabs are two spaces for pretty printing.
7
+ TAB = ' ';
8
+ TRAILING_WHITESPACE = /\s+$/gm;
9
+ // Keep the identifier regex in sync with the Lexer.
10
+ IDENTIFIER = /^[a-zA-Z$_](\w|\$)*$/;
11
+ // Merge objects.
12
+ merge = function merge(options, overrides) {
13
+ var _a, _b, fresh, key, val;
14
+ fresh = {};
15
+ _a = options;
16
+ for (key in _a) { if (__hasProp.call(_a, key)) {
17
+ val = _a[key];
18
+ ((fresh[key] = val));
19
+ }}
20
+ if (overrides) {
21
+ _b = overrides;
22
+ for (key in _b) { if (__hasProp.call(_b, key)) {
23
+ val = _b[key];
24
+ ((fresh[key] = val));
25
+ }}
26
+ }
27
+ return fresh;
28
+ };
29
+ // Trim out all falsy values from an array.
30
+ compact = function compact(array) {
31
+ var _a, _b, _c, item;
32
+ _a = []; _b = array;
33
+ for (_c = 0; _c < _b.length; _c++) {
34
+ item = _b[_c];
35
+ if (item) {
36
+ _a.push(item);
37
+ }
38
+ }
39
+ return _a;
40
+ };
41
+ // Return a completely flattened version of an array.
42
+ flatten = function flatten(array) {
43
+ var _a, _b, item, memo;
44
+ memo = [];
45
+ _a = array;
46
+ for (_b = 0; _b < _a.length; _b++) {
47
+ item = _a[_b];
48
+ item instanceof Array ? (memo = memo.concat(item)) : memo.push(item);
49
+ }
50
+ return memo;
51
+ };
52
+ // Delete a key from an object, returning the value.
53
+ del = function del(obj, key) {
54
+ var val;
55
+ val = obj[key];
56
+ delete obj[key];
57
+ return val;
58
+ };
59
+ // Quickie inheritance convenience wrapper to reduce typing.
60
+ inherit = function inherit(parent, props) {
61
+ var _a, _b, klass, name, prop;
62
+ klass = del(props, 'constructor');
63
+ _a = function(){};
64
+ _a.prototype = parent.prototype;
65
+ klass.__superClass__ = parent.prototype;
66
+ klass.prototype = new _a();
67
+ klass.prototype.constructor = klass;
68
+ _b = props;
69
+ for (name in _b) { if (__hasProp.call(_b, name)) {
70
+ prop = _b[name];
71
+ ((klass.prototype[name] = prop));
72
+ }}
73
+ return klass;
74
+ };
75
+ // Mark a node as a statement, or a statement only.
76
+ statement = function statement(klass, only) {
77
+ klass.prototype.is_statement = function is_statement() {
78
+ return true;
79
+ };
80
+ if (only) {
81
+ return ((klass.prototype.is_statement_only = function is_statement_only() {
82
+ return true;
83
+ }));
84
+ }
85
+ };
86
+ // The abstract base class for all CoffeeScript nodes.
87
+ // All nodes are implement a "compile_node" method, which performs the
88
+ // code generation for that node. To compile a node, call the "compile"
89
+ // method, which wraps "compile_node" in some extra smarts, to know when the
90
+ // generated code should be wrapped up in a closure. An options hash is passed
91
+ // and cloned throughout, containing messages from higher in the AST,
92
+ // information about the current scope, and indentation level.
93
+ Node = (exports.Node = function Node() { });
94
+ // This is extremely important -- we convert JS statements into expressions
95
+ // by wrapping them in a closure, only if it's possible, and we're not at
96
+ // the top level of a block (which would be unnecessary), and we haven't
97
+ // already been asked to return the result.
98
+ Node.prototype.compile = function compile(o) {
99
+ var closure, top;
100
+ this.options = merge(o || {});
101
+ this.indent = o.indent;
102
+ if (!(this.operation_sensitive())) {
103
+ del(this.options, 'operation');
104
+ }
105
+ top = this.top_sensitive() ? this.options.top : del(this.options, 'top');
106
+ closure = this.is_statement() && !this.is_statement_only() && !top && !this.options.returns && !(this instanceof CommentNode) && !this.contains(function(node) {
107
+ return node.is_statement_only();
108
+ });
109
+ return closure ? this.compile_closure(this.options) : this.compile_node(this.options);
110
+ };
111
+ // Statements converted into expressions share scope with their parent
112
+ // closure, to preserve JavaScript-style lexical scope.
113
+ Node.prototype.compile_closure = function compile_closure(o) {
114
+ this.indent = o.indent;
115
+ o.shared_scope = o.scope;
116
+ return ClosureNode.wrap(this).compile(o);
117
+ };
118
+ // If the code generation wishes to use the result of a complex expression
119
+ // in multiple places, ensure that the expression is only ever evaluated once.
120
+ Node.prototype.compile_reference = function compile_reference(o) {
121
+ var compiled, reference;
122
+ reference = new LiteralNode(o.scope.free_variable());
123
+ compiled = new AssignNode(reference, this);
124
+ return [compiled, reference];
125
+ };
126
+ // Quick short method for the current indentation level, plus tabbing in.
127
+ Node.prototype.idt = function idt(tabs) {
128
+ var _a, _b, _c, _d, i, idt;
129
+ idt = (this.indent || '');
130
+ _c = 0; _d = (tabs || 0);
131
+ for (_b = 0, i=_c; (_c <= _d ? i < _d : i > _d); (_c <= _d ? i += 1 : i -= 1), _b++) {
132
+ idt += TAB;
133
+ }
134
+ return idt;
135
+ };
136
+ // Does this node, or any of its children, contain a node of a certain kind?
137
+ Node.prototype.contains = function contains(block) {
138
+ var _a, _b, node;
139
+ _a = this.children;
140
+ for (_b = 0; _b < _a.length; _b++) {
141
+ node = _a[_b];
142
+ if (block(node)) {
143
+ return true;
144
+ }
145
+ if (node instanceof Node && node.contains(block)) {
146
+ return true;
147
+ }
148
+ }
149
+ return false;
150
+ };
151
+ // toString representation of the node, for inspecting the parse tree.
152
+ Node.prototype.toString = function toString(idt) {
153
+ var _a, _b, _c, child;
154
+ idt = idt || '';
155
+ return '\n' + idt + this.type + (function() {
156
+ _a = []; _b = this.children;
157
+ for (_c = 0; _c < _b.length; _c++) {
158
+ child = _b[_c];
159
+ _a.push(child.toString(idt + TAB));
160
+ }
161
+ return _a;
162
+ }).call(this).join('');
163
+ };
164
+ // Default implementations of the common node methods.
165
+ Node.prototype.unwrap = function unwrap() {
166
+ return this;
167
+ };
168
+ Node.prototype.children = [];
169
+ Node.prototype.is_statement = function is_statement() {
170
+ return false;
171
+ };
172
+ Node.prototype.is_statement_only = function is_statement_only() {
173
+ return false;
174
+ };
175
+ Node.prototype.top_sensitive = function top_sensitive() {
176
+ return false;
177
+ };
178
+ Node.prototype.operation_sensitive = function operation_sensitive() {
179
+ return false;
180
+ };
181
+ // A collection of nodes, each one representing an expression.
182
+ Expressions = (exports.Expressions = inherit(Node, {
183
+ type: 'Expressions',
184
+ constructor: function constructor(nodes) {
185
+ this.children = (this.expressions = compact(flatten(nodes || [])));
186
+ return this;
187
+ },
188
+ // Tack an expression on to the end of this expression list.
189
+ push: function push(node) {
190
+ this.expressions.push(node);
191
+ return this;
192
+ },
193
+ // Tack an expression on to the beginning of this expression list.
194
+ unshift: function unshift(node) {
195
+ this.expressions.unshift(node);
196
+ return this;
197
+ },
198
+ // If this Expressions consists of a single node, pull it back out.
199
+ unwrap: function unwrap() {
200
+ return this.expressions.length === 1 ? this.expressions[0] : this;
201
+ },
202
+ // Is this an empty block of code?
203
+ empty: function empty() {
204
+ return this.expressions.length === 0;
205
+ },
206
+ // Is the node last in this block of expressions?
207
+ is_last: function is_last(node) {
208
+ var l, last_index;
209
+ l = this.expressions.length;
210
+ last_index = this.expressions[l - 1] instanceof CommentNode ? 2 : 1;
211
+ return node === this.expressions[l - last_index];
212
+ },
213
+ compile: function compile(o) {
214
+ o = o || {};
215
+ return o.scope ? Node.prototype.compile.call(this, o) : this.compile_root(o);
216
+ },
217
+ // Compile each expression in the Expressions body.
218
+ compile_node: function compile_node(o) {
219
+ var _a, _b, _c, node;
220
+ return (function() {
221
+ _a = []; _b = this.expressions;
222
+ for (_c = 0; _c < _b.length; _c++) {
223
+ node = _b[_c];
224
+ _a.push(this.compile_expression(node, merge(o)));
225
+ }
226
+ return _a;
227
+ }).call(this).join("\n");
228
+ },
229
+ // If this is the top-level Expressions, wrap everything in a safety closure.
230
+ compile_root: function compile_root(o) {
231
+ var code, indent;
232
+ o.indent = (this.indent = (indent = o.no_wrap ? '' : TAB));
233
+ o.scope = new Scope(null, this, null);
234
+ code = o.globals ? this.compile_node(o) : this.compile_with_declarations(o);
235
+ code = code.replace(TRAILING_WHITESPACE, '');
236
+ return o.no_wrap ? code : "(function(){\n" + code + "\n})();";
237
+ },
238
+ // Compile the expressions body, with declarations of all inner variables
239
+ // pushed up to the top.
240
+ compile_with_declarations: function compile_with_declarations(o) {
241
+ var args, code;
242
+ code = this.compile_node(o);
243
+ args = this.contains(function(node) {
244
+ return node instanceof ValueNode && node.is_arguments();
245
+ });
246
+ if (args) {
247
+ code = this.idt() + "arguments = Array.prototype.slice.call(arguments, 0);\n" + code;
248
+ }
249
+ if (o.scope.has_assignments(this)) {
250
+ code = this.idt() + 'var ' + o.scope.compiled_assignments() + ";\n" + code;
251
+ }
252
+ if (o.scope.has_declarations(this)) {
253
+ code = this.idt() + 'var ' + o.scope.compiled_declarations() + ";\n" + code;
254
+ }
255
+ return code;
256
+ },
257
+ // Compiles a single expression within the expressions body.
258
+ compile_expression: function compile_expression(node, o) {
259
+ var returns, stmt;
260
+ this.indent = o.indent;
261
+ stmt = node.is_statement();
262
+ // We need to return the result if this is the last node in the expressions body.
263
+ returns = del(o, 'returns') && this.is_last(node) && !node.is_statement_only();
264
+ // Return the regular compile of the node, unless we need to return the result.
265
+ if (!(returns)) {
266
+ return (stmt ? '' : this.idt()) + node.compile(merge(o, {
267
+ top: true
268
+ })) + (stmt ? '' : ';');
269
+ }
270
+ // If it's a statement, the node knows how to return itself.
271
+ if (node.is_statement()) {
272
+ return node.compile(merge(o, {
273
+ returns: true
274
+ }));
275
+ }
276
+ // Otherwise, we can just return the value of the expression.
277
+ return this.idt() + 'return ' + node.compile(o) + ';';
278
+ }
279
+ }));
280
+ // Wrap up a node as an Expressions, unless it already is one.
281
+ Expressions.wrap = function wrap(nodes) {
282
+ if (nodes.length === 1 && nodes[0] instanceof Expressions) {
283
+ return nodes[0];
284
+ }
285
+ return new Expressions(nodes);
286
+ };
287
+ statement(Expressions);
288
+ // Literals are static values that can be passed through directly into
289
+ // JavaScript without translation, eg.: strings, numbers, true, false, null...
290
+ LiteralNode = (exports.LiteralNode = inherit(Node, {
291
+ type: 'Literal',
292
+ constructor: function constructor(value) {
293
+ this.value = value;
294
+ return this;
295
+ },
296
+ // Break and continue must be treated as statements -- they lose their meaning
297
+ // when wrapped in a closure.
298
+ is_statement: function is_statement() {
299
+ return this.value === 'break' || this.value === 'continue';
300
+ },
301
+ compile_node: function compile_node(o) {
302
+ var end, idt;
303
+ idt = this.is_statement() ? this.idt() : '';
304
+ end = this.is_statement() ? ';' : '';
305
+ return idt + this.value + end;
306
+ },
307
+ toString: function toString(idt) {
308
+ return ' "' + this.value + '"';
309
+ }
310
+ }));
311
+ LiteralNode.prototype.is_statement_only = LiteralNode.prototype.is_statement;
312
+ // Return an expression, or wrap it in a closure and return it.
313
+ ReturnNode = (exports.ReturnNode = inherit(Node, {
314
+ type: 'Return',
315
+ constructor: function constructor(expression) {
316
+ this.children = [(this.expression = expression)];
317
+ return this;
318
+ },
319
+ compile_node: function compile_node(o) {
320
+ if (this.expression.is_statement()) {
321
+ return this.expression.compile(merge(o, {
322
+ returns: true
323
+ }));
324
+ }
325
+ return this.idt() + 'return ' + this.expression.compile(o) + ';';
326
+ }
327
+ }));
328
+ statement(ReturnNode, true);
329
+ // A value, indexed or dotted into, or vanilla.
330
+ ValueNode = (exports.ValueNode = inherit(Node, {
331
+ type: 'Value',
332
+ SOAK: " == undefined ? undefined : ",
333
+ constructor: function constructor(base, properties) {
334
+ this.children = flatten([(this.base = base), (this.properties = (properties || []))]);
335
+ return this;
336
+ },
337
+ push: function push(prop) {
338
+ this.properties.push(prop);
339
+ this.children.push(prop);
340
+ return this;
341
+ },
342
+ operation_sensitive: function operation_sensitive() {
343
+ return true;
344
+ },
345
+ has_properties: function has_properties() {
346
+ return !!this.properties.length;
347
+ },
348
+ is_array: function is_array() {
349
+ return this.base instanceof ArrayNode && !this.has_properties();
350
+ },
351
+ is_object: function is_object() {
352
+ return this.base instanceof ObjectNode && !this.has_properties();
353
+ },
354
+ is_splice: function is_splice() {
355
+ return this.has_properties() && this.properties[this.properties.length - 1] instanceof SliceNode;
356
+ },
357
+ is_arguments: function is_arguments() {
358
+ return this.base.value === 'arguments';
359
+ },
360
+ unwrap: function unwrap() {
361
+ return this.properties.length ? this : this.base;
362
+ },
363
+ // Values are statements if their base is a statement.
364
+ is_statement: function is_statement() {
365
+ return this.base.is_statement && this.base.is_statement() && !this.has_properties();
366
+ },
367
+ compile_node: function compile_node(o) {
368
+ var _a, _b, baseline, complete, only, op, part, prop, props, soaked, temp;
369
+ soaked = false;
370
+ only = del(o, 'only_first');
371
+ op = del(o, 'operation');
372
+ props = only ? this.properties.slice(0, this.properties.length - 1) : this.properties;
373
+ baseline = this.base.compile(o);
374
+ if (this.base instanceof ObjectNode && this.has_properties()) {
375
+ baseline = '(' + baseline + ')';
376
+ }
377
+ complete = (this.last = baseline);
378
+ _a = props;
379
+ for (_b = 0; _b < _a.length; _b++) {
380
+ prop = _a[_b];
381
+ this.source = baseline;
382
+ if (prop.soak_node) {
383
+ soaked = true;
384
+ if (this.base instanceof CallNode && prop === props[0]) {
385
+ temp = o.scope.free_variable();
386
+ complete = '(' + temp + ' = ' + complete + ')' + this.SOAK + ((baseline = temp + prop.compile(o)));
387
+ } else {
388
+ complete = complete + this.SOAK + (baseline += prop.compile(o));
389
+ }
390
+ } else {
391
+ part = prop.compile(o);
392
+ baseline += part;
393
+ complete += part;
394
+ this.last = part;
395
+ }
396
+ }
397
+ return op && soaked ? '(' + complete + ')' : complete;
398
+ }
399
+ }));
400
+ // Pass through CoffeeScript comments into JavaScript comments at the
401
+ // same position.
402
+ CommentNode = (exports.CommentNode = inherit(Node, {
403
+ type: 'Comment',
404
+ constructor: function constructor(lines) {
405
+ this.lines = lines;
406
+ return this;
407
+ },
408
+ compile_node: function compile_node(o) {
409
+ return this.idt() + '//' + this.lines.join('\n' + this.idt() + '//');
410
+ }
411
+ }));
412
+ statement(CommentNode);
413
+ // Node for a function invocation. Takes care of converting super() calls into
414
+ // calls against the prototype's function of the same name.
415
+ CallNode = (exports.CallNode = inherit(Node, {
416
+ type: 'Call',
417
+ constructor: function constructor(variable, args) {
418
+ this.children = flatten([(this.variable = variable), (this.args = (args || []))]);
419
+ this.prefix = '';
420
+ return this;
421
+ },
422
+ new_instance: function new_instance() {
423
+ this.prefix = 'new ';
424
+ return this;
425
+ },
426
+ push: function push(arg) {
427
+ this.args.push(arg);
428
+ this.children.push(arg);
429
+ return this;
430
+ },
431
+ // Compile a vanilla function call.
432
+ compile_node: function compile_node(o) {
433
+ var _a, _b, _c, arg, args;
434
+ if (this.args[this.args.length - 1] instanceof SplatNode) {
435
+ return this.compile_splat(o);
436
+ }
437
+ args = (function() {
438
+ _a = []; _b = this.args;
439
+ for (_c = 0; _c < _b.length; _c++) {
440
+ arg = _b[_c];
441
+ _a.push(arg.compile(o));
442
+ }
443
+ return _a;
444
+ }).call(this).join(', ');
445
+ if (this.variable === 'super') {
446
+ return this.compile_super(args, o);
447
+ }
448
+ return this.prefix + this.variable.compile(o) + '(' + args + ')';
449
+ },
450
+ // Compile a call against the superclass's implementation of the current function.
451
+ compile_super: function compile_super(args, o) {
452
+ var arg_part, meth, methname;
453
+ methname = o.scope.method.name;
454
+ arg_part = args.length ? ', ' + args : '';
455
+ meth = o.scope.method.proto ? o.scope.method.proto + '.__superClass__.' + methname : methname + '.__superClass__.constructor';
456
+ return meth + '.call(this' + arg_part + ')';
457
+ },
458
+ // Compile a function call being passed variable arguments.
459
+ compile_splat: function compile_splat(o) {
460
+ var _a, _b, arg, args, code, i, meth, obj;
461
+ meth = this.variable.compile(o);
462
+ obj = this.variable.source || 'this';
463
+ args = (function() {
464
+ _a = []; _b = this.args;
465
+ for (i = 0; i < _b.length; i++) {
466
+ arg = _b[i];
467
+ _a.push((function() {
468
+ code = arg.compile(o);
469
+ code = arg instanceof SplatNode ? code : '[' + code + ']';
470
+ return i === 0 ? code : '.concat(' + code + ')';
471
+ }).call(this));
472
+ }
473
+ return _a;
474
+ }).call(this);
475
+ return this.prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')';
476
+ }
477
+ }));
478
+ // Node to extend an object's prototype with an ancestor object.
479
+ // After goog.inherits from the Closure Library.
480
+ ExtendsNode = (exports.ExtendsNode = inherit(Node, {
481
+ type: 'Extends',
482
+ constructor: function constructor(child, parent) {
483
+ this.children = [(this.child = child), (this.parent = parent)];
484
+ return this;
485
+ },
486
+ // Hooking one constructor into another's prototype chain.
487
+ compile_node: function compile_node(o) {
488
+ var child, child_var, construct, parent, parent_var, prefix;
489
+ construct = o.scope.free_variable();
490
+ child = this.child.compile(o);
491
+ parent = this.parent.compile(o);
492
+ prefix = '';
493
+ if (!(this.child instanceof ValueNode) || this.child.has_properties() || !(this.child.unwrap() instanceof LiteralNode)) {
494
+ child_var = o.scope.free_variable();
495
+ prefix += this.idt() + child_var + ' = ' + child + ';\n';
496
+ child = child_var;
497
+ }
498
+ if (!(this.parent instanceof ValueNode) || this.parent.has_properties() || !(this.parent.unwrap() instanceof LiteralNode)) {
499
+ parent_var = o.scope.free_variable();
500
+ prefix += this.idt() + parent_var + ' = ' + parent + ';\n';
501
+ parent = parent_var;
502
+ }
503
+ return prefix + this.idt() + construct + ' = function(){};\n' + this.idt() + construct + '.prototype = ' + parent + ".prototype;\n" + this.idt() + child + '.__superClass__ = ' + parent + ".prototype;\n" + this.idt() + child + '.prototype = new ' + construct + "();\n" + this.idt() + child + '.prototype.constructor = ' + child + ';';
504
+ }
505
+ }));
506
+ statement(ExtendsNode);
507
+ // A dotted accessor into a part of a value, or the :: shorthand for
508
+ // an accessor into the object's prototype.
509
+ AccessorNode = (exports.AccessorNode = inherit(Node, {
510
+ type: 'Accessor',
511
+ constructor: function constructor(name, tag) {
512
+ this.children = [(this.name = name)];
513
+ this.prototype = tag === 'prototype';
514
+ this.soak_node = tag === 'soak';
515
+ return this;
516
+ },
517
+ compile_node: function compile_node(o) {
518
+ return '.' + (this.prototype ? 'prototype.' : '') + this.name.compile(o);
519
+ }
520
+ }));
521
+ // An indexed accessor into a part of an array or object.
522
+ IndexNode = (exports.IndexNode = inherit(Node, {
523
+ type: 'Index',
524
+ constructor: function constructor(index, tag) {
525
+ this.children = [(this.index = index)];
526
+ this.soak_node = tag === 'soak';
527
+ return this;
528
+ },
529
+ compile_node: function compile_node(o) {
530
+ return '[' + this.index.compile(o) + ']';
531
+ }
532
+ }));
533
+ // A range literal. Ranges can be used to extract portions (slices) of arrays,
534
+ // or to specify a range for list comprehensions.
535
+ RangeNode = (exports.RangeNode = inherit(Node, {
536
+ type: 'Range',
537
+ constructor: function constructor(from, to, exclusive) {
538
+ this.children = [(this.from = from), (this.to = to)];
539
+ this.exclusive = !!exclusive;
540
+ return this;
541
+ },
542
+ compile_variables: function compile_variables(o) {
543
+ this.indent = o.indent;
544
+ this.from_var = o.scope.free_variable();
545
+ this.to_var = o.scope.free_variable();
546
+ return this.from_var + ' = ' + this.from.compile(o) + '; ' + this.to_var + ' = ' + this.to.compile(o) + ";\n" + this.idt();
547
+ },
548
+ compile_node: function compile_node(o) {
549
+ var compare, equals, idx, incr, intro, step, vars;
550
+ if (!(o.index)) {
551
+ return this.compile_array(o);
552
+ }
553
+ idx = del(o, 'index');
554
+ step = del(o, 'step');
555
+ vars = idx + '=' + this.from_var;
556
+ step = step ? step.compile(o) : '1';
557
+ equals = this.exclusive ? '' : '=';
558
+ intro = '(' + this.from_var + ' <= ' + this.to_var + ' ? ' + idx;
559
+ compare = intro + ' <' + equals + ' ' + this.to_var + ' : ' + idx + ' >' + equals + ' ' + this.to_var + ')';
560
+ incr = intro + ' += ' + step + ' : ' + idx + ' -= ' + step + ')';
561
+ return vars + '; ' + compare + '; ' + incr;
562
+ },
563
+ // Expand the range into the equivalent array, if it's not being used as
564
+ // part of a comprehension, slice, or splice.
565
+ // TODO: This generates pretty ugly code ... shrink it.
566
+ compile_array: function compile_array(o) {
567
+ var arr, body, name;
568
+ name = o.scope.free_variable();
569
+ body = Expressions.wrap([new LiteralNode(name)]);
570
+ arr = Expressions.wrap([new ForNode(body, {
571
+ source: (new ValueNode(this))
572
+ }, new LiteralNode(name))
573
+ ]);
574
+ return (new ParentheticalNode(new CallNode(new CodeNode([], arr)))).compile(o);
575
+ }
576
+ }));
577
+ // An array slice literal. Unlike JavaScript's Array#slice, the second parameter
578
+ // specifies the index of the end of the slice (just like the first parameter)
579
+ // is the index of the beginning.
580
+ SliceNode = (exports.SliceNode = inherit(Node, {
581
+ type: 'Slice',
582
+ constructor: function constructor(range) {
583
+ this.children = [(this.range = range)];
584
+ return this;
585
+ },
586
+ compile_node: function compile_node(o) {
587
+ var from, plus_part, to;
588
+ from = this.range.from.compile(o);
589
+ to = this.range.to.compile(o);
590
+ plus_part = this.range.exclusive ? '' : ' + 1';
591
+ return ".slice(" + from + ', ' + to + plus_part + ')';
592
+ }
593
+ }));
594
+ // An object literal.
595
+ ObjectNode = (exports.ObjectNode = inherit(Node, {
596
+ type: 'Object',
597
+ constructor: function constructor(props) {
598
+ this.children = (this.objects = (this.properties = props || []));
599
+ return this;
600
+ },
601
+ // All the mucking about with commas is to make sure that CommentNodes and
602
+ // AssignNodes get interleaved correctly, with no trailing commas or
603
+ // commas affixed to comments. TODO: Extract this and add it to ArrayNode.
604
+ compile_node: function compile_node(o) {
605
+ var _a, _b, _c, _d, _e, i, indent, inner, join, last_noncom, non_comments, prop, props;
606
+ o.indent = this.idt(1);
607
+ non_comments = (function() {
608
+ _a = []; _b = this.properties;
609
+ for (_c = 0; _c < _b.length; _c++) {
610
+ prop = _b[_c];
611
+ if (!(prop instanceof CommentNode)) {
612
+ _a.push(prop);
613
+ }
614
+ }
615
+ return _a;
616
+ }).call(this);
617
+ last_noncom = non_comments[non_comments.length - 1];
618
+ props = (function() {
619
+ _d = []; _e = this.properties;
620
+ for (i = 0; i < _e.length; i++) {
621
+ prop = _e[i];
622
+ _d.push((function() {
623
+ join = ",\n";
624
+ if ((prop === last_noncom) || (prop instanceof CommentNode)) {
625
+ join = "\n";
626
+ }
627
+ if (i === this.properties.length - 1) {
628
+ join = '';
629
+ }
630
+ indent = prop instanceof CommentNode ? '' : this.idt(1);
631
+ return indent + prop.compile(o) + join;
632
+ }).call(this));
633
+ }
634
+ return _d;
635
+ }).call(this);
636
+ props = props.join('');
637
+ inner = props ? '\n' + props + '\n' + this.idt() : '';
638
+ return '{' + inner + '}';
639
+ }
640
+ }));
641
+ // An array literal.
642
+ ArrayNode = (exports.ArrayNode = inherit(Node, {
643
+ type: 'Array',
644
+ constructor: function constructor(objects) {
645
+ this.children = (this.objects = objects || []);
646
+ return this;
647
+ },
648
+ compile_node: function compile_node(o) {
649
+ var _a, _b, code, ending, i, obj, objects;
650
+ o.indent = this.idt(1);
651
+ objects = (function() {
652
+ _a = []; _b = this.objects;
653
+ for (i = 0; i < _b.length; i++) {
654
+ obj = _b[i];
655
+ _a.push((function() {
656
+ code = obj.compile(o);
657
+ if (obj instanceof CommentNode) {
658
+ return '\n' + code + '\n' + o.indent;
659
+ } else if (i === this.objects.length - 1) {
660
+ return code;
661
+ } else {
662
+ return code + ', ';
663
+ }
664
+ }).call(this));
665
+ }
666
+ return _a;
667
+ }).call(this);
668
+ objects = objects.join('');
669
+ ending = objects.indexOf('\n') >= 0 ? "\n" + this.idt() + ']' : ']';
670
+ return '[' + objects + ending;
671
+ }
672
+ }));
673
+ // A faux-node that is never created by the grammar, but is used during
674
+ // code generation to generate a quick "array.push(value)" tree of nodes.
675
+ PushNode = (exports.PushNode = {
676
+ wrap: function wrap(array, expressions) {
677
+ var expr;
678
+ expr = expressions.unwrap();
679
+ if (expr.is_statement_only() || expr.contains(function(n) {
680
+ return n.is_statement_only();
681
+ })) {
682
+ return expressions;
683
+ }
684
+ return Expressions.wrap([new CallNode(new ValueNode(new LiteralNode(array), [new AccessorNode(new LiteralNode('push'))]), [expr])]);
685
+ }
686
+ });
687
+ // A faux-node used to wrap an expressions body in a closure.
688
+ ClosureNode = (exports.ClosureNode = {
689
+ wrap: function wrap(expressions, statement) {
690
+ var call, func;
691
+ func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])));
692
+ call = new CallNode(new ValueNode(func, [new AccessorNode(new LiteralNode('call'))]), [new LiteralNode('this')]);
693
+ return statement ? Expressions.wrap([call]) : call;
694
+ }
695
+ });
696
+ // Setting the value of a local variable, or the value of an object property.
697
+ AssignNode = (exports.AssignNode = inherit(Node, {
698
+ type: 'Assign',
699
+ PROTO_ASSIGN: /^(\S+)\.prototype/,
700
+ LEADING_DOT: /^\.(prototype\.)?/,
701
+ constructor: function constructor(variable, value, context) {
702
+ this.children = [(this.variable = variable), (this.value = value)];
703
+ this.context = context;
704
+ return this;
705
+ },
706
+ top_sensitive: function top_sensitive() {
707
+ return true;
708
+ },
709
+ is_value: function is_value() {
710
+ return this.variable instanceof ValueNode;
711
+ },
712
+ is_statement: function is_statement() {
713
+ return this.is_value() && (this.variable.is_array() || this.variable.is_object());
714
+ },
715
+ compile_node: function compile_node(o) {
716
+ var last, match, name, proto, stmt, top, val;
717
+ top = del(o, 'top');
718
+ if (this.is_statement()) {
719
+ return this.compile_pattern_match(o);
720
+ }
721
+ if (this.is_value() && this.variable.is_splice()) {
722
+ return this.compile_splice(o);
723
+ }
724
+ stmt = del(o, 'as_statement');
725
+ name = this.variable.compile(o);
726
+ last = this.is_value() ? this.variable.last.replace(this.LEADING_DOT, '') : name;
727
+ match = name.match(this.PROTO_ASSIGN);
728
+ proto = match && match[1];
729
+ if (this.value instanceof CodeNode) {
730
+ if (last.match(IDENTIFIER)) {
731
+ this.value.name = last;
732
+ }
733
+ if (proto) {
734
+ this.value.proto = proto;
735
+ }
736
+ }
737
+ if (this.context === 'object') {
738
+ return name + ': ' + this.value.compile(o);
739
+ }
740
+ if (!(this.is_value() && this.variable.has_properties())) {
741
+ o.scope.find(name);
742
+ }
743
+ val = name + ' = ' + this.value.compile(o);
744
+ if (stmt) {
745
+ return this.idt() + val + ';';
746
+ }
747
+ if (!top || o.returns) {
748
+ val = '(' + val + ')';
749
+ }
750
+ if (o.returns) {
751
+ val = this.idt() + 'return ' + val;
752
+ }
753
+ return val;
754
+ },
755
+ // Implementation of recursive pattern matching, when assigning array or
756
+ // object literals to a value. Peeks at their properties to assign inner names.
757
+ // See: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
758
+ compile_pattern_match: function compile_pattern_match(o) {
759
+ var _a, _b, access_class, assigns, i, idx, obj, val, val_var;
760
+ val_var = o.scope.free_variable();
761
+ assigns = [this.idt() + val_var + ' = ' + this.value.compile(o) + ';'];
762
+ o.top = true;
763
+ o.as_statement = true;
764
+ _a = this.variable.base.objects;
765
+ for (i = 0; i < _a.length; i++) {
766
+ obj = _a[i];
767
+ idx = i;
768
+ if (this.variable.is_object()) {
769
+ _b = [obj.value, obj.variable.base];
770
+ obj = _b[0];
771
+ idx = _b[1];
772
+ }
773
+ access_class = this.variable.is_array() ? IndexNode : AccessorNode;
774
+ if (obj instanceof SplatNode) {
775
+ val = new LiteralNode(obj.compile_value(o, val_var, this.variable.base.objects.indexOf(obj)));
776
+ } else {
777
+ if (!(typeof idx === 'object')) {
778
+ idx = new LiteralNode(idx);
779
+ }
780
+ val = new ValueNode(new LiteralNode(val_var), [new access_class(idx)]);
781
+ }
782
+ assigns.push(new AssignNode(obj, val).compile(o));
783
+ }
784
+ return assigns.join("\n");
785
+ },
786
+ compile_splice: function compile_splice(o) {
787
+ var from, l, name, plus, range, to;
788
+ name = this.variable.compile(merge(o, {
789
+ only_first: true
790
+ }));
791
+ l = this.variable.properties.length;
792
+ range = this.variable.properties[l - 1].range;
793
+ plus = range.exclusive ? '' : ' + 1';
794
+ from = range.from.compile(o);
795
+ to = range.to.compile(o) + ' - ' + from + plus;
796
+ return name + '.splice.apply(' + name + ', [' + from + ', ' + to + '].concat(' + this.value.compile(o) + '))';
797
+ }
798
+ }));
799
+ // A function definition. The only node that creates a new Scope.
800
+ // A CodeNode does not have any children -- they're within the new scope.
801
+ CodeNode = (exports.CodeNode = inherit(Node, {
802
+ type: 'Code',
803
+ constructor: function constructor(params, body, tag) {
804
+ this.params = params;
805
+ this.body = body;
806
+ this.bound = tag === 'boundfunc';
807
+ return this;
808
+ },
809
+ compile_node: function compile_node(o) {
810
+ var _a, _b, _c, _d, _e, code, func, inner, name_part, param, params, shared_scope, splat, top;
811
+ shared_scope = del(o, 'shared_scope');
812
+ top = del(o, 'top');
813
+ o.scope = shared_scope || new Scope(o.scope, this.body, this);
814
+ o.returns = true;
815
+ o.top = true;
816
+ o.indent = this.idt(this.bound ? 2 : 1);
817
+ del(o, 'no_wrap');
818
+ del(o, 'globals');
819
+ if (this.params[this.params.length - 1] instanceof SplatNode) {
820
+ splat = this.params.pop();
821
+ splat.index = this.params.length;
822
+ this.body.unshift(splat);
823
+ }
824
+ params = (function() {
825
+ _a = []; _b = this.params;
826
+ for (_c = 0; _c < _b.length; _c++) {
827
+ param = _b[_c];
828
+ _a.push(param.compile(o));
829
+ }
830
+ return _a;
831
+ }).call(this);
832
+ _d = params;
833
+ for (_e = 0; _e < _d.length; _e++) {
834
+ param = _d[_e];
835
+ (o.scope.parameter(param));
836
+ }
837
+ code = this.body.expressions.length ? '\n' + this.body.compile_with_declarations(o) + '\n' : '';
838
+ name_part = this.name ? ' ' + this.name : '';
839
+ func = 'function' + (this.bound ? '' : name_part) + '(' + params.join(', ') + ') {' + code + this.idt(this.bound ? 1 : 0) + '}';
840
+ if (top && !this.bound) {
841
+ func = '(' + func + ')';
842
+ }
843
+ if (!(this.bound)) {
844
+ return func;
845
+ }
846
+ inner = '(function' + name_part + '() {\n' + this.idt(2) + 'return __func.apply(__this, arguments);\n' + this.idt(1) + '});';
847
+ return '(function(__this) {\n' + this.idt(1) + 'var __func = ' + func + ';\n' + this.idt(1) + 'return ' + inner + '\n' + this.idt() + '})(this)';
848
+ },
849
+ top_sensitive: function top_sensitive() {
850
+ return true;
851
+ },
852
+ toString: function toString(idt) {
853
+ var _a, _b, _c, child, children;
854
+ idt = idt || '';
855
+ children = flatten([this.params, this.body.expressions]);
856
+ return '\n' + idt + this.type + (function() {
857
+ _a = []; _b = children;
858
+ for (_c = 0; _c < _b.length; _c++) {
859
+ child = _b[_c];
860
+ _a.push(child.toString(idt + TAB));
861
+ }
862
+ return _a;
863
+ }).call(this).join('');
864
+ }
865
+ }));
866
+ // A splat, either as a parameter to a function, an argument to a call,
867
+ // or in a destructuring assignment.
868
+ SplatNode = (exports.SplatNode = inherit(Node, {
869
+ type: 'Splat',
870
+ constructor: function constructor(name) {
871
+ if (!(name.compile)) {
872
+ name = new LiteralNode(name);
873
+ }
874
+ this.children = [(this.name = name)];
875
+ return this;
876
+ },
877
+ compile_node: function compile_node(o) {
878
+ var _a;
879
+ return (typeof (_a = this.index) !== "undefined" && _a !== null) ? this.compile_param(o) : this.name.compile(o);
880
+ },
881
+ compile_param: function compile_param(o) {
882
+ var name;
883
+ name = this.name.compile(o);
884
+ o.scope.find(name);
885
+ return name + ' = Array.prototype.slice.call(arguments, ' + this.index + ')';
886
+ },
887
+ compile_value: function compile_value(o, name, index) {
888
+ return "Array.prototype.slice.call(" + name + ', ' + index + ')';
889
+ }
890
+ }));
891
+ // A while loop, the only sort of low-level loop exposed by CoffeeScript. From
892
+ // it, all other loops can be manufactured.
893
+ WhileNode = (exports.WhileNode = inherit(Node, {
894
+ type: 'While',
895
+ constructor: function constructor(condition, opts) {
896
+ this.children = [(this.condition = condition)];
897
+ this.filter = opts && opts.filter;
898
+ return this;
899
+ },
900
+ add_body: function add_body(body) {
901
+ this.children.push((this.body = body));
902
+ return this;
903
+ },
904
+ top_sensitive: function top_sensitive() {
905
+ return true;
906
+ },
907
+ compile_node: function compile_node(o) {
908
+ var cond, post, pre, returns, rvar, set, top;
909
+ returns = del(o, 'returns');
910
+ top = del(o, 'top') && !returns;
911
+ o.indent = this.idt(1);
912
+ o.top = true;
913
+ cond = this.condition.compile(o);
914
+ set = '';
915
+ if (!top) {
916
+ rvar = o.scope.free_variable();
917
+ set = this.idt() + rvar + ' = [];\n';
918
+ if (this.body) {
919
+ this.body = PushNode.wrap(rvar, this.body);
920
+ }
921
+ }
922
+ post = returns ? '\n' + this.idt() + 'return ' + rvar + ';' : '';
923
+ pre = set + this.idt() + 'while (' + cond + ')';
924
+ if (!this.body) {
925
+ return pre + ' null;' + post;
926
+ }
927
+ if (this.filter) {
928
+ this.body = Expressions.wrap([new IfNode(this.filter, this.body)]);
929
+ }
930
+ return pre + ' {\n' + this.body.compile(o) + '\n' + this.idt() + '}' + post;
931
+ }
932
+ }));
933
+ statement(WhileNode);
934
+ // Simple Arithmetic and logical operations. Performs some conversion from
935
+ // CoffeeScript operations into their JavaScript equivalents.
936
+ OpNode = (exports.OpNode = inherit(Node, {
937
+ type: 'Op',
938
+ CONVERSIONS: {
939
+ '==': '===',
940
+ '!=': '!==',
941
+ 'and': '&&',
942
+ 'or': '||',
943
+ 'is': '===',
944
+ 'isnt': '!==',
945
+ 'not': '!'
946
+ },
947
+ CHAINABLE: ['<', '>', '>=', '<=', '===', '!=='],
948
+ ASSIGNMENT: ['||=', '&&=', '?='],
949
+ PREFIX_OPERATORS: ['typeof', 'delete'],
950
+ constructor: function constructor(operator, first, second, flip) {
951
+ this.type += ' ' + operator;
952
+ this.children = compact([(this.first = first), (this.second = second)]);
953
+ this.operator = this.CONVERSIONS[operator] || operator;
954
+ this.flip = !!flip;
955
+ return this;
956
+ },
957
+ is_unary: function is_unary() {
958
+ return !this.second;
959
+ },
960
+ is_chainable: function is_chainable() {
961
+ return this.CHAINABLE.indexOf(this.operator) >= 0;
962
+ },
963
+ compile_node: function compile_node(o) {
964
+ o.operation = true;
965
+ if (this.is_chainable() && this.first.unwrap() instanceof OpNode && this.first.unwrap().is_chainable()) {
966
+ return this.compile_chain(o);
967
+ }
968
+ if (this.ASSIGNMENT.indexOf(this.operator) >= 0) {
969
+ return this.compile_assignment(o);
970
+ }
971
+ if (this.is_unary()) {
972
+ return this.compile_unary(o);
973
+ }
974
+ if (this.operator === '?') {
975
+ return this.compile_existence(o);
976
+ }
977
+ return this.first.compile(o) + ' ' + this.operator + ' ' + this.second.compile(o);
978
+ },
979
+ // Mimic Python's chained comparisons. See:
980
+ // http://docs.python.org/reference/expressions.html#notin
981
+ compile_chain: function compile_chain(o) {
982
+ var _a, shared;
983
+ shared = this.first.unwrap().second;
984
+ if (shared instanceof CallNode) {
985
+ _a = shared.compile_reference(o);
986
+ this.first.second = _a[0];
987
+ shared = _a[1];
988
+ }
989
+ return '(' + this.first.compile(o) + ') && (' + shared.compile(o) + ' ' + this.operator + ' ' + this.second.compile(o) + ')';
990
+ },
991
+ compile_assignment: function compile_assignment(o) {
992
+ var _a, first, second;
993
+ _a = [this.first.compile(o), this.second.compile(o)];
994
+ first = _a[0];
995
+ second = _a[1];
996
+ if (first.match(IDENTIFIER)) {
997
+ o.scope.find(first);
998
+ }
999
+ if (this.operator === '?=') {
1000
+ return first + ' = ' + ExistenceNode.compile_test(o, this.first) + ' ? ' + first + ' : ' + second;
1001
+ }
1002
+ return first + ' = ' + first + ' ' + this.operator.substr(0, 2) + ' ' + second;
1003
+ },
1004
+ compile_existence: function compile_existence(o) {
1005
+ var _a, first, second;
1006
+ _a = [this.first.compile(o), this.second.compile(o)];
1007
+ first = _a[0];
1008
+ second = _a[1];
1009
+ return ExistenceNode.compile_test(o, this.first) + ' ? ' + first + ' : ' + second;
1010
+ },
1011
+ compile_unary: function compile_unary(o) {
1012
+ var parts, space;
1013
+ space = this.PREFIX_OPERATORS.indexOf(this.operator) >= 0 ? ' ' : '';
1014
+ parts = [this.operator, space, this.first.compile(o)];
1015
+ if (this.flip) {
1016
+ parts = parts.reverse();
1017
+ }
1018
+ return parts.join('');
1019
+ }
1020
+ }));
1021
+ // A try/catch/finally block.
1022
+ TryNode = (exports.TryNode = inherit(Node, {
1023
+ type: 'Try',
1024
+ constructor: function constructor(attempt, error, recovery, ensure) {
1025
+ this.children = compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]);
1026
+ this.error = error;
1027
+ return this;
1028
+ },
1029
+ compile_node: function compile_node(o) {
1030
+ var catch_part, error_part, finally_part;
1031
+ o.indent = this.idt(1);
1032
+ o.top = true;
1033
+ error_part = this.error ? ' (' + this.error.compile(o) + ') ' : ' ';
1034
+ catch_part = (this.recovery || '') && ' catch' + error_part + '{\n' + this.recovery.compile(o) + '\n' + this.idt() + '}';
1035
+ finally_part = (this.ensure || '') && ' finally {\n' + this.ensure.compile(merge(o, {
1036
+ returns: null
1037
+ })) + '\n' + this.idt() + '}';
1038
+ return this.idt() + 'try {\n' + this.attempt.compile(o) + '\n' + this.idt() + '}' + catch_part + finally_part;
1039
+ }
1040
+ }));
1041
+ statement(TryNode);
1042
+ // Throw an exception.
1043
+ ThrowNode = (exports.ThrowNode = inherit(Node, {
1044
+ type: 'Throw',
1045
+ constructor: function constructor(expression) {
1046
+ this.children = [(this.expression = expression)];
1047
+ return this;
1048
+ },
1049
+ compile_node: function compile_node(o) {
1050
+ return this.idt() + 'throw ' + this.expression.compile(o) + ';';
1051
+ }
1052
+ }));
1053
+ statement(ThrowNode, true);
1054
+ // Check an expression for existence (meaning not null or undefined).
1055
+ ExistenceNode = (exports.ExistenceNode = inherit(Node, {
1056
+ type: 'Existence',
1057
+ constructor: function constructor(expression) {
1058
+ this.children = [(this.expression = expression)];
1059
+ return this;
1060
+ },
1061
+ compile_node: function compile_node(o) {
1062
+ return ExistenceNode.compile_test(o, this.expression);
1063
+ }
1064
+ }));
1065
+ ExistenceNode.compile_test = function compile_test(o, variable) {
1066
+ var _a, _b, first, second;
1067
+ _a = [variable, variable];
1068
+ first = _a[0];
1069
+ second = _a[1];
1070
+ if (variable instanceof CallNode || (variable instanceof ValueNode && variable.has_properties())) {
1071
+ _b = variable.compile_reference(o);
1072
+ first = _b[0];
1073
+ second = _b[1];
1074
+ }
1075
+ return '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)';
1076
+ };
1077
+ // An extra set of parentheses, specified explicitly in the source.
1078
+ ParentheticalNode = (exports.ParentheticalNode = inherit(Node, {
1079
+ type: 'Paren',
1080
+ constructor: function constructor(expression) {
1081
+ this.children = [(this.expression = expression)];
1082
+ return this;
1083
+ },
1084
+ is_statement: function is_statement() {
1085
+ return this.expression.is_statement();
1086
+ },
1087
+ compile_node: function compile_node(o) {
1088
+ var code, l;
1089
+ code = this.expression.compile(o);
1090
+ if (this.is_statement()) {
1091
+ return code;
1092
+ }
1093
+ l = code.length;
1094
+ if (code.substr(l - 1, 1) === ';') {
1095
+ code = code.substr(o, l - 1);
1096
+ }
1097
+ return '(' + code + ')';
1098
+ }
1099
+ }));
1100
+ // The replacement for the for loop is an array comprehension (that compiles)
1101
+ // into a for loop. Also acts as an expression, able to return the result
1102
+ // of the comprehenion. Unlike Python array comprehensions, it's able to pass
1103
+ // the current index of the loop as a second parameter.
1104
+ ForNode = (exports.ForNode = inherit(Node, {
1105
+ type: 'For',
1106
+ constructor: function constructor(body, source, name, index) {
1107
+ var _a;
1108
+ this.body = body;
1109
+ this.name = name;
1110
+ this.index = index || null;
1111
+ this.source = source.source;
1112
+ this.filter = source.filter;
1113
+ this.step = source.step;
1114
+ this.object = !!source.object;
1115
+ if (this.object) {
1116
+ _a = [this.index, this.name];
1117
+ this.name = _a[0];
1118
+ this.index = _a[1];
1119
+ }
1120
+ this.children = compact([this.body, this.source, this.filter]);
1121
+ return this;
1122
+ },
1123
+ top_sensitive: function top_sensitive() {
1124
+ return true;
1125
+ },
1126
+ compile_node: function compile_node(o) {
1127
+ var body, body_dent, close, for_part, index, index_found, index_var, ivar, name, name_found, range, return_result, rvar, scope, set_result, source, source_part, step_part, svar, top_level, var_part, vars;
1128
+ top_level = del(o, 'top') && !o.returns;
1129
+ range = this.source instanceof ValueNode && this.source.base instanceof RangeNode && !this.source.properties.length;
1130
+ source = range ? this.source.base : this.source;
1131
+ scope = o.scope;
1132
+ name = this.name && this.name.compile(o);
1133
+ index = this.index && this.index.compile(o);
1134
+ name_found = name && scope.find(name);
1135
+ index_found = index && scope.find(index);
1136
+ body_dent = this.idt(1);
1137
+ if (!(top_level)) {
1138
+ rvar = scope.free_variable();
1139
+ }
1140
+ svar = scope.free_variable();
1141
+ ivar = range ? name : index || scope.free_variable();
1142
+ var_part = '';
1143
+ body = Expressions.wrap([this.body]);
1144
+ if (range) {
1145
+ index_var = scope.free_variable();
1146
+ source_part = source.compile_variables(o);
1147
+ for_part = index_var + ' = 0, ' + source.compile(merge(o, {
1148
+ index: ivar,
1149
+ step: this.step
1150
+ })) + ', ' + index_var + '++';
1151
+ } else {
1152
+ index_var = null;
1153
+ source_part = svar + ' = ' + this.source.compile(o) + ';\n' + this.idt();
1154
+ step_part = this.step ? ivar + ' += ' + this.step.compile(o) : ivar + '++';
1155
+ for_part = ivar + ' = 0; ' + ivar + ' < ' + svar + '.length; ' + step_part;
1156
+ if (name) {
1157
+ var_part = body_dent + name + ' = ' + svar + '[' + ivar + '];\n';
1158
+ }
1159
+ }
1160
+ set_result = rvar ? this.idt() + rvar + ' = []; ' : this.idt();
1161
+ return_result = rvar || '';
1162
+ if (top_level && this.contains(function(n) {
1163
+ return n instanceof CodeNode;
1164
+ })) {
1165
+ body = ClosureNode.wrap(body, true);
1166
+ }
1167
+ if (!(top_level)) {
1168
+ body = PushNode.wrap(rvar, body);
1169
+ }
1170
+ if (o.returns) {
1171
+ return_result = 'return ' + return_result;
1172
+ del(o, 'returns');
1173
+ if (this.filter) {
1174
+ body = new IfNode(this.filter, body, null, {
1175
+ statement: true
1176
+ });
1177
+ }
1178
+ } else if (this.filter) {
1179
+ body = Expressions.wrap([new IfNode(this.filter, body)]);
1180
+ }
1181
+ if (this.object) {
1182
+ o.scope.assign('__hasProp', 'Object.prototype.hasOwnProperty', true);
1183
+ for_part = ivar + ' in ' + svar + ') { if (__hasProp.call(' + svar + ', ' + ivar + ')';
1184
+ }
1185
+ if (!(top_level)) {
1186
+ return_result = '\n' + this.idt() + return_result + ';';
1187
+ }
1188
+ body = body.compile(merge(o, {
1189
+ indent: body_dent,
1190
+ top: true
1191
+ }));
1192
+ vars = range ? name : name + ', ' + ivar;
1193
+ close = this.object ? '}}\n' : '}\n';
1194
+ return set_result + source_part + 'for (' + for_part + ') {\n' + var_part + body + '\n' + this.idt() + close + this.idt() + return_result;
1195
+ }
1196
+ }));
1197
+ statement(ForNode);
1198
+ // If/else statements. Switch/whens get compiled into these. Acts as an
1199
+ // expression by pushing down requested returns to the expression bodies.
1200
+ // Single-expression IfNodes are compiled into ternary operators if possible,
1201
+ // because ternaries are first-class returnable assignable expressions.
1202
+ IfNode = (exports.IfNode = inherit(Node, {
1203
+ type: 'If',
1204
+ constructor: function constructor(condition, body, else_body, tags) {
1205
+ this.condition = condition;
1206
+ this.body = body && body.unwrap();
1207
+ this.else_body = else_body && else_body.unwrap();
1208
+ this.children = compact([this.condition, this.body, this.else_body]);
1209
+ this.tags = tags || {};
1210
+ if (this.condition instanceof Array) {
1211
+ this.multiple = true;
1212
+ }
1213
+ if (this.tags.invert) {
1214
+ this.condition = new OpNode('!', new ParentheticalNode(this.condition));
1215
+ }
1216
+ return this;
1217
+ },
1218
+ push: function push(else_body) {
1219
+ var eb;
1220
+ eb = else_body.unwrap();
1221
+ this.else_body ? this.else_body.push(eb) : (this.else_body = eb);
1222
+ return this;
1223
+ },
1224
+ force_statement: function force_statement() {
1225
+ this.tags.statement = true;
1226
+ return this;
1227
+ },
1228
+ // Tag a chain of IfNodes with their switch condition for equality.
1229
+ rewrite_condition: function rewrite_condition(expression) {
1230
+ this.switcher = expression;
1231
+ return this;
1232
+ },
1233
+ // Rewrite a chain of IfNodes with their switch condition for equality.
1234
+ rewrite_switch: function rewrite_switch(o) {
1235
+ var _a, _b, assigner, cond, i, variable;
1236
+ assigner = this.switcher;
1237
+ if (!(this.switcher.unwrap() instanceof LiteralNode)) {
1238
+ variable = new LiteralNode(o.scope.free_variable());
1239
+ assigner = new AssignNode(variable, this.switcher);
1240
+ this.switcher = variable;
1241
+ }
1242
+ this.condition = (function() {
1243
+ if (this.multiple) {
1244
+ _a = []; _b = this.condition;
1245
+ for (i = 0; i < _b.length; i++) {
1246
+ cond = _b[i];
1247
+ _a.push(new OpNode('is', (i === 0 ? assigner : this.switcher), cond));
1248
+ }
1249
+ return _a;
1250
+ } else {
1251
+ return new OpNode('is', assigner, this.condition);
1252
+ }
1253
+ }).call(this);
1254
+ if (this.is_chain()) {
1255
+ this.else_body.rewrite_condition(this.switcher);
1256
+ }
1257
+ return this;
1258
+ },
1259
+ // Rewrite a chain of IfNodes to add a default case as the final else.
1260
+ add_else: function add_else(exprs, statement) {
1261
+ if (this.is_chain()) {
1262
+ this.else_body.add_else(exprs, statement);
1263
+ } else {
1264
+ if (!(statement)) {
1265
+ exprs = exprs.unwrap();
1266
+ }
1267
+ this.children.push((this.else_body = exprs));
1268
+ }
1269
+ return this;
1270
+ },
1271
+ // If the else_body is an IfNode itself, then we've got an if-else chain.
1272
+ is_chain: function is_chain() {
1273
+ return this.chain = this.chain || this.else_body && this.else_body instanceof IfNode;
1274
+ },
1275
+ // The IfNode only compiles into a statement if either of the bodies needs
1276
+ // to be a statement.
1277
+ is_statement: function is_statement() {
1278
+ return this.statement = this.statement || !!(this.comment || this.tags.statement || this.body.is_statement() || (this.else_body && this.else_body.is_statement()));
1279
+ },
1280
+ compile_condition: function compile_condition(o) {
1281
+ var _a, _b, _c, cond;
1282
+ return (function() {
1283
+ _a = []; _b = flatten([this.condition]);
1284
+ for (_c = 0; _c < _b.length; _c++) {
1285
+ cond = _b[_c];
1286
+ _a.push(cond.compile(o));
1287
+ }
1288
+ return _a;
1289
+ }).call(this).join(' || ');
1290
+ },
1291
+ compile_node: function compile_node(o) {
1292
+ return this.is_statement() ? this.compile_statement(o) : this.compile_ternary(o);
1293
+ },
1294
+ // Compile the IfNode as a regular if-else statement. Flattened chains
1295
+ // force sub-else bodies into statement form.
1296
+ compile_statement: function compile_statement(o) {
1297
+ var body, child, com_dent, cond_o, else_part, if_dent, if_part, prefix;
1298
+ if (this.switcher) {
1299
+ this.rewrite_switch(o);
1300
+ }
1301
+ child = del(o, 'chain_child');
1302
+ cond_o = merge(o);
1303
+ del(cond_o, 'returns');
1304
+ o.indent = this.idt(1);
1305
+ o.top = true;
1306
+ if_dent = child ? '' : this.idt();
1307
+ com_dent = child ? this.idt() : '';
1308
+ prefix = this.comment ? this.comment.compile(cond_o) + '\n' + com_dent : '';
1309
+ body = Expressions.wrap([this.body]).compile(o);
1310
+ if_part = prefix + if_dent + 'if (' + this.compile_condition(cond_o) + ') {\n' + body + '\n' + this.idt() + '}';
1311
+ if (!(this.else_body)) {
1312
+ return if_part;
1313
+ }
1314
+ else_part = this.is_chain() ? ' else ' + this.else_body.compile(merge(o, {
1315
+ indent: this.idt(),
1316
+ chain_child: true
1317
+ })) : ' else {\n' + Expressions.wrap([this.else_body]).compile(o) + '\n' + this.idt() + '}';
1318
+ return if_part + else_part;
1319
+ },
1320
+ // Compile the IfNode into a ternary operator.
1321
+ compile_ternary: function compile_ternary(o) {
1322
+ var else_part, if_part;
1323
+ if_part = this.condition.compile(o) + ' ? ' + this.body.compile(o);
1324
+ else_part = this.else_body ? this.else_body.compile(o) : 'null';
1325
+ return if_part + ' : ' + else_part;
1326
+ }
1327
+ }));
1328
+ })();