spade 0.0.8.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (346) hide show
  1. data/.gitignore +0 -1
  2. data/.gitmodules +4 -4
  3. data/README.md +4 -0
  4. data/bin/spade +1 -1
  5. data/lib/spade.rb +0 -51
  6. data/lib/spade/cli.rb +10 -4
  7. data/lib/spade/version.rb +1 -1
  8. data/spade.gemspec +4 -21
  9. metadata +13 -482
  10. data/Gemfile +0 -3
  11. data/Gemfile.lock +0 -40
  12. data/lib/index.js +0 -14
  13. data/lib/node/loader.js +0 -146
  14. data/lib/node/sandbox.js +0 -44
  15. data/lib/spade.js +0 -1130
  16. data/lib/spade/bundle.rb +0 -171
  17. data/lib/spade/cli/base.rb +0 -354
  18. data/lib/spade/cli/owner.rb +0 -45
  19. data/lib/spade/cli/project_generator.rb +0 -58
  20. data/lib/spade/compiler.rb +0 -34
  21. data/lib/spade/console.rb +0 -39
  22. data/lib/spade/context.rb +0 -116
  23. data/lib/spade/credentials.rb +0 -36
  24. data/lib/spade/dependency_installer.rb +0 -103
  25. data/lib/spade/environment.rb +0 -35
  26. data/lib/spade/exports.rb +0 -71
  27. data/lib/spade/installer.rb +0 -40
  28. data/lib/spade/loader.rb +0 -238
  29. data/lib/spade/local.rb +0 -46
  30. data/lib/spade/package.rb +0 -157
  31. data/lib/spade/reactor.rb +0 -159
  32. data/lib/spade/remote.rb +0 -99
  33. data/lib/spade/repository.rb +0 -18
  34. data/lib/spade/server.rb +0 -66
  35. data/lib/spade/shell.rb +0 -36
  36. data/lib/spade/templates/project/LICENSE +0 -19
  37. data/lib/spade/templates/project/README.md +0 -21
  38. data/lib/spade/templates/project/lib/main.js +0 -9
  39. data/lib/spade/templates/project/project.json +0 -31
  40. data/lib/spade/templates/project/tests/main-test.js +0 -8
  41. data/package.json +0 -27
  42. data/packages/coffee-script/.gitignore +0 -8
  43. data/packages/coffee-script/.npmignore +0 -11
  44. data/packages/coffee-script/Cakefile +0 -229
  45. data/packages/coffee-script/LICENSE +0 -22
  46. data/packages/coffee-script/README +0 -47
  47. data/packages/coffee-script/Rakefile +0 -78
  48. data/packages/coffee-script/bin/cake +0 -7
  49. data/packages/coffee-script/bin/coffee +0 -7
  50. data/packages/coffee-script/documentation/coffee/aliases.coffee +0 -11
  51. data/packages/coffee-script/documentation/coffee/array_comprehensions.coffee +0 -2
  52. data/packages/coffee-script/documentation/coffee/block_comment.coffee +0 -6
  53. data/packages/coffee-script/documentation/coffee/cake_tasks.coffee +0 -9
  54. data/packages/coffee-script/documentation/coffee/classes.coffee +0 -25
  55. data/packages/coffee-script/documentation/coffee/comparisons.coffee +0 -5
  56. data/packages/coffee-script/documentation/coffee/conditionals.coffee +0 -13
  57. data/packages/coffee-script/documentation/coffee/default_args.coffee +0 -8
  58. data/packages/coffee-script/documentation/coffee/do.coffee +0 -4
  59. data/packages/coffee-script/documentation/coffee/embedded.coffee +0 -5
  60. data/packages/coffee-script/documentation/coffee/existence.coffee +0 -10
  61. data/packages/coffee-script/documentation/coffee/expressions.coffee +0 -9
  62. data/packages/coffee-script/documentation/coffee/expressions_assignment.coffee +0 -3
  63. data/packages/coffee-script/documentation/coffee/expressions_comprehension.coffee +0 -3
  64. data/packages/coffee-script/documentation/coffee/expressions_try.coffee +0 -7
  65. data/packages/coffee-script/documentation/coffee/fat_arrow.coffee +0 -6
  66. data/packages/coffee-script/documentation/coffee/functions.coffee +0 -2
  67. data/packages/coffee-script/documentation/coffee/heredocs.coffee +0 -7
  68. data/packages/coffee-script/documentation/coffee/heregexes.coffee +0 -11
  69. data/packages/coffee-script/documentation/coffee/interpolation.coffee +0 -6
  70. data/packages/coffee-script/documentation/coffee/multiple_return_values.coffee +0 -7
  71. data/packages/coffee-script/documentation/coffee/object_comprehensions.coffee +0 -4
  72. data/packages/coffee-script/documentation/coffee/object_extraction.coffee +0 -13
  73. data/packages/coffee-script/documentation/coffee/objects_and_arrays.coffee +0 -19
  74. data/packages/coffee-script/documentation/coffee/objects_reserved.coffee +0 -5
  75. data/packages/coffee-script/documentation/coffee/overview.coffee +0 -28
  76. data/packages/coffee-script/documentation/coffee/parallel_assignment.coffee +0 -6
  77. data/packages/coffee-script/documentation/coffee/patterns_and_splats.coffee +0 -7
  78. data/packages/coffee-script/documentation/coffee/prototypes.coffee +0 -3
  79. data/packages/coffee-script/documentation/coffee/range_comprehensions.coffee +0 -2
  80. data/packages/coffee-script/documentation/coffee/scope.coffee +0 -5
  81. data/packages/coffee-script/documentation/coffee/slices.coffee +0 -7
  82. data/packages/coffee-script/documentation/coffee/soaks.coffee +0 -1
  83. data/packages/coffee-script/documentation/coffee/splats.coffee +0 -27
  84. data/packages/coffee-script/documentation/coffee/splices.coffee +0 -5
  85. data/packages/coffee-script/documentation/coffee/strings.coffee +0 -8
  86. data/packages/coffee-script/documentation/coffee/switch.coffee +0 -10
  87. data/packages/coffee-script/documentation/coffee/try.coffee +0 -8
  88. data/packages/coffee-script/documentation/coffee/while.coffee +0 -10
  89. data/packages/coffee-script/documentation/css/docs.css +0 -374
  90. data/packages/coffee-script/documentation/css/idle.css +0 -64
  91. data/packages/coffee-script/documentation/docs/browser.html +0 -25
  92. data/packages/coffee-script/documentation/docs/cake.html +0 -43
  93. data/packages/coffee-script/documentation/docs/coffee-script.html +0 -51
  94. data/packages/coffee-script/documentation/docs/command.html +0 -161
  95. data/packages/coffee-script/documentation/docs/docco.css +0 -186
  96. data/packages/coffee-script/documentation/docs/grammar.html +0 -399
  97. data/packages/coffee-script/documentation/docs/helpers.html +0 -31
  98. data/packages/coffee-script/documentation/docs/index.html +0 -3
  99. data/packages/coffee-script/documentation/docs/lexer.html +0 -490
  100. data/packages/coffee-script/documentation/docs/nodes.html +0 -1338
  101. data/packages/coffee-script/documentation/docs/optparse.html +0 -78
  102. data/packages/coffee-script/documentation/docs/repl.html +0 -24
  103. data/packages/coffee-script/documentation/docs/rewriter.html +0 -251
  104. data/packages/coffee-script/documentation/docs/scope.html +0 -54
  105. data/packages/coffee-script/documentation/docs/underscore.html +0 -295
  106. data/packages/coffee-script/documentation/images/background.png +0 -0
  107. data/packages/coffee-script/documentation/images/banding.png +0 -0
  108. data/packages/coffee-script/documentation/images/button_bg.png +0 -0
  109. data/packages/coffee-script/documentation/images/button_bg_dark.gif +0 -0
  110. data/packages/coffee-script/documentation/images/button_bg_green.gif +0 -0
  111. data/packages/coffee-script/documentation/images/favicon.ico +0 -0
  112. data/packages/coffee-script/documentation/images/logo.png +0 -0
  113. data/packages/coffee-script/documentation/images/screenshadow.png +0 -0
  114. data/packages/coffee-script/documentation/index.html.erb +0 -1607
  115. data/packages/coffee-script/documentation/js/aliases.js +0 -17
  116. data/packages/coffee-script/documentation/js/array_comprehensions.js +0 -6
  117. data/packages/coffee-script/documentation/js/block_comment.js +0 -4
  118. data/packages/coffee-script/documentation/js/cake_tasks.js +0 -10
  119. data/packages/coffee-script/documentation/js/classes.js +0 -44
  120. data/packages/coffee-script/documentation/js/comparisons.js +0 -3
  121. data/packages/coffee-script/documentation/js/conditionals.js +0 -12
  122. data/packages/coffee-script/documentation/js/default_args.js +0 -7
  123. data/packages/coffee-script/documentation/js/do.js +0 -10
  124. data/packages/coffee-script/documentation/js/embedded.js +0 -4
  125. data/packages/coffee-script/documentation/js/existence.js +0 -6
  126. data/packages/coffee-script/documentation/js/expressions.js +0 -15
  127. data/packages/coffee-script/documentation/js/expressions_assignment.js +0 -2
  128. data/packages/coffee-script/documentation/js/expressions_comprehension.js +0 -9
  129. data/packages/coffee-script/documentation/js/expressions_try.js +0 -7
  130. data/packages/coffee-script/documentation/js/fat_arrow.js +0 -9
  131. data/packages/coffee-script/documentation/js/functions.js +0 -7
  132. data/packages/coffee-script/documentation/js/heredocs.js +0 -2
  133. data/packages/coffee-script/documentation/js/heregexes.js +0 -2
  134. data/packages/coffee-script/documentation/js/interpolation.js +0 -4
  135. data/packages/coffee-script/documentation/js/multiple_return_values.js +0 -5
  136. data/packages/coffee-script/documentation/js/object_comprehensions.js +0 -15
  137. data/packages/coffee-script/documentation/js/object_extraction.js +0 -10
  138. data/packages/coffee-script/documentation/js/objects_and_arrays.js +0 -17
  139. data/packages/coffee-script/documentation/js/objects_reserved.js +0 -4
  140. data/packages/coffee-script/documentation/js/overview.js +0 -35
  141. data/packages/coffee-script/documentation/js/parallel_assignment.js +0 -4
  142. data/packages/coffee-script/documentation/js/patterns_and_splats.js +0 -4
  143. data/packages/coffee-script/documentation/js/prototypes.js +0 -3
  144. data/packages/coffee-script/documentation/js/range_comprehensions.js +0 -9
  145. data/packages/coffee-script/documentation/js/scope.js +0 -8
  146. data/packages/coffee-script/documentation/js/slices.js +0 -4
  147. data/packages/coffee-script/documentation/js/soaks.js +0 -2
  148. data/packages/coffee-script/documentation/js/splats.js +0 -15
  149. data/packages/coffee-script/documentation/js/splices.js +0 -3
  150. data/packages/coffee-script/documentation/js/strings.js +0 -2
  151. data/packages/coffee-script/documentation/js/switch.js +0 -23
  152. data/packages/coffee-script/documentation/js/try.js +0 -8
  153. data/packages/coffee-script/documentation/js/while.js +0 -18
  154. data/packages/coffee-script/documentation/vendor/jquery-1.4.2.js +0 -6240
  155. data/packages/coffee-script/examples/beautiful_code/binary_search.coffee +0 -16
  156. data/packages/coffee-script/examples/beautiful_code/quicksort_runtime.coffee +0 -13
  157. data/packages/coffee-script/examples/beautiful_code/regular_expression_matcher.coffee +0 -34
  158. data/packages/coffee-script/examples/blocks.coffee +0 -54
  159. data/packages/coffee-script/examples/code.coffee +0 -167
  160. data/packages/coffee-script/examples/computer_science/README +0 -4
  161. data/packages/coffee-script/examples/computer_science/binary_search.coffee +0 -25
  162. data/packages/coffee-script/examples/computer_science/bubble_sort.coffee +0 -11
  163. data/packages/coffee-script/examples/computer_science/linked_list.coffee +0 -108
  164. data/packages/coffee-script/examples/computer_science/luhn_algorithm.coffee +0 -36
  165. data/packages/coffee-script/examples/computer_science/merge_sort.coffee +0 -19
  166. data/packages/coffee-script/examples/computer_science/selection_sort.coffee +0 -23
  167. data/packages/coffee-script/examples/poignant.coffee +0 -181
  168. data/packages/coffee-script/examples/potion.coffee +0 -206
  169. data/packages/coffee-script/examples/underscore.coffee +0 -682
  170. data/packages/coffee-script/examples/web_server.coffee +0 -12
  171. data/packages/coffee-script/extras/EXTRAS +0 -7
  172. data/packages/coffee-script/extras/coffee-script.js +0 -8
  173. data/packages/coffee-script/extras/jsl.conf +0 -44
  174. data/packages/coffee-script/index.html +0 -2515
  175. data/packages/coffee-script/lib/browser.js +0 -52
  176. data/packages/coffee-script/lib/cake.js +0 -76
  177. data/packages/coffee-script/lib/coffee-script.js +0 -82
  178. data/packages/coffee-script/lib/command.js +0 -263
  179. data/packages/coffee-script/lib/grammar.js +0 -581
  180. data/packages/coffee-script/lib/helpers.js +0 -66
  181. data/packages/coffee-script/lib/index.js +0 -8
  182. data/packages/coffee-script/lib/lexer.js +0 -633
  183. data/packages/coffee-script/lib/nodes.js +0 -2165
  184. data/packages/coffee-script/lib/optparse.js +0 -111
  185. data/packages/coffee-script/lib/parser.js +0 -649
  186. data/packages/coffee-script/lib/repl.js +0 -42
  187. data/packages/coffee-script/lib/rewriter.js +0 -353
  188. data/packages/coffee-script/lib/scope.js +0 -120
  189. data/packages/coffee-script/lib/spade-format.js +0 -45
  190. data/packages/coffee-script/package.json +0 -26
  191. data/packages/coffee-script/src/browser.coffee +0 -43
  192. data/packages/coffee-script/src/cake.coffee +0 -69
  193. data/packages/coffee-script/src/coffee-script.coffee +0 -92
  194. data/packages/coffee-script/src/command.coffee +0 -214
  195. data/packages/coffee-script/src/grammar.coffee +0 -590
  196. data/packages/coffee-script/src/helpers.coffee +0 -56
  197. data/packages/coffee-script/src/index.coffee +0 -2
  198. data/packages/coffee-script/src/lexer.coffee +0 -653
  199. data/packages/coffee-script/src/nodes.coffee +0 -1754
  200. data/packages/coffee-script/src/optparse.coffee +0 -99
  201. data/packages/coffee-script/src/repl.coffee +0 -42
  202. data/packages/coffee-script/src/rewriter.coffee +0 -326
  203. data/packages/coffee-script/src/scope.coffee +0 -94
  204. data/packages/coffee-script/test/arguments.coffee +0 -127
  205. data/packages/coffee-script/test/assignment.coffee +0 -98
  206. data/packages/coffee-script/test/break.coffee +0 -18
  207. data/packages/coffee-script/test/comments.coffee +0 -201
  208. data/packages/coffee-script/test/conditionals.coffee +0 -181
  209. data/packages/coffee-script/test/exception_handling.coffee +0 -90
  210. data/packages/coffee-script/test/helpers.coffee +0 -96
  211. data/packages/coffee-script/test/importing.coffee +0 -18
  212. data/packages/coffee-script/test/operators.coffee +0 -225
  213. data/packages/coffee-script/test/ranges_slices_and_splices.coffee +0 -186
  214. data/packages/coffee-script/test/regular_expressions.coffee +0 -56
  215. data/packages/coffee-script/test/test.html +0 -123
  216. data/packages/coffee-script/test/test_chaining.coffee +0 -77
  217. data/packages/coffee-script/test/test_classes.coffee +0 -372
  218. data/packages/coffee-script/test/test_compilation.coffee +0 -26
  219. data/packages/coffee-script/test/test_comprehensions.coffee +0 -318
  220. data/packages/coffee-script/test/test_existence.coffee +0 -165
  221. data/packages/coffee-script/test/test_functions.coffee +0 -379
  222. data/packages/coffee-script/test/test_heredocs.coffee +0 -111
  223. data/packages/coffee-script/test/test_literals.coffee +0 -270
  224. data/packages/coffee-script/test/test_option_parser.coffee +0 -27
  225. data/packages/coffee-script/test/test_pattern_matching.coffee +0 -162
  226. data/packages/coffee-script/test/test_returns.coffee +0 -63
  227. data/packages/coffee-script/test/test_splats.coffee +0 -102
  228. data/packages/coffee-script/test/test_strings.coffee +0 -118
  229. data/packages/coffee-script/test/test_switch.coffee +0 -103
  230. data/packages/coffee-script/test/test_while.coffee +0 -71
  231. data/packages/ivory/LICENSE.txt +0 -1
  232. data/packages/ivory/README.md +0 -19
  233. data/packages/ivory/lib/buffer.js +0 -111
  234. data/packages/ivory/lib/events.js +0 -137
  235. data/packages/ivory/lib/fs.js +0 -266
  236. data/packages/ivory/lib/main.js +0 -13
  237. data/packages/ivory/lib/path.js +0 -158
  238. data/packages/ivory/lib/ruby/buffer.rb +0 -145
  239. data/packages/ivory/lib/ruby/constants.rb +0 -585
  240. data/packages/ivory/lib/ruby/events.rb +0 -32
  241. data/packages/ivory/lib/ruby/fs.rb +0 -245
  242. data/packages/ivory/lib/ruby/process.rb +0 -28
  243. data/packages/ivory/lib/stream.js +0 -115
  244. data/packages/ivory/lib/util.js +0 -414
  245. data/packages/ivory/package.json +0 -11
  246. data/packages/jquery/main.js +0 -7179
  247. data/packages/jquery/package.json +0 -10
  248. data/packages/json/lib/main.js +0 -14
  249. data/packages/json/package.json +0 -8
  250. data/packages/lproj/README.md +0 -77
  251. data/packages/lproj/examples/demo-app/en.lproj/localized.strings +0 -2
  252. data/packages/lproj/examples/demo-app/fr.lproj/localized.strings +0 -3
  253. data/packages/lproj/examples/demo-app/index.html +0 -8
  254. data/packages/lproj/examples/demo-app/lib/main.js +0 -7
  255. data/packages/lproj/examples/demo-app/package.json +0 -9
  256. data/packages/lproj/lib/main.js +0 -78
  257. data/packages/lproj/lib/strings-format.js +0 -6
  258. data/packages/lproj/package.json +0 -9
  259. data/packages/optparse/README.md +0 -161
  260. data/packages/optparse/TODO +0 -1
  261. data/packages/optparse/examples/browser-test.html +0 -75
  262. data/packages/optparse/examples/nodejs-test.js +0 -90
  263. data/packages/optparse/lib/optparse.js +0 -309
  264. data/packages/optparse/package.json +0 -13
  265. data/packages/optparse/seed.yml +0 -5
  266. data/packages/text/lib/main.js +0 -8
  267. data/packages/text/package.json +0 -9
  268. data/packages/web-file/README.md +0 -7
  269. data/packages/web-file/lib/errors.js +0 -32
  270. data/packages/web-file/lib/file-reader.js +0 -10
  271. data/packages/web-file/lib/file-system.js +0 -234
  272. data/packages/web-file/lib/file-writer.js +0 -10
  273. data/packages/web-file/lib/file.js +0 -9
  274. data/packages/web-file/lib/main.js +0 -34
  275. data/packages/web-file/lib/platform.js +0 -25
  276. data/packages/web-file/lib/ruby/file.rb +0 -252
  277. data/packages/web-file/lib/ruby/file_reader.rb +0 -69
  278. data/packages/web-file/lib/ruby/file_system.rb +0 -134
  279. data/packages/web-file/lib/ruby/file_writer.rb +0 -78
  280. data/packages/web-file/package.json +0 -12
  281. data/packages/web-typed-array/README.md +0 -7
  282. data/packages/web-typed-array/lib/array-buffer-view.js +0 -9
  283. data/packages/web-typed-array/lib/array-buffer.js +0 -7
  284. data/packages/web-typed-array/lib/main.js +0 -33
  285. data/packages/web-typed-array/lib/platform.js +0 -20
  286. data/packages/web-typed-array/lib/ruby/array_buffer.rb +0 -31
  287. data/packages/web-typed-array/lib/ruby/array_buffer_view.rb +0 -130
  288. data/packages/web-typed-array/lib/ruby/typed_array.rb +0 -133
  289. data/packages/web-typed-array/lib/typed-array.js +0 -26
  290. data/packages/web-typed-array/package.json +0 -9
  291. data/spec/cli/build_spec.rb +0 -59
  292. data/spec/cli/install_spec.rb +0 -120
  293. data/spec/cli/installed_spec.rb +0 -55
  294. data/spec/cli/list_spec.rb +0 -75
  295. data/spec/cli/login_spec.rb +0 -76
  296. data/spec/cli/new_spec.rb +0 -5
  297. data/spec/cli/owner_spec.rb +0 -115
  298. data/spec/cli/push_spec.rb +0 -74
  299. data/spec/cli/uninstall_spec.rb +0 -58
  300. data/spec/cli/unpack_spec.rb +0 -73
  301. data/spec/cli/unyank_spec.rb +0 -74
  302. data/spec/cli/update_spec.rb +0 -8
  303. data/spec/cli/yank_spec.rb +0 -74
  304. data/spec/credentials_spec.rb +0 -24
  305. data/spec/fixtures/coffee-1.0.1.pre.spd +0 -0
  306. data/spec/fixtures/core-test-0.4.3.spd +0 -0
  307. data/spec/fixtures/core-test/bin/cot +0 -3
  308. data/spec/fixtures/core-test/lib/main.js +0 -1
  309. data/spec/fixtures/core-test/resources/runner.css +0 -0
  310. data/spec/fixtures/core-test/tests/test.js +0 -1
  311. data/spec/fixtures/ivory-0.0.1.spd +0 -0
  312. data/spec/fixtures/jquery-1.4.3.spd +0 -0
  313. data/spec/fixtures/optparse-1.0.1.spd +0 -0
  314. data/spec/fixtures/package.json +0 -30
  315. data/spec/gauntlet_spec.rb +0 -27
  316. data/spec/javascript/async-test.js +0 -123
  317. data/spec/javascript/compiler/javascript.js +0 -13
  318. data/spec/javascript/compiler/ruby.js +0 -14
  319. data/spec/javascript/loader-test.js +0 -64
  320. data/spec/javascript/normalize-test.js +0 -73
  321. data/spec/javascript/packages-test.js +0 -44
  322. data/spec/javascript/relative-require-test.js +0 -72
  323. data/spec/javascript/require-test.js +0 -117
  324. data/spec/javascript/sandbox/compile.js +0 -37
  325. data/spec/javascript/sandbox/creation.js +0 -44
  326. data/spec/javascript/sandbox/format.js +0 -79
  327. data/spec/javascript/sandbox/misc.js +0 -57
  328. data/spec/javascript/sandbox/preprocessor.js +0 -81
  329. data/spec/javascript/sandbox/require.js +0 -48
  330. data/spec/javascript/sandbox/run-command.js +0 -21
  331. data/spec/javascript/spade/externs.js +0 -14
  332. data/spec/javascript/spade/load-factory.js +0 -15
  333. data/spec/javascript/spade/misc.js +0 -23
  334. data/spec/javascript/spade/ready.js +0 -12
  335. data/spec/javascript/spade/register.js +0 -13
  336. data/spec/javascript_spec.rb +0 -7
  337. data/spec/package_spec.rb +0 -267
  338. data/spec/spec_helper.rb +0 -30
  339. data/spec/support/cli.rb +0 -94
  340. data/spec/support/core_test.rb +0 -59
  341. data/spec/support/fake.rb +0 -44
  342. data/spec/support/fake_gem_server.rb +0 -66
  343. data/spec/support/fake_gemcutter.rb +0 -49
  344. data/spec/support/matchers.rb +0 -31
  345. data/spec/support/path.rb +0 -54
  346. data/test-spade.html +0 -8
@@ -1,1754 +0,0 @@
1
- # `nodes.coffee` contains all of the node classes for the syntax tree. Most
2
- # nodes are created as the result of actions in the [grammar](grammar.html),
3
- # but some are created by other nodes as a method of code generation. To convert
4
- # the syntax tree into a string of JavaScript code, call `compile()` on the root.
5
-
6
- {Scope} = require './scope'
7
-
8
- # Import the helpers we plan to use.
9
- {compact, flatten, extend, merge, del, starts, ends, last} = require './helpers'
10
-
11
- exports.extend = extend # for parser
12
-
13
- # Constant functions for nodes that don't need customization.
14
- YES = -> yes
15
- NO = -> no
16
- THIS = -> this
17
- NEGATE = -> @negated = not @negated; this
18
-
19
- #### Base
20
-
21
- # The **Base** is the abstract base class for all nodes in the syntax tree.
22
- # Each subclass implements the `compileNode` method, which performs the
23
- # code generation for that node. To compile a node to JavaScript,
24
- # call `compile` on it, which wraps `compileNode` in some generic extra smarts,
25
- # to know when the generated code needs to be wrapped up in a closure.
26
- # An options hash is passed and cloned throughout, containing information about
27
- # the environment from higher in the tree (such as if a returned value is
28
- # being requested by the surrounding function), information about the current
29
- # scope, and indentation level.
30
- exports.Base = class Base
31
-
32
- # Common logic for determining whether to wrap this node in a closure before
33
- # compiling it, or to compile directly. We need to wrap if this node is a
34
- # *statement*, and it's not a *pureStatement*, and we're not at
35
- # the top level of a block (which would be unnecessary), and we haven't
36
- # already been asked to return the result (because statements know how to
37
- # return results).
38
- compile: (o, lvl) ->
39
- o = extend {}, o
40
- o.level = lvl if lvl
41
- node = @unfoldSoak(o) or this
42
- node.tab = o.indent
43
- if o.level is LEVEL_TOP or not node.isStatement(o)
44
- node.compileNode o
45
- else
46
- node.compileClosure o
47
-
48
- # Statements converted into expressions via closure-wrapping share a scope
49
- # object with their parent closure, to preserve the expected lexical scope.
50
- compileClosure: (o) ->
51
- if @jumps()
52
- throw SyntaxError 'cannot use a pure statement in an expression.'
53
- o.sharedScope = yes
54
- Closure.wrap(this).compileNode o
55
-
56
- # If the code generation wishes to use the result of a complex expression
57
- # in multiple places, ensure that the expression is only ever evaluated once,
58
- # by assigning it to a temporary variable. Pass a level to precompile.
59
- cache: (o, level, reused) ->
60
- unless @isComplex()
61
- ref = if level then @compile o, level else this
62
- [ref, ref]
63
- else
64
- ref = new Literal reused or o.scope.freeVariable 'ref'
65
- sub = new Assign ref, this
66
- if level then [sub.compile(o, level), ref.value] else [sub, ref]
67
-
68
- # Compile to a source/variable pair suitable for looping.
69
- compileLoopReference: (o, name) ->
70
- src = tmp = @compile o, LEVEL_LIST
71
- unless -Infinity < +src < Infinity or IDENTIFIER.test(src) and o.scope.check(src, yes)
72
- src = "#{ tmp = o.scope.freeVariable name } = #{src}"
73
- [src, tmp]
74
-
75
- # Construct a node that returns the current node's result.
76
- # Note that this is overridden for smarter behavior for
77
- # many statement nodes (e.g. If, For)...
78
- makeReturn: ->
79
- new Return this
80
-
81
- # Does this node, or any of its children, contain a node of a certain kind?
82
- # Recursively traverses down the *children* of the nodes, yielding to a block
83
- # and returning true when the block finds a match. `contains` does not cross
84
- # scope boundaries.
85
- contains: (pred) ->
86
- contains = no
87
- @traverseChildren no, (node) ->
88
- if pred node
89
- contains = yes
90
- return no
91
- contains
92
-
93
- # Is this node of a certain type, or does it contain the type?
94
- containsType: (type) ->
95
- this instanceof type or @contains (node) -> node instanceof type
96
-
97
- # Pull out the last non-comment node of a node list.
98
- lastNonComment: (list) ->
99
- i = list.length
100
- return list[i] while i-- when list[i] not instanceof Comment
101
- null
102
-
103
- # `toString` representation of the node, for inspecting the parse tree.
104
- # This is what `coffee --nodes` prints out.
105
- toString: (idt = '', name = @constructor.name) ->
106
- tree = '\n' + idt + name
107
- tree += '?' if @soak
108
- @eachChild (node) -> tree += node.toString idt + TAB
109
- tree
110
-
111
- # Passes each child to a function, breaking when the function returns `false`.
112
- eachChild: (func) ->
113
- return this unless @children
114
- for attr in @children when @[attr]
115
- for child in flatten [@[attr]]
116
- return this if func(child) is false
117
- this
118
-
119
- traverseChildren: (crossScope, func) ->
120
- @eachChild (child) ->
121
- return false if func(child) is false
122
- child.traverseChildren crossScope, func
123
-
124
- invert: ->
125
- new Op '!', this
126
-
127
- unwrapAll: ->
128
- node = this
129
- continue until node is node = node.unwrap()
130
- node
131
-
132
- # Default implementations of the common node properties and methods. Nodes
133
- # will override these with custom logic, if needed.
134
- children: []
135
-
136
- isStatement : NO
137
- jumps : NO
138
- isComplex : YES
139
- isChainable : NO
140
- isAssignable : NO
141
-
142
- unwrap : THIS
143
- unfoldSoak : NO
144
-
145
- # Is this node used to assign a certain variable?
146
- assigns: NO
147
-
148
- #### Expressions
149
-
150
- # The expressions body is the list of expressions that forms the body of an
151
- # indented block of code -- the implementation of a function, a clause in an
152
- # `if`, `switch`, or `try`, and so on...
153
- exports.Expressions = class Expressions extends Base
154
- constructor: (nodes) ->
155
- @expressions = compact flatten nodes or []
156
-
157
- children: ['expressions']
158
-
159
- # Tack an expression on to the end of this expression list.
160
- push: (node) ->
161
- @expressions.push node
162
- this
163
-
164
- # Remove and return the last expression of this expression list.
165
- pop: ->
166
- @expressions.pop()
167
-
168
- # Add an expression at the beginning of this expression list.
169
- unshift: (node) ->
170
- @expressions.unshift node
171
- this
172
-
173
- # If this Expressions consists of just a single node, unwrap it by pulling
174
- # it back out.
175
- unwrap: ->
176
- if @expressions.length is 1 then @expressions[0] else this
177
-
178
- # Is this an empty block of code?
179
- isEmpty: ->
180
- not @expressions.length
181
-
182
- isStatement: (o) ->
183
- for exp in @expressions when exp.isStatement o
184
- return yes
185
- no
186
-
187
- jumps: (o) ->
188
- for exp in @expressions
189
- return exp if exp.jumps o
190
-
191
- # An Expressions node does not return its entire body, rather it
192
- # ensures that the final expression is returned.
193
- makeReturn: ->
194
- len = @expressions.length
195
- while len--
196
- expr = @expressions[len]
197
- if expr not instanceof Comment
198
- @expressions[len] = expr.makeReturn()
199
- break
200
- this
201
-
202
- # An **Expressions** is the only node that can serve as the root.
203
- compile: (o = {}, level) ->
204
- if o.scope then super o, level else @compileRoot o
205
-
206
- # Compile all expressions within the **Expressions** body. If we need to
207
- # return the result, and it's an expression, simply return it. If it's a
208
- # statement, ask the statement to do so.
209
- compileNode: (o) ->
210
- @tab = o.indent
211
- top = o.level is LEVEL_TOP
212
- codes = []
213
- for node in @expressions
214
- node = node.unwrapAll()
215
- node = (node.unfoldSoak(o) or node)
216
- if top
217
- node.front = true
218
- code = node.compile o
219
- codes.push if node.isStatement o then code else @tab + code + ';'
220
- else
221
- codes.push node.compile o, LEVEL_LIST
222
- return codes.join '\n' if top
223
- code = codes.join(', ') or 'void 0'
224
- if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code
225
-
226
- # If we happen to be the top-level **Expressions**, wrap everything in
227
- # a safety closure, unless requested not to.
228
- # It would be better not to generate them in the first place, but for now,
229
- # clean up obvious double-parentheses.
230
- compileRoot: (o) ->
231
- o.indent = @tab = if o.bare then '' else TAB
232
- o.scope = new Scope null, this, null
233
- o.level = LEVEL_TOP
234
- code = @compileWithDeclarations o
235
- code = code.replace TRAILING_WHITESPACE, ''
236
- if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
237
-
238
- # Compile the expressions body for the contents of a function, with
239
- # declarations of all inner variables pushed up to the top.
240
- compileWithDeclarations: (o) ->
241
- code = post = ''
242
- for exp, i in @expressions
243
- exp = exp.unwrap()
244
- break unless exp instanceof Comment or exp instanceof Literal
245
- o = merge(o, level: LEVEL_TOP)
246
- if i
247
- rest = @expressions.splice i, @expressions.length
248
- code = @compileNode o
249
- @expressions = rest
250
- post = @compileNode o
251
- {scope} = o
252
- if scope.expressions is this
253
- if not o.globals and o.scope.hasDeclarations()
254
- code += "#{@tab}var #{ scope.declaredVariables().join(', ') };\n"
255
- if scope.hasAssignments
256
- code += "#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"
257
- code + post
258
-
259
- # Wrap up the given nodes as an **Expressions**, unless it already happens
260
- # to be one.
261
- @wrap: (nodes) ->
262
- return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
263
- new Expressions nodes
264
-
265
- #### Literal
266
-
267
- # Literals are static values that can be passed through directly into
268
- # JavaScript without translation, such as: strings, numbers,
269
- # `true`, `false`, `null`...
270
- exports.Literal = class Literal extends Base
271
- constructor: (@value) ->
272
-
273
- makeReturn: ->
274
- if @isStatement() then this else new Return this
275
-
276
- isAssignable: ->
277
- IDENTIFIER.test @value
278
-
279
- isStatement: ->
280
- @value in ['break', 'continue', 'debugger']
281
-
282
- isComplex: NO
283
-
284
- assigns: (name) ->
285
- name is @value
286
-
287
- jumps: (o) ->
288
- return no unless @isStatement()
289
- if not (o and (o.loop or o.block and (@value isnt 'continue'))) then this else no
290
-
291
- compileNode: (o) ->
292
- code = if @value.reserved then "\"#{@value}\"" else @value
293
- if @isStatement() then "#{@tab}#{code};" else code
294
-
295
- toString: ->
296
- ' "' + @value + '"'
297
-
298
- #### Return
299
-
300
- # A `return` is a *pureStatement* -- wrapping it in a closure wouldn't
301
- # make sense.
302
- exports.Return = class Return extends Base
303
- constructor: (@expression) ->
304
-
305
- children: ['expression']
306
-
307
- isStatement: YES
308
- makeReturn: THIS
309
- jumps: THIS
310
-
311
- compile: (o, level) ->
312
- expr = @expression?.makeReturn()
313
- if expr and expr not instanceof Return then expr.compile o, level else super o, level
314
-
315
- compileNode: (o) ->
316
- @tab + "return#{ if @expression then ' ' + @expression.compile(o, LEVEL_PAREN) else '' };"
317
-
318
- #### Value
319
-
320
- # A value, variable or literal or parenthesized, indexed or dotted into,
321
- # or vanilla.
322
- exports.Value = class Value extends Base
323
- constructor: (base, props, tag) ->
324
- return base if not props and base instanceof Value
325
- @base = base
326
- @properties = props or []
327
- @[tag] = true if tag
328
- return this
329
-
330
- children: ['base', 'properties']
331
-
332
- # Add a property access to the list.
333
- push: (prop) ->
334
- @properties.push prop
335
- this
336
-
337
- hasProperties: ->
338
- !!@properties.length
339
-
340
- # Some boolean checks for the benefit of other nodes.
341
- isArray : -> not @properties.length and @base instanceof Arr
342
- isComplex : -> @hasProperties() or @base.isComplex()
343
- isAssignable : -> @hasProperties() or @base.isAssignable()
344
- isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value
345
- isAtomic : ->
346
- for node in @properties.concat @base
347
- return no if node.soak or node instanceof Call
348
- yes
349
-
350
- isStatement : (o) -> not @properties.length and @base.isStatement o
351
- assigns : (name) -> not @properties.length and @base.assigns name
352
- jumps : (o) -> not @properties.length and @base.jumps o
353
-
354
- isObject: (onlyGenerated) ->
355
- return no if @properties.length
356
- (@base instanceof Obj) and (not onlyGenerated or @base.generated)
357
-
358
- isSplice: ->
359
- last(@properties) instanceof Slice
360
-
361
- makeReturn: ->
362
- if @properties.length then super() else @base.makeReturn()
363
-
364
- # The value can be unwrapped as its inner node, if there are no attached
365
- # properties.
366
- unwrap: ->
367
- if @properties.length then this else @base
368
-
369
- # A reference has base part (`this` value) and name part.
370
- # We cache them separately for compiling complex expressions.
371
- # `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c`
372
- cacheReference: (o) ->
373
- name = last @properties
374
- if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
375
- return [this, this] # `a` `a.b`
376
- base = new Value @base, @properties.slice 0, -1
377
- if base.isComplex() # `a().b`
378
- bref = new Literal o.scope.freeVariable 'base'
379
- base = new Value new Parens new Assign bref, base
380
- return [base, bref] unless name # `a()`
381
- if name.isComplex() # `a[b()]`
382
- nref = new Literal o.scope.freeVariable 'name'
383
- name = new Index new Assign nref, name.index
384
- nref = new Index nref
385
- [base.push(name), new Value(bref or base.base, [nref or name])]
386
-
387
- # We compile a value to JavaScript by compiling and joining each property.
388
- # Things get much more interesting if the chain of properties has *soak*
389
- # operators `?.` interspersed. Then we have to take care not to accidentally
390
- # evaluate anything twice when building the soak chain.
391
- compileNode: (o) ->
392
- @base.front = @front
393
- props = @properties
394
- code = @base.compile o, if props.length then LEVEL_ACCESS else null
395
- code = "(#{code})" if props[0] instanceof Access and @isSimpleNumber()
396
- code += prop.compile o for prop in props
397
- code
398
-
399
- # Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
400
- unfoldSoak: (o) ->
401
- if ifn = @base.unfoldSoak o
402
- Array::push.apply ifn.body.properties, @properties
403
- return ifn
404
- for prop, i in @properties when prop.soak
405
- prop.soak = off
406
- fst = new Value @base, @properties.slice 0, i
407
- snd = new Value @base, @properties.slice i
408
- if fst.isComplex()
409
- ref = new Literal o.scope.freeVariable 'ref'
410
- fst = new Parens new Assign ref, fst
411
- snd.base = ref
412
- return new If new Existence(fst), snd, soak: on
413
- null
414
-
415
- #### Comment
416
-
417
- # CoffeeScript passes through block comments as JavaScript block comments
418
- # at the same position.
419
- exports.Comment = class Comment extends Base
420
- constructor: (@comment) ->
421
-
422
- isStatement: YES
423
- makeReturn: THIS
424
-
425
- compileNode: (o, level) ->
426
- code = '/*' + multident(@comment, @tab) + '*/'
427
- code = o.indent + code if (level or o.level) is LEVEL_TOP
428
- code
429
-
430
- #### Call
431
-
432
- # Node for a function invocation. Takes care of converting `super()` calls into
433
- # calls against the prototype's function of the same name.
434
- exports.Call = class Call extends Base
435
- constructor: (variable, @args = [], @soak) ->
436
- @isNew = false
437
- @isSuper = variable is 'super'
438
- @variable = if @isSuper then null else variable
439
-
440
- children: ['variable', 'args']
441
-
442
- # Tag this invocation as creating a new instance.
443
- newInstance: ->
444
- base = @variable.base or @variable
445
- if base instanceof Call
446
- base.newInstance()
447
- else
448
- @isNew = true
449
- this
450
-
451
- # Grab the reference to the superclass's implementation of the current
452
- # method.
453
- superReference: (o) ->
454
- {method} = o.scope
455
- throw SyntaxError 'cannot call super outside of a function.' unless method
456
- {name} = method
457
- throw SyntaxError 'cannot call super on an anonymous function.' unless name
458
- if method.klass
459
- "#{method.klass}.__super__.#{name}"
460
- else
461
- "#{name}.__super__.constructor"
462
-
463
- # Soaked chained invocations unfold into if/else ternary structures.
464
- unfoldSoak: (o) ->
465
- if @soak
466
- if @variable
467
- return ifn if ifn = unfoldSoak o, this, 'variable'
468
- [left, rite] = new Value(@variable).cacheReference o
469
- else
470
- left = new Literal @superReference o
471
- rite = new Value left
472
- rite = new Call rite, @args
473
- rite.isNew = @isNew
474
- left = new Literal "typeof #{ left.compile o } === \"function\""
475
- return new If left, new Value(rite), soak: yes
476
- call = this
477
- list = []
478
- loop
479
- if call.variable instanceof Call
480
- list.push call
481
- call = call.variable
482
- continue
483
- break unless call.variable instanceof Value
484
- list.push call
485
- break unless (call = call.variable.base) instanceof Call
486
- for call in list.reverse()
487
- if ifn
488
- if call.variable instanceof Call
489
- call.variable = ifn
490
- else
491
- call.variable.base = ifn
492
- ifn = unfoldSoak o, call, 'variable'
493
- ifn
494
-
495
- # Compile a vanilla function call.
496
- compileNode: (o) ->
497
- @variable?.front = @front
498
- if code = Splat.compileSplattedArray o, @args, true
499
- return @compileSplat o, code
500
- args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
501
- if @isSuper
502
- @superReference(o) + ".call(this#{ args and ', ' + args })"
503
- else
504
- (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})"
505
-
506
- # `super()` is converted into a call against the superclass's implementation
507
- # of the current function.
508
- compileSuper: (args, o) ->
509
- "#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#{args})"
510
-
511
- # If you call a function with a splat, it's converted into a JavaScript
512
- # `.apply()` call to allow an array of arguments to be passed.
513
- # If it's a constructor, then things get real tricky. We have to inject an
514
- # inner constructor in order to be able to pass the varargs.
515
- compileSplat: (o, splatArgs) ->
516
- return "#{ @superReference o }.apply(this, #{splatArgs})" if @isSuper
517
- if @isNew
518
- idt = @tab + TAB
519
- return """
520
- (function(func, args, ctor) {
521
- #{idt}ctor.prototype = func.prototype;
522
- #{idt}var child = new ctor, result = func.apply(child, args);
523
- #{idt}return typeof result === "object" ? result : child;
524
- #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
525
- """
526
- base = new Value @variable
527
- if (name = base.properties.pop()) and base.isComplex()
528
- ref = o.scope.freeVariable 'ref'
529
- fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
530
- else
531
- fun = base.compile o, LEVEL_ACCESS
532
- if name
533
- ref = fun
534
- fun += name.compile o
535
- else
536
- ref = 'null'
537
- "#{fun}.apply(#{ref}, #{splatArgs})"
538
-
539
- #### Extends
540
-
541
- # Node to extend an object's prototype with an ancestor object.
542
- # After `goog.inherits` from the
543
- # [Closure Library](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html).
544
- exports.Extends = class Extends extends Base
545
- constructor: (@child, @parent) ->
546
-
547
- children: ['child', 'parent']
548
-
549
- # Hooks one constructor into another's prototype chain.
550
- compile: (o) ->
551
- utility 'hasProp'
552
- new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o
553
-
554
- #### Access
555
-
556
- # A `.` access into a property of a value, or the `::` shorthand for
557
- # an access into the object's prototype.
558
- exports.Access = class Access extends Base
559
- constructor: (@name, tag) ->
560
- @name.asKey = yes
561
- @proto = if tag is 'proto' then '.prototype' else ''
562
- @soak = tag is 'soak'
563
-
564
- children: ['name']
565
-
566
- compile: (o) ->
567
- name = @name.compile o
568
- @proto + if IS_STRING.test name then "[#{name}]" else ".#{name}"
569
-
570
- isComplex: NO
571
-
572
- #### Index
573
-
574
- # A `[ ... ]` indexed access into an array or object.
575
- exports.Index = class Index extends Base
576
- constructor: (@index) ->
577
-
578
- children: ['index']
579
-
580
- compile: (o) ->
581
- (if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]"
582
-
583
- isComplex: ->
584
- @index.isComplex()
585
-
586
- #### Range
587
-
588
- # A range literal. Ranges can be used to extract portions (slices) of arrays,
589
- # to specify a range for comprehensions, or as a value, to be expanded into the
590
- # corresponding array of integers at runtime.
591
- exports.Range = class Range extends Base
592
-
593
- children: ['from', 'to']
594
-
595
- constructor: (@from, @to, tag) ->
596
- @exclusive = tag is 'exclusive'
597
- @equals = if @exclusive then '' else '='
598
-
599
- # Compiles the range's source variables -- where it starts and where it ends.
600
- # But only if they need to be cached to avoid double evaluation.
601
- compileVariables: (o) ->
602
- o = merge(o, top: true)
603
- [@from, @fromVar] = @from.cache o, LEVEL_LIST
604
- [@to, @toVar] = @to.cache o, LEVEL_LIST
605
- [@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
606
- parts = []
607
- parts.push @from if @from isnt @fromVar
608
- parts.push @to if @to isnt @toVar
609
-
610
- # When compiled normally, the range returns the contents of the *for loop*
611
- # needed to iterate over the values in the range. Used by comprehensions.
612
- compileNode: (o) ->
613
- @compileVariables o
614
- return @compileArray(o) unless o.index
615
- return @compileSimple(o) if @fromNum and @toNum
616
- idx = del o, 'index'
617
- step = del o, 'step'
618
- vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
619
- intro = "(#{@fromVar} <= #{@toVar} ? #{idx}"
620
- compare = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})"
621
- stepPart = if step then step.compile(o) else '1'
622
- incr = if step then "#{idx} += #{stepPart}" else "#{intro} += #{stepPart} : #{idx} -= #{stepPart})"
623
- "#{vars}; #{compare}; #{incr}"
624
-
625
- # Compile a simple range comprehension, with integers.
626
- compileSimple: (o) ->
627
- [from, to] = [+@fromNum, +@toNum]
628
- idx = del o, 'index'
629
- step = del o, 'step'
630
- step and= "#{idx} += #{step.compile(o)}"
631
- if from <= to
632
- "#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "#{idx}++"}"
633
- else
634
- "#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "#{idx}--"}"
635
-
636
- # When used as a value, expand the range into the equivalent array.
637
- compileArray: (o) ->
638
- if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20
639
- range = [+@fromNum..+@toNum]
640
- range.pop() if @exclusive
641
- return "[#{ range.join(', ') }]"
642
- idt = @tab + TAB
643
- i = o.scope.freeVariable 'i'
644
- result = o.scope.freeVariable 'results'
645
- pre = "\n#{idt}#{result} = [];"
646
- if @fromNum and @toNum
647
- o.index = i
648
- body = @compileSimple o
649
- else
650
- vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
651
- clause = "#{@fromVar} <= #{@toVar} ?"
652
- body = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
653
- post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
654
- "(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)"
655
-
656
- #### Slice
657
-
658
- # An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter
659
- # specifies the index of the end of the slice, just as the first parameter
660
- # is the index of the beginning.
661
- exports.Slice = class Slice extends Base
662
-
663
- children: ['range']
664
-
665
- constructor: (@range) ->
666
- super()
667
-
668
- # We have to be careful when trying to slice through the end of the array,
669
- # `9e9` is used because not all implementations respect `undefined` or `1/0`.
670
- # `9e9` should be safe because `9e9` > `2**32`, the max array length.
671
- compileNode: (o) ->
672
- {to, from} = @range
673
- fromStr = from and from.compile(o, LEVEL_PAREN) or '0'
674
- compiled = to and to.compile o, LEVEL_PAREN
675
- if to and not (not @range.exclusive and +compiled is -1)
676
- toStr = ', ' + if @range.exclusive
677
- compiled
678
- else if SIMPLENUM.test compiled
679
- (+compiled + 1).toString()
680
- else
681
- "(#{compiled} + 1) || 9e9"
682
- ".slice(#{ fromStr }#{ toStr or '' })"
683
-
684
- #### Obj
685
-
686
- # An object literal, nothing fancy.
687
- exports.Obj = class Obj extends Base
688
- constructor: (props, @generated = false) ->
689
- @objects = @properties = props or []
690
-
691
- children: ['properties']
692
-
693
- compileNode: (o) ->
694
- props = @properties
695
- return (if @front then '({})' else '{}') unless props.length
696
- idt = o.indent += TAB
697
- lastNoncom = @lastNonComment @properties
698
- props = for prop, i in props
699
- join = if i is props.length - 1
700
- ''
701
- else if prop is lastNoncom or prop instanceof Comment
702
- '\n'
703
- else
704
- ',\n'
705
- indent = if prop instanceof Comment then '' else idt
706
- if prop instanceof Value and prop.this
707
- prop = new Assign prop.properties[0].name, prop, 'object'
708
- if prop not instanceof Comment
709
- if prop not instanceof Assign
710
- prop = new Assign prop, prop, 'object'
711
- (prop.variable.base or prop.variable).asKey = yes
712
- indent + prop.compile(o, LEVEL_TOP) + join
713
- props = props.join ''
714
- obj = "{#{ props and '\n' + props + '\n' + @tab }}"
715
- if @front then "(#{obj})" else obj
716
-
717
- assigns: (name) ->
718
- for prop in @properties when prop.assigns name then return yes
719
- no
720
-
721
- #### Arr
722
-
723
- # An array literal.
724
- exports.Arr = class Arr extends Base
725
- constructor: (objs) ->
726
- @objects = objs or []
727
-
728
- children: ['objects']
729
-
730
- compileNode: (o) ->
731
- return '[]' unless @objects.length
732
- o.indent += TAB
733
- return code if code = Splat.compileSplattedArray o, @objects
734
- code = (obj.compile o, LEVEL_LIST for obj in @objects).join ', '
735
- if code.indexOf('\n') >= 0
736
- "[\n#{o.indent}#{code}\n#{@tab}]"
737
- else
738
- "[#{code}]"
739
-
740
- assigns: (name) ->
741
- for obj in @objects when obj.assigns name then return yes
742
- no
743
-
744
- #### Class
745
-
746
- # The CoffeeScript class definition.
747
- # Initialize a **Class** with its name, an optional superclass, and a
748
- # list of prototype property assignments.
749
- exports.Class = class Class extends Base
750
- constructor: (@variable, @parent, @body = new Expressions) ->
751
- @boundFuncs = []
752
- @body.classBody = yes
753
-
754
- children: ['variable', 'parent', 'body']
755
-
756
- # Figure out the appropriate name for the constructor function of this class.
757
- determineName: ->
758
- return null unless @variable
759
- decl = if tail = last @variable.properties
760
- tail instanceof Access and tail.name.value
761
- else
762
- @variable.base.value
763
- decl and= IDENTIFIER.test(decl) and decl
764
-
765
- # For all `this`-references and bound functions in the class definition,
766
- # `this` is the Class being constructed.
767
- setContext: (name) ->
768
- @body.traverseChildren false, (node) ->
769
- return false if node.classBody
770
- if node instanceof Literal and node.value is 'this'
771
- node.value = name
772
- else if node instanceof Code
773
- node.klass = name
774
- node.context = name if node.bound
775
-
776
- # Ensure that all functions bound to the instance are proxied in the
777
- # constructor.
778
- addBoundFunctions: (o) ->
779
- if @boundFuncs.length
780
- for bvar in @boundFuncs
781
- bname = bvar.compile o
782
- @ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this);"
783
-
784
- # Merge the properties from a top-level object as prototypal properties
785
- # on the class.
786
- addProperties: (node, name) ->
787
- props = node.base.properties.slice 0
788
- while assign = props.shift()
789
- if assign instanceof Assign
790
- base = assign.variable.base
791
- delete assign.context
792
- func = assign.value
793
- if base.value is 'constructor'
794
- if @ctor
795
- throw new Error 'cannot define more than one constructor in a class'
796
- if func.bound
797
- throw new Error 'cannot define a constructor as a bound function'
798
- if func instanceof Code
799
- assign = @ctor = func
800
- else
801
- assign = @ctor = new Assign(new Value(new Literal name), func)
802
- else
803
- unless assign.variable.this
804
- assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
805
- if func instanceof Code and func.bound
806
- @boundFuncs.push base
807
- func.bound = no
808
- assign
809
-
810
- # Walk the body of the class, looking for prototype properties to be converted.
811
- walkBody: (name) ->
812
- @traverseChildren false, (child) =>
813
- return false if child instanceof Class
814
- if child instanceof Expressions
815
- for node, i in exps = child.expressions
816
- if node instanceof Value and node.isObject(true)
817
- exps[i] = @addProperties node, name
818
- child.expressions = exps = flatten exps
819
-
820
- # Make sure that a constructor is defined for the class, and properly
821
- # configured.
822
- ensureConstructor: (name) ->
823
- if not @ctor
824
- @ctor = new Code
825
- @ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent
826
- @body.expressions.unshift @ctor
827
- @ctor.ctor = @ctor.name = name
828
- @ctor.klass = null
829
- @ctor.noReturn = yes
830
-
831
- # Instead of generating the JavaScript string directly, we build up the
832
- # equivalent syntax tree and compile that, in pieces. You can see the
833
- # constructor, property assignments, and inheritance getting built out below.
834
- compileNode: (o) ->
835
- decl = @determineName()
836
- name = decl or @name or '_Class'
837
- lname = new Literal name
838
-
839
- @setContext name
840
- @walkBody name
841
- @body.expressions.unshift new Extends lname, @parent if @parent
842
- @ensureConstructor name
843
- @body.expressions.push lname
844
- @addBoundFunctions o
845
-
846
- klass = new Parens Closure.wrap(@body), true
847
- klass = new Assign @variable, klass if @variable
848
- klass.compile o
849
-
850
- #### Assign
851
-
852
- # The **Assign** is used to assign a local variable to value, or to set the
853
- # property of an object -- including within object literals.
854
- exports.Assign = class Assign extends Base
855
- constructor: (@variable, @value, @context, options) ->
856
- @param = options and options.param
857
-
858
- # Matchers for detecting class/method names
859
- METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/
860
-
861
- children: ['variable', 'value']
862
-
863
- assigns: (name) ->
864
- @[if @context is 'object' then 'value' else 'variable'].assigns name
865
-
866
- unfoldSoak: (o) ->
867
- unfoldSoak o, this, 'variable'
868
-
869
- # Compile an assignment, delegating to `compilePatternMatch` or
870
- # `compileSplice` if appropriate. Keep track of the name of the base object
871
- # we've been assigned to, for correct internal references. If the variable
872
- # has not been seen yet within the current scope, declare it.
873
- compileNode: (o) ->
874
- if isValue = @variable instanceof Value
875
- return @compilePatternMatch o if @variable.isArray() or @variable.isObject()
876
- return @compileSplice o if @variable.isSplice()
877
- return @compileConditional o if @context in ['||=', '&&=', '?=']
878
- name = @variable.compile o, LEVEL_LIST
879
- if @value instanceof Code and match = @METHOD_DEF.exec name
880
- @value.name = match[2]
881
- @value.klass = match[1] if match[1]
882
- val = @value.compile o, LEVEL_LIST
883
- return "#{name}: #{val}" if @context is 'object'
884
- unless @variable.isAssignable()
885
- throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
886
- unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
887
- if @param
888
- o.scope.add name, 'var'
889
- else
890
- o.scope.find name
891
- val = name + " #{ @context or '=' } " + val
892
- if o.level <= LEVEL_LIST then val else "(#{val})"
893
-
894
- # Brief implementation of recursive pattern matching, when assigning array or
895
- # object literals to a value. Peeks at their properties to assign inner names.
896
- # See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring)
897
- # for details.
898
- compilePatternMatch: (o) ->
899
- top = o.level is LEVEL_TOP
900
- {value} = this
901
- {objects} = @variable.base
902
- return value.compile o unless olen = objects.length
903
- isObject = @variable.isObject()
904
- if top and olen is 1 and (obj = objects[0]) not instanceof Splat
905
- # Unroll simplest cases: `{v} = x` -> `v = x.v`
906
- if obj instanceof Assign
907
- {variable: {base: idx}, value: obj} = obj
908
- else
909
- if obj.base instanceof Parens
910
- [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
911
- else
912
- idx = if isObject
913
- if obj.this then obj.properties[0].name else obj
914
- else
915
- new Literal 0
916
- acc = IDENTIFIER.test idx.unwrap().value or 0
917
- value = new Value value
918
- value.properties.push new (if acc then Access else Index) idx
919
- return new Assign(obj, value).compile o
920
- vvar = value.compile o, LEVEL_LIST
921
- assigns = []
922
- splat = false
923
- if not IDENTIFIER.test(vvar) or @variable.assigns(vvar)
924
- assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{vvar}"
925
- vvar = ref
926
- for obj, i in objects
927
- # A regular array pattern-match.
928
- idx = i
929
- if isObject
930
- if obj instanceof Assign
931
- # A regular object pattern-match.
932
- {variable: {base: idx}, value: obj} = obj
933
- else
934
- # A shorthand `{a, b, @c} = val` pattern-match.
935
- if obj.base instanceof Parens
936
- [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
937
- else
938
- idx = if obj.this then obj.properties[0].name else obj
939
- if not splat and obj instanceof Splat
940
- val = "#{olen} <= #{vvar}.length ? #{ utility 'slice' }.call(#{vvar}, #{i}"
941
- if rest = olen - i - 1
942
- ivar = o.scope.freeVariable 'i'
943
- val += ", #{ivar} = #{vvar}.length - #{rest}) : (#{ivar} = #{i}, [])"
944
- else
945
- val += ") : []"
946
- val = new Literal val
947
- splat = "#{ivar}++"
948
- else
949
- if obj instanceof Splat
950
- obj = obj.name.compile o
951
- throw SyntaxError \
952
- "multiple splats are disallowed in an assignment: #{obj} ..."
953
- if typeof idx is 'number'
954
- idx = new Literal splat or idx
955
- acc = no
956
- else
957
- acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
958
- val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
959
- assigns.push new Assign(obj, val, null, param: @param).compile o, LEVEL_TOP
960
- assigns.push vvar unless top
961
- code = assigns.join ', '
962
- if o.level < LEVEL_LIST then code else "(#{code})"
963
-
964
- # When compiling a conditional assignment, take care to ensure that the
965
- # operands are only evaluated once, even though we have to reference them
966
- # more than once.
967
- compileConditional: (o) ->
968
- [left, rite] = @variable.cacheReference o
969
- new Op(@context.slice(0, -1), left, new Assign(rite, @value, '=')).compile o
970
-
971
- # Compile the assignment from an array splice literal, using JavaScript's
972
- # `Array#splice` method.
973
- compileSplice: (o) ->
974
- {range: {from, to, exclusive}} = @variable.properties.pop()
975
- name = @variable.compile o
976
- [fromDecl, fromRef] = from?.cache(o, LEVEL_OP) or ['0', '0']
977
- if to
978
- if from?.isSimpleNumber() and to.isSimpleNumber()
979
- to = +to.compile(o) - +fromRef
980
- to += 1 unless exclusive
981
- else
982
- to = to.compile(o) + ' - ' + fromRef
983
- to += ' + 1' unless exclusive
984
- else
985
- to = "9e9"
986
- [valDef, valRef] = @value.cache o, LEVEL_LIST
987
- code = "[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}"
988
- if o.level > LEVEL_TOP then "(#{code})" else code
989
-
990
- #### Code
991
-
992
- # A function definition. This is the only node that creates a new Scope.
993
- # When for the purposes of walking the contents of a function body, the Code
994
- # has no *children* -- they're within the inner scope.
995
- exports.Code = class Code extends Base
996
- constructor: (params, body, tag) ->
997
- @params = params or []
998
- @body = body or new Expressions
999
- @bound = tag is 'boundfunc'
1000
- @context = 'this' if @bound
1001
-
1002
- children: ['params', 'body']
1003
-
1004
- isStatement: -> !!@ctor
1005
-
1006
- jumps: NO
1007
-
1008
- # Compilation creates a new scope unless explicitly asked to share with the
1009
- # outer scope. Handles splat parameters in the parameter list by peeking at
1010
- # the JavaScript `arguments` objects. If the function is bound with the `=>`
1011
- # arrow, generates a wrapper that saves the current value of `this` through
1012
- # a closure.
1013
- compileNode: (o) ->
1014
- o.scope = new Scope o.scope, @body, this
1015
- o.scope.shared = del o, 'sharedScope'
1016
- o.indent += TAB
1017
- delete o.bare
1018
- delete o.globals
1019
- vars = []
1020
- exprs = []
1021
- for param in @params when param.splat
1022
- splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
1023
- new Value new Literal 'arguments'
1024
- break
1025
- for param in @params
1026
- if param.isComplex()
1027
- val = ref = param.asReference o
1028
- val = new Op '?', ref, param.value if param.value
1029
- exprs.push new Assign new Value(param.name), val, '=', param: yes
1030
- else
1031
- ref = param
1032
- if param.value
1033
- lit = new Literal ref.name.value + ' == null'
1034
- val = new Assign new Value(param.name), param.value, '='
1035
- exprs.push new If lit, val
1036
- vars.push ref unless splats
1037
- wasEmpty = @body.isEmpty()
1038
- exprs.unshift splats if splats
1039
- @body.expressions.unshift exprs... if exprs.length
1040
- o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
1041
- @body.makeReturn() unless wasEmpty or @noReturn
1042
- idt = o.indent
1043
- code = 'function'
1044
- code += ' ' + @name if @ctor
1045
- code += '(' + vars.join(', ') + ') {'
1046
- code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
1047
- code += '}'
1048
- return @tab + code if @ctor
1049
- return utility('bind') + "(#{code}, #{@context})" if @bound
1050
- if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
1051
-
1052
- # Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
1053
- # unless `crossScope` is `true`.
1054
- traverseChildren: (crossScope, func) ->
1055
- super(crossScope, func) if crossScope
1056
-
1057
- #### Param
1058
-
1059
- # A parameter in a function definition. Beyond a typical Javascript parameter,
1060
- # these parameters can also attach themselves to the context of the function,
1061
- # as well as be a splat, gathering up a group of parameters into an array.
1062
- exports.Param = class Param extends Base
1063
- constructor: (@name, @value, @splat) ->
1064
-
1065
- children: ['name', 'value']
1066
-
1067
- compile: (o) ->
1068
- @name.compile o, LEVEL_LIST
1069
-
1070
- asReference: (o) ->
1071
- return @reference if @reference
1072
- node = @name
1073
- if node.this
1074
- node = node.properties[0].name
1075
- node = new Literal '_' + node.value if node.value.reserved
1076
- else if node.isComplex()
1077
- node = new Literal o.scope.freeVariable 'arg'
1078
- node = new Value node
1079
- node = new Splat node if @splat
1080
- @reference = node
1081
-
1082
- isComplex: ->
1083
- @name.isComplex()
1084
-
1085
- #### Splat
1086
-
1087
- # A splat, either as a parameter to a function, an argument to a call,
1088
- # or as part of a destructuring assignment.
1089
- exports.Splat = class Splat extends Base
1090
-
1091
- children: ['name']
1092
-
1093
- isAssignable: YES
1094
-
1095
- constructor: (name) ->
1096
- @name = if name.compile then name else new Literal name
1097
-
1098
- assigns: (name) ->
1099
- @name.assigns name
1100
-
1101
- compile: (o) ->
1102
- if @index? then @compileParam o else @name.compile o
1103
-
1104
- # Utility function that converts arbitrary number of elements, mixed with
1105
- # splats, to a proper array.
1106
- @compileSplattedArray: (o, list, apply) ->
1107
- index = -1
1108
- continue while (node = list[++index]) and node not instanceof Splat
1109
- return '' if index >= list.length
1110
- if list.length is 1
1111
- code = list[0].compile o, LEVEL_LIST
1112
- return code if apply
1113
- return "#{ utility 'slice' }.call(#{code})"
1114
- args = list.slice index
1115
- for node, i in args
1116
- code = node.compile o, LEVEL_LIST
1117
- args[i] = if node instanceof Splat
1118
- then "#{ utility 'slice' }.call(#{code})"
1119
- else "[#{code}]"
1120
- return args[0] + ".concat(#{ args.slice(1).join ', ' })" if index is 0
1121
- base = (node.compile o, LEVEL_LIST for node in list.slice 0, index)
1122
- "[#{ base.join ', ' }].concat(#{ args.join ', ' })"
1123
-
1124
- #### While
1125
-
1126
- # A while loop, the only sort of low-level loop exposed by CoffeeScript. From
1127
- # it, all other loops can be manufactured. Useful in cases where you need more
1128
- # flexibility or more speed than a comprehension can provide.
1129
- exports.While = class While extends Base
1130
- constructor: (condition, options) ->
1131
- @condition = if options?.invert then condition.invert() else condition
1132
- @guard = options?.guard
1133
-
1134
- children: ['condition', 'guard', 'body']
1135
-
1136
- isStatement: YES
1137
-
1138
- makeReturn: ->
1139
- @returns = yes
1140
- this
1141
-
1142
- addBody: (@body) ->
1143
- this
1144
-
1145
- jumps: ->
1146
- {expressions} = @body
1147
- return no unless expressions.length
1148
- for node in expressions
1149
- return node if node.jumps loop: yes
1150
- no
1151
-
1152
- # The main difference from a JavaScript *while* is that the CoffeeScript
1153
- # *while* can be used as a part of a larger expression -- while loops may
1154
- # return an array containing the computed result of each iteration.
1155
- compileNode: (o) ->
1156
- o.indent += TAB
1157
- set = ''
1158
- {body} = this
1159
- if body.isEmpty()
1160
- body = ''
1161
- else
1162
- if o.level > LEVEL_TOP or @returns
1163
- rvar = o.scope.freeVariable 'results'
1164
- set = "#{@tab}#{rvar} = [];\n"
1165
- body = Push.wrap rvar, body if body
1166
- body = Expressions.wrap [new If @guard, body] if @guard
1167
- body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
1168
- code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
1169
- if @returns
1170
- code += "\n#{@tab}return #{rvar};"
1171
- code
1172
-
1173
- #### Op
1174
-
1175
- # Simple Arithmetic and logical operations. Performs some conversion from
1176
- # CoffeeScript operations into their JavaScript equivalents.
1177
- exports.Op = class Op extends Base
1178
- constructor: (op, first, second, flip) ->
1179
- return new In first, second if op is 'in'
1180
- return new Call first, first.params or [] if op is 'do'
1181
- if op is 'new'
1182
- return first.newInstance() if first instanceof Call
1183
- first = new Parens first if first instanceof Code and first.bound
1184
- @operator = CONVERSIONS[op] or op
1185
- @first = first
1186
- @second = second
1187
- @flip = !!flip
1188
- return this
1189
-
1190
- # The map of conversions from CoffeeScript to JavaScript symbols.
1191
- CONVERSIONS =
1192
- '==': '==='
1193
- '!=': '!=='
1194
- 'of': 'in'
1195
-
1196
- # The map of invertible operators.
1197
- INVERSIONS =
1198
- '!==': '==='
1199
- '===': '!=='
1200
-
1201
- children: ['first', 'second']
1202
-
1203
- isSimpleNumber: NO
1204
-
1205
- isUnary: ->
1206
- not @second
1207
-
1208
- # Am I capable of
1209
- # [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
1210
- isChainable: ->
1211
- @operator in ['<', '>', '>=', '<=', '===', '!==']
1212
-
1213
- invert: ->
1214
- if @isChainable() and @first.isChainable()
1215
- allInvertable = yes
1216
- curr = this
1217
- while curr and curr.operator
1218
- allInvertable and= (curr.operator of INVERSIONS)
1219
- curr = curr.first
1220
- return new Parens(this).invert() unless allInvertable
1221
- curr = this
1222
- while curr and curr.operator
1223
- curr.invert = !curr.invert
1224
- curr.operator = INVERSIONS[curr.operator]
1225
- curr = curr.first
1226
- this
1227
- else if op = INVERSIONS[@operator]
1228
- @operator = op
1229
- if @first.unwrap() instanceof Op
1230
- @first.invert()
1231
- this
1232
- else if @second
1233
- new Parens(this).invert()
1234
- else if @operator is '!' and (fst = @first.unwrap()) instanceof Op and
1235
- fst.operator in ['!', 'in', 'instanceof']
1236
- fst
1237
- else
1238
- new Op '!', this
1239
-
1240
- unfoldSoak: (o) ->
1241
- @operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first'
1242
-
1243
- compileNode: (o) ->
1244
- return @compileUnary o if @isUnary()
1245
- return @compileChain o if @isChainable() and @first.isChainable()
1246
- return @compileExistence o if @operator is '?'
1247
- @first.front = @front
1248
- code = @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' +
1249
- @second.compile(o, LEVEL_OP)
1250
- if o.level <= LEVEL_OP then code else "(#{code})"
1251
-
1252
- # Mimic Python's chained comparisons when multiple comparison operators are
1253
- # used sequentially. For example:
1254
- #
1255
- # bin/coffee -e 'console.log 50 < 65 > 10'
1256
- # true
1257
- compileChain: (o) ->
1258
- [@first.second, shared] = @first.second.cache o
1259
- fst = @first.compile o, LEVEL_OP
1260
- code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
1261
- "(#{code})"
1262
-
1263
- compileExistence: (o) ->
1264
- if @first.isComplex()
1265
- ref = o.scope.freeVariable 'ref'
1266
- fst = new Parens new Assign new Literal(ref), @first
1267
- else
1268
- fst = @first
1269
- ref = fst.compile o
1270
- new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL_LIST }"
1271
-
1272
- # Compile a unary **Op**.
1273
- compileUnary: (o) ->
1274
- parts = [op = @operator]
1275
- parts.push ' ' if op in ['new', 'typeof', 'delete'] or
1276
- op in ['+', '-'] and @first instanceof Op and @first.operator is op
1277
- parts.push @first.compile o, LEVEL_OP
1278
- parts.reverse() if @flip
1279
- parts.join ''
1280
-
1281
- toString: (idt) ->
1282
- super idt, @constructor.name + ' ' + @operator
1283
-
1284
- #### In
1285
- exports.In = class In extends Base
1286
- constructor: (@object, @array) ->
1287
-
1288
- children: ['object', 'array']
1289
-
1290
- invert: NEGATE
1291
-
1292
- compileNode: (o) ->
1293
- if @array instanceof Value and @array.isArray()
1294
- @compileOrTest o
1295
- else
1296
- @compileLoopTest o
1297
-
1298
- compileOrTest: (o) ->
1299
- [sub, ref] = @object.cache o, LEVEL_OP
1300
- [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
1301
- tests = for item, i in @array.base.objects
1302
- (if i then ref else sub) + cmp + item.compile o, LEVEL_OP
1303
- tests = tests.join cnj
1304
- if o.level < LEVEL_OP then tests else "(#{tests})"
1305
-
1306
- compileLoopTest: (o) ->
1307
- [sub, ref] = @object.cache o, LEVEL_LIST
1308
- code = utility('indexOf') + ".call(#{ @array.compile o, LEVEL_LIST }, #{ref}) " +
1309
- if @negated then '< 0' else '>= 0'
1310
- return code if sub is ref
1311
- code = sub + ', ' + code
1312
- if o.level < LEVEL_LIST then code else "(#{code})"
1313
-
1314
- toString: (idt) ->
1315
- super idt, @constructor.name + if @negated then '!' else ''
1316
-
1317
- #### Try
1318
-
1319
- # A classic *try/catch/finally* block.
1320
- exports.Try = class Try extends Base
1321
- constructor: (@attempt, @error, @recovery, @ensure) ->
1322
-
1323
- children: ['attempt', 'recovery', 'ensure']
1324
-
1325
- isStatement: YES
1326
-
1327
- jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)
1328
-
1329
- makeReturn: ->
1330
- @attempt = @attempt .makeReturn() if @attempt
1331
- @recovery = @recovery.makeReturn() if @recovery
1332
- this
1333
-
1334
- # Compilation is more or less as you would expect -- the *finally* clause
1335
- # is optional, the *catch* is not.
1336
- compileNode: (o) ->
1337
- o.indent += TAB
1338
- errorPart = if @error then " (#{ @error.compile o }) " else ' '
1339
- catchPart = if @recovery
1340
- " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
1341
- else unless @ensure or @recovery
1342
- ' catch (_e) {}'
1343
- """
1344
- #{@tab}try {
1345
- #{ @attempt.compile o, LEVEL_TOP }
1346
- #{@tab}}#{ catchPart or '' }
1347
- """ + if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else ''
1348
-
1349
- #### Throw
1350
-
1351
- # Simple node to throw an exception.
1352
- exports.Throw = class Throw extends Base
1353
- constructor: (@expression) ->
1354
-
1355
- children: ['expression']
1356
-
1357
- isStatement: YES
1358
- jumps: NO
1359
-
1360
- # A **Throw** is already a return, of sorts...
1361
- makeReturn: THIS
1362
-
1363
- compileNode: (o) ->
1364
- @tab + "throw #{ @expression.compile o };"
1365
-
1366
- #### Existence
1367
-
1368
- # Checks a variable for existence -- not *null* and not *undefined*. This is
1369
- # similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth
1370
- # table.
1371
- exports.Existence = class Existence extends Base
1372
- constructor: (@expression) ->
1373
-
1374
- children: ['expression']
1375
-
1376
- invert: NEGATE
1377
-
1378
- compileNode: (o) ->
1379
- code = @expression.compile o, LEVEL_OP
1380
- code = if IDENTIFIER.test(code) and not o.scope.check code
1381
- if @negated
1382
- "typeof #{code} == \"undefined\" || #{code} === null"
1383
- else
1384
- "typeof #{code} != \"undefined\" && #{code} !== null"
1385
- else
1386
- sym = if @negated then '==' else '!='
1387
- "#{code} #{sym} null"
1388
- if o.level <= LEVEL_COND then code else "(#{code})"
1389
-
1390
- #### Parens
1391
-
1392
- # An extra set of parentheses, specified explicitly in the source. At one time
1393
- # we tried to clean up the results by detecting and removing redundant
1394
- # parentheses, but no longer -- you can put in as many as you please.
1395
- #
1396
- # Parentheses are a good way to force any statement to become an expression.
1397
- exports.Parens = class Parens extends Base
1398
- constructor: (@body) ->
1399
-
1400
- children: ['body']
1401
-
1402
- unwrap : -> @body
1403
- isComplex : -> @body.isComplex()
1404
- makeReturn: -> @body.makeReturn()
1405
-
1406
- compileNode: (o) ->
1407
- expr = @body.unwrap()
1408
- if expr instanceof Value and expr.isAtomic()
1409
- expr.front = @front
1410
- return expr.compile o
1411
- code = expr.compile o, LEVEL_PAREN
1412
- bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
1413
- (expr instanceof For and expr.returns))
1414
- if bare then code else "(#{code})"
1415
-
1416
- #### For
1417
-
1418
- # CoffeeScript's replacement for the *for* loop is our array and object
1419
- # comprehensions, that compile into *for* loops here. They also act as an
1420
- # expression, able to return the result of each filtered iteration.
1421
- #
1422
- # Unlike Python array comprehensions, they can be multi-line, and you can pass
1423
- # the current index of the loop as a second parameter. Unlike Ruby blocks,
1424
- # you can map and filter in a single pass.
1425
- exports.For = class For extends Base
1426
- constructor: (body, source) ->
1427
- {@source, @guard, @step, @name, @index} = source
1428
- @body = Expressions.wrap [body]
1429
- @own = !!source.own
1430
- @object = !!source.object
1431
- [@name, @index] = [@index, @name] if @object
1432
- throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value
1433
- @range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length
1434
- @pattern = @name instanceof Value
1435
- throw SyntaxError 'indexes do not apply to range loops' if @range and @index
1436
- throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern
1437
- @returns = false
1438
-
1439
- children: ['body', 'source', 'guard', 'step']
1440
-
1441
- isStatement: YES
1442
-
1443
- jumps: While::jumps
1444
-
1445
- makeReturn: ->
1446
- @returns = yes
1447
- this
1448
-
1449
- # Welcome to the hairiest method in all of CoffeeScript. Handles the inner
1450
- # loop, filtering, stepping, and result saving for array, object, and range
1451
- # comprehensions. Some of the generated code can be shared in common, and
1452
- # some cannot.
1453
- compileNode: (o) ->
1454
- body = Expressions.wrap [@body]
1455
- lastJumps = last(body.expressions)?.jumps()
1456
- @returns = no if lastJumps and lastJumps instanceof Return
1457
- source = if @range then @source.base else @source
1458
- scope = o.scope
1459
- name = @name and @name.compile o, LEVEL_LIST
1460
- index = @index and @index.compile o, LEVEL_LIST
1461
- scope.find(name, immediate: yes) if name and not @pattern
1462
- scope.find(index, immediate: yes) if index
1463
- rvar = scope.freeVariable 'results' if @returns
1464
- ivar = (if @range then name else index) or scope.freeVariable 'i'
1465
- name = ivar if @pattern
1466
- varPart = ''
1467
- guardPart = ''
1468
- defPart = ''
1469
- idt1 = @tab + TAB
1470
- if @range
1471
- forPart = source.compile merge(o, {index: ivar, @step})
1472
- else
1473
- svar = @source.compile o, LEVEL_LIST
1474
- if (name or @own) and not IDENTIFIER.test svar
1475
- defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
1476
- svar = ref
1477
- if name and not @pattern
1478
- namePart = "#{name} = #{svar}[#{ivar}]"
1479
- unless @object
1480
- lvar = scope.freeVariable 'len'
1481
- stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++"
1482
- forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
1483
- if @returns
1484
- resultPart = "#{@tab}#{rvar} = [];\n"
1485
- returnResult = "\n#{@tab}return #{rvar};"
1486
- body = Push.wrap rvar, body
1487
- if @guard
1488
- body = Expressions.wrap [new If @guard, body]
1489
- if @pattern
1490
- body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
1491
- defPart += @pluckDirectCall o, body
1492
- varPart = "\n#{idt1}#{namePart};" if namePart
1493
- if @object
1494
- forPart = "#{ivar} in #{svar}"
1495
- guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
1496
- body = body.compile merge(o, indent: idt1), LEVEL_TOP
1497
- body = '\n' + body + '\n' if body
1498
- """
1499
- #{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
1500
- """
1501
-
1502
- pluckDirectCall: (o, body) ->
1503
- defs = ''
1504
- for expr, idx in body.expressions
1505
- expr = expr.unwrapAll()
1506
- continue unless expr instanceof Call
1507
- val = expr.variable.unwrapAll()
1508
- continue unless (val instanceof Code) or
1509
- (val instanceof Value and
1510
- val.base?.unwrapAll() instanceof Code and
1511
- val.properties.length is 1 and
1512
- val.properties[0].name?.value in ['call', 'apply'])
1513
- fn = val.base?.unwrapAll() or val
1514
- ref = new Literal o.scope.freeVariable 'fn'
1515
- base = new Value ref
1516
- if val.base
1517
- [val.base, base] = [base, val]
1518
- args.unshift new Literal 'this'
1519
- body.expressions[idx] = new Call base, expr.args
1520
- defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
1521
- defs
1522
-
1523
- #### Switch
1524
-
1525
- # A JavaScript *switch* statement. Converts into a returnable expression on-demand.
1526
- exports.Switch = class Switch extends Base
1527
- constructor: (@subject, @cases, @otherwise) ->
1528
-
1529
- children: ['subject', 'cases', 'otherwise']
1530
-
1531
- isStatement: YES
1532
-
1533
- jumps: (o = {block: yes}) ->
1534
- for [conds, block] in @cases
1535
- return block if block.jumps o
1536
- @otherwise?.jumps o
1537
-
1538
- makeReturn: ->
1539
- pair[1].makeReturn() for pair in @cases
1540
- @otherwise?.makeReturn()
1541
- this
1542
-
1543
- compileNode: (o) ->
1544
- idt1 = o.indent + TAB
1545
- idt2 = o.indent = idt1 + TAB
1546
- code = @tab + "switch (#{ @subject?.compile(o, LEVEL_PAREN) or false }) {\n"
1547
- for [conditions, block], i in @cases
1548
- for cond in flatten [conditions]
1549
- cond = cond.invert() unless @subject
1550
- code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n"
1551
- code += body + '\n' if body = block.compile o, LEVEL_TOP
1552
- break if i is @cases.length - 1 and not @otherwise
1553
- expr = @lastNonComment block.expressions
1554
- jumper = expr.jumps()
1555
- if not expr or not jumper or (jumper instanceof Literal and jumper.value is 'debugger')
1556
- code += idt2 + 'break;\n'
1557
- code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
1558
- code + @tab + '}'
1559
-
1560
- #### If
1561
-
1562
- # *If/else* statements. Acts as an expression by pushing down requested returns
1563
- # to the last line of each clause.
1564
- #
1565
- # Single-expression **Ifs** are compiled into conditional operators if possible,
1566
- # because ternaries are already proper expressions, and don't need conversion.
1567
- exports.If = class If extends Base
1568
- constructor: (condition, @body, options = {}) ->
1569
- @condition = if options.type is 'unless' then condition.invert() else condition
1570
- @elseBody = null
1571
- @isChain = false
1572
- {@soak} = options
1573
-
1574
- children: ['condition', 'body', 'elseBody']
1575
-
1576
- bodyNode: -> @body?.unwrap()
1577
- elseBodyNode: -> @elseBody?.unwrap()
1578
-
1579
- # Rewrite a chain of **Ifs** to add a default case as the final *else*.
1580
- addElse: (elseBody) ->
1581
- if @isChain
1582
- @elseBodyNode().addElse elseBody
1583
- else
1584
- @isChain = elseBody instanceof If
1585
- @elseBody = @ensureExpressions elseBody
1586
- this
1587
-
1588
- # The **If** only compiles into a statement if either of its bodies needs
1589
- # to be a statement. Otherwise a conditional operator is safe.
1590
- isStatement: (o) ->
1591
- o?.level is LEVEL_TOP or
1592
- @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
1593
-
1594
- jumps: (o) -> @body.jumps(o) or @elseBody?.jumps(o)
1595
-
1596
- compileNode: (o) ->
1597
- if @isStatement o then @compileStatement o else @compileExpression o
1598
-
1599
- makeReturn: ->
1600
- @body and= new Expressions [@body.makeReturn()]
1601
- @elseBody and= new Expressions [@elseBody.makeReturn()]
1602
- this
1603
-
1604
- ensureExpressions: (node) ->
1605
- if node instanceof Expressions then node else new Expressions [node]
1606
-
1607
- # Compile the **If** as a regular *if-else* statement. Flattened chains
1608
- # force inner *else* bodies into statement form.
1609
- compileStatement: (o) ->
1610
- child = del o, 'chainChild'
1611
- cond = @condition.compile o, LEVEL_PAREN
1612
- o.indent += TAB
1613
- body = @ensureExpressions(@body).compile o
1614
- body = "\n#{body}\n#{@tab}" if body
1615
- ifPart = "if (#{cond}) {#{body}}"
1616
- ifPart = @tab + ifPart unless child
1617
- return ifPart unless @elseBody
1618
- ifPart + ' else ' + if @isChain
1619
- o.indent = @tab
1620
- o.chainChild = yes
1621
- @elseBody.unwrap().compile o, LEVEL_TOP
1622
- else
1623
- "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"
1624
-
1625
- # Compile the If as a conditional operator.
1626
- compileExpression: (o) ->
1627
- cond = @condition.compile o, LEVEL_COND
1628
- body = @bodyNode().compile o, LEVEL_LIST
1629
- alt = if @elseBodyNode() then @elseBodyNode().compile(o, LEVEL_LIST) else 'void 0'
1630
- code = "#{cond} ? #{body} : #{alt}"
1631
- if o.level >= LEVEL_COND then "(#{code})" else code
1632
-
1633
- unfoldSoak: ->
1634
- @soak and this
1635
-
1636
- # Faux-Nodes
1637
- # ----------
1638
- # Faux-nodes are never created by the grammar, but are used during code
1639
- # generation to generate other combinations of nodes.
1640
-
1641
- #### Push
1642
-
1643
- # The **Push** creates the tree for `array.push(value)`,
1644
- # which is helpful for recording the result arrays from comprehensions.
1645
- Push =
1646
- wrap: (name, exps) ->
1647
- return exps if exps.isEmpty() or last(exps.expressions).jumps()
1648
- exps.push new Call new Value(new Literal(name), [new Access new Literal 'push']), [exps.pop()]
1649
-
1650
- #### Closure
1651
-
1652
- # A faux-node used to wrap an expressions body in a closure.
1653
- Closure =
1654
-
1655
- # Wrap the expressions body, unless it contains a pure statement,
1656
- # in which case, no dice. If the body mentions `this` or `arguments`,
1657
- # then make sure that the closure wrapper preserves the original values.
1658
- wrap: (expressions, statement, noReturn) ->
1659
- return expressions if expressions.jumps()
1660
- func = new Code [], Expressions.wrap [expressions]
1661
- args = []
1662
- if (mentionsArgs = expressions.contains @literalArgs) or
1663
- ( expressions.contains @literalThis)
1664
- meth = new Literal if mentionsArgs then 'apply' else 'call'
1665
- args = [new Literal 'this']
1666
- args.push new Literal 'arguments' if mentionsArgs
1667
- func = new Value func, [new Access meth]
1668
- func.noReturn = noReturn
1669
- call = new Call func, args
1670
- if statement then Expressions.wrap [call] else call
1671
-
1672
- literalArgs: (node) ->
1673
- node instanceof Literal and node.value is 'arguments' and not node.asKey
1674
- literalThis: (node) ->
1675
- (node instanceof Literal and node.value is 'this' and not node.asKey) or
1676
- (node instanceof Code and node.bound)
1677
-
1678
- # Unfold a node's child if soak, then tuck the node under created `If`
1679
- unfoldSoak = (o, parent, name) ->
1680
- return unless ifn = parent[name].unfoldSoak o
1681
- parent[name] = ifn.body
1682
- ifn.body = new Value parent
1683
- ifn
1684
-
1685
- # Constants
1686
- # ---------
1687
-
1688
- UTILITIES =
1689
-
1690
- # Correctly set up a prototype chain for inheritance, including a reference
1691
- # to the superclass for `super()` calls, and copies of any static properties.
1692
- extends: '''
1693
- function(child, parent) {
1694
- for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
1695
- function ctor() { this.constructor = child; }
1696
- ctor.prototype = parent.prototype;
1697
- child.prototype = new ctor;
1698
- child.__super__ = parent.prototype;
1699
- return child;
1700
- }
1701
- '''
1702
-
1703
- # Create a function bound to the current value of "this".
1704
- bind: '''
1705
- function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
1706
- '''
1707
-
1708
- # Discover if an item is in an array.
1709
- indexOf: '''
1710
- Array.prototype.indexOf || function(item) {
1711
- for (var i = 0, l = this.length; i < l; i++) {
1712
- if (this[i] === item) return i;
1713
- }
1714
- return -1;
1715
- }
1716
- '''
1717
-
1718
- # Shortcuts to speed up the lookup time for native functions.
1719
- hasProp: 'Object.prototype.hasOwnProperty'
1720
- slice : 'Array.prototype.slice'
1721
-
1722
- # Levels indicates a node's position in the AST. Useful for knowing if
1723
- # parens are necessary or superfluous.
1724
- LEVEL_TOP = 1 # ...;
1725
- LEVEL_PAREN = 2 # (...)
1726
- LEVEL_LIST = 3 # [...]
1727
- LEVEL_COND = 4 # ... ? x : y
1728
- LEVEL_OP = 5 # !...
1729
- LEVEL_ACCESS = 6 # ...[0]
1730
-
1731
- # Tabs are two spaces for pretty printing.
1732
- TAB = ' '
1733
-
1734
- # Trim out all trailing whitespace, so that the generated code plays nice
1735
- # with Git.
1736
- TRAILING_WHITESPACE = /[ \t]+$/gm
1737
-
1738
- IDENTIFIER = /^[$A-Za-z_][$\w]*$/
1739
- SIMPLENUM = /^[+-]?\d+$/
1740
-
1741
- # Is a literal value a string?
1742
- IS_STRING = /^['"]/
1743
-
1744
- # Utility Functions
1745
- # -----------------
1746
-
1747
- # Helper for ensuring that utility functions are assigned at the top level.
1748
- utility = (name) ->
1749
- ref = "__#{name}"
1750
- Scope.root.assign ref, UTILITIES[name]
1751
- ref
1752
-
1753
- multident = (code, tab) ->
1754
- code.replace /\n/g, '$&' + tab