Compare commits

..

345 Commits
0.5.2 ... 0.6.0

Author SHA1 Message Date
Jeremy Ashkenas
c067808b54 CoffeeScript 0.6.0 is on the books. 2010-04-03 20:43:50 -04:00
Jeremy Ashkenas
59ae79d8fb rebuilding the docs with the fixed highlighter for '@' and regexes. 2010-04-03 19:10:26 -04:00
Jeremy Ashkenas
ad1c5e1884 merging non-func-constructor-fix, but a little more forgiving. 2010-04-03 14:53:26 -04:00
Stan Angeloff
9958cedd89 Throwing proper error when "constructor" is not a function within a class body. 2010-04-03 21:43:42 +03:00
Jeremy Ashkenas
d1aaed4430 Merge branch 'master' of git://github.com/Tesco/coffee-script 2010-04-03 12:21:31 -04:00
Tim Jones
89debc87b2 Removing {@prop: value} from the grammar. 2010-04-04 04:18:29 +12:00
Jeremy Ashkenas
9d2c81ea54 rebuilding the docs with new pygments, no errors on '@' 2010-04-03 12:01:46 -04:00
Jeremy Ashkenas
44765907b3 tiny tweak 2010-04-03 11:16:49 -04:00
Jeremy Ashkenas
4a85f3d499 cleaning up tests ... consolidation, consistency... 2010-04-03 10:39:32 -04:00
Jeremy Ashkenas
f99b5ad463 Merging Tesco's invoking-this-fix 2010-04-03 09:58:45 -04:00
Tim Jones
8fc631269b Added a rule to prevent invoking THIS. 2010-04-03 14:14:16 +13:00
Tim Jones
a1975583a7 Added THIS to CALLABLE. 2010-04-03 13:58:21 +13:00
Jeremy Ashkenas
1c628e7883 fixing parens-around-implicit-function-with-multiline-chained-chaser bug 2010-04-01 23:38:20 -04:00
Jeremy Ashkenas
3605168e85 fixing single evaluation of functions used in chained comparisons wrapped in parentheses. 2010-03-31 22:48:47 -04:00
Jeremy Ashkenas
f86fca2739 merged tanob's fix for installing outside of /usr/local without a /bin 2010-03-31 21:30:14 -04:00
Adriano Bonat
0410748e2d Merge remote branch 'upstream/master' 2010-03-31 22:14:26 -03:00
Adriano Bonat
2172878f21 When installing in different prefixes, prefix + '/bin' may not exist. 2010-03-31 09:38:05 -03:00
Jeremy Ashkenas
d3a51fbfa1 stylistics: removing a bunch of unecessary parentheses 2010-03-31 00:17:49 -04:00
Jeremy Ashkenas
aae2405de4 removing all of the 'type' tags from the Nodes. Simply using constructor.name instead. 2010-03-31 00:04:14 -04:00
Jeremy Ashkenas
2b578367a9 rebuilding the source documentation with the new utility refactors 2010-03-30 23:53:02 -04:00
Jeremy Ashkenas
f9b028b78c __extend back to __extends, as is the correct name. 2010-03-30 20:15:51 -04:00
Jeremy Ashkenas
572aa4e98f reverting the grammar to the pre-slice notation. 2010-03-30 20:11:40 -04:00
Jeremy Ashkenas
864275f07e removing __range, and all the slice behavior it enabled. If you can't do array[-1], then you shouldn't be able to do array[0..-1] -- it's just too inconsistent. 2010-03-30 20:06:44 -04:00
Jeremy Ashkenas
998a7c8cb0 more cleanups, added a utility helper function to the codegen 2010-03-30 19:48:37 -04:00
Jeremy Ashkenas
6d7a04228f another reshuffle ... removed utilities.coffee entirely. 2010-03-30 19:42:09 -04:00
Jeremy Ashkenas
4a8c2e8a13 more refactors to utilities ... removing dependencies and the namespacing 2010-03-30 19:27:38 -04:00
Jeremy Ashkenas
f3a60edc5d simplifying the lookup of the top-level scope object 2010-03-30 19:21:14 -04:00
Jeremy Ashkenas
1e1146d61d more utility simplifications 2010-03-30 19:17:40 -04:00
Jeremy Ashkenas
832e1d8cb8 Utilities doesn't need to be a class, and removing __utilities.keys 2010-03-30 19:00:59 -04:00
Jeremy Ashkenas
4936211a9c modified shorter imlementation of bind 2010-03-30 18:49:55 -04:00
Jeremy Ashkenas
f0d731009f merged matehat's utility branch, arraySlice -> slice, removed dead dependency... 2010-03-30 18:27:53 -04:00
Jeremy Ashkenas
a6248d03e5 Merge branch 'slice' of git://github.com/matehat/coffee-script 2010-03-30 18:19:41 -04:00
Jeremy Ashkenas
a934cf4947 make JSLint happy about the while condition 2010-03-30 18:19:09 -04:00
matehat
c498b7090e Removed __splice in the same manner 2010-03-30 18:14:51 -04:00
matehat
ca9e45e8af Removed the __slice method, in favor of the native array slice method 2010-03-30 17:57:23 -04:00
matehat
97096696a2 Put back every utility functions on the global scope, automatically prefixed with __ and set them dynamically as reserved on the lexer. 2010-03-30 16:48:43 -04:00
matehat
27fb3763b4 A set of improvements on previous code 2010-03-30 16:14:07 -04:00
matehat
da43c70488 Merged in StanAngeloff excellent slice branch, applying recent factoring of utility functions 2010-03-30 15:43:30 -04:00
Stan Angeloff
76ade0cb4d Removing vendor specific files for measurement tests. 2010-03-30 14:33:57 -04:00
Stan Angeloff
09e1526bca Removing commented code in compile_splice -- this is working correctly now. 2010-03-30 14:33:57 -04:00
Stan Angeloff
7d1fbeb708 Re-compiling the core using the new __slice and __splice functions. 2010-03-30 14:32:37 -04:00
Stan Angeloff
15217c705e Allowing for negative indices in slice literals. 2010-03-30 14:30:15 -04:00
matehat
9f108e87eb Removed unused __hasProp assignment and declared Coffeescript a reserved name 2010-03-30 11:20:53 -04:00
matehat
1e786d6d8b Removed unnecessary check 2010-03-30 10:58:21 -04:00
matehat
0557eb9b93 Removed hard-coding of utility object name 2010-03-30 09:08:16 -04:00
matehat
241f6f3068 Applied the utility factoring into a "Coffeescript" object to the core. All tests pass fast. 2010-03-30 09:02:51 -04:00
Jeremy Ashkenas
326656245a using the new static properties of class definitions in the CoffeeScript compiler -- it's hardly used. 2010-03-29 21:49:20 -04:00
Jeremy Ashkenas
177ec92c39 adding class methods to class definition syntax, using '@' 2010-03-29 21:43:12 -04:00
Jeremy Ashkenas
711dacae5f more little documentation for the rewriter ... moving along 2010-03-29 21:22:12 -04:00
Jeremy Ashkenas
c19183118e removing a case from Rewriter#add_implicit_parentheses that apparently never happens... 2010-03-29 20:52:22 -04:00
Jeremy Ashkenas
0af132d0c6 update internal documentation ... it's been a while 2010-03-29 20:48:41 -04:00
Jeremy Ashkenas
83c0e77ca8 making the Rewriter's add_implicit_calls more sensitive of parenthetical arguments. 2010-03-28 17:12:30 -04:00
Jeremy Ashkenas
1e315b5a33 fixing single-line implicit call wrapped around function with trailing arguments 2010-03-28 16:44:41 -04:00
Tim Jones
6e0e0767f9 Removed unprocessed values on a for loop from the grammar. 2010-03-29 07:32:01 +13:00
Tim Jones
6df50399a9 Restricted class and extends values to simple assignments. 2010-03-29 06:14:35 +13:00
Tim Jones
7b9a8998cf Addressing some assignment issues. 2010-03-29 06:06:16 +13:00
Jeremy Ashkenas
7de5253318 removing unused reserved variable 'source var' from range comprehensions 2010-03-27 16:04:47 -04:00
Jeremy Ashkenas
eaf4a71d32 Revert "Added Unix-like piping. Allows chaining of function calls where every succeeding call receives as first argument the result of all preceding expressions."
This reverts commit 7ee10e06be.
2010-03-27 15:25:34 -04:00
Jeremy Ashkenas
4dd40034ed Revert "removing the special case for | or"
This reverts commit 9763839ed1.
2010-03-27 15:25:27 -04:00
Jeremy Ashkenas
030476d335 Revert "typo for @compile_bitwise_or"
This reverts commit 45aae5e322.
2010-03-27 15:25:19 -04:00
Jeremy Ashkenas
45aae5e322 typo for @compile_bitwise_or 2010-03-27 12:13:24 -04:00
Jeremy Ashkenas
9763839ed1 removing the special case for | or 2010-03-27 10:28:08 -04:00
Stan Angeloff
7ee10e06be Added Unix-like piping. Allows chaining of function calls where every succeeding call receives as first argument the result of all preceding expressions. 2010-03-27 15:49:33 +02:00
matehat
8f3ea1d0c5 Fixed a small bug that happened when having a trailing comma in multiline array and object literals 2010-03-26 14:11:34 -04:00
matehat
b9b87f7d8e Minor modifications to the grammar to allow a single trailing comma for function call arguments, array literal and object literals. Adjusted tests accordingly 2010-03-26 11:44:25 -04:00
Jeremy Ashkenas
c8f969b4a2 adding a test case for the explicit returns 2010-03-25 18:54:17 -04:00
Jeremy Ashkenas
ecd1c77f48 fixing explicit returns of comprehensions (and probably other things as well) 2010-03-25 18:51:24 -04:00
Jeremy Ashkenas
ad93d2fe4d added another language extension test for a << b into a.push(b) 2010-03-23 20:42:40 -04:00
Jeremy Ashkenas
5a4d401582 make sure that the source-hacking docs mention to 'git checkout lib' 2010-03-23 00:25:37 -04:00
Jeremy Ashkenas
590c069158 CoffeeScript 0.5.6 2010-03-23 00:18:50 -04:00
Jeremy Ashkenas
94185e3f70 Merge branch 'master' of git://github.com/matehat/coffee-script 2010-03-22 23:20:05 -04:00
Jeremy Ashkenas
9adcd16ec6 '=' -> ':' 2010-03-22 18:48:41 -04:00
matehat
74bcd898e7 improving readability a bit 2010-03-22 02:02:04 -04:00
matehat
296808d4d3 Added splats positional flexibility to pattern matching 2010-03-22 01:52:47 -04:00
Jeremy Ashkenas
b7519cb834 switching a couple of the half_assignment tests to ensure that : and = are still interchangeable 2010-03-21 23:46:58 -04:00
Jeremy Ashkenas
7d6c050048 more half-assignment tests 2010-03-21 23:39:05 -04:00
Jeremy Ashkenas
16f9a2e6b7 rewriting the compiler to use half-expression assignment 2010-03-21 23:33:24 -04:00
Jeremy Ashkenas
cbfe7f5822 fix and tests for half assignments... whew. 2010-03-21 23:24:24 -04:00
Jeremy Ashkenas
895cd88761 almost there with half-assignments 2010-03-21 23:06:04 -04:00
Jeremy Ashkenas
f2ea18b0ba removing AND OR NOT IS ISNT from the grammar 2010-03-21 22:07:46 -04:00
Jeremy Ashkenas
162f6b9d5c one step at a time 2010-03-21 22:05:49 -04:00
Jeremy Ashkenas
4f8ae3ccbe one more step 2010-03-21 21:46:53 -04:00
Jeremy Ashkenas
acd9be3863 one step further 2010-03-21 21:46:06 -04:00
Jeremy Ashkenas
ddf18ae34c nothing much 2010-03-21 21:26:12 -04:00
Jeremy Ashkenas
0da61ec47e adding a couple of interchangeable tests 2010-03-21 21:07:32 -04:00
Jeremy Ashkenas
80230414a2 merging in gfxmonk's major refactor to the way that returns are pushed down into the interior of expressions 2010-03-21 11:28:05 -04:00
Jeremy Ashkenas
ce7c0d176b briefer test runner output 2010-03-21 10:18:23 -04:00
Jeremy Ashkenas
4ec79732f1 merging gfxmonk's cleanups 2010-03-21 10:11:02 -04:00
gfxmonk
cc3c314988 Cleaned up return logic
- ReturnNodes are explicitly added during compilation
 - ReturnNode is used instead of scattering "return" throughout
   code compilation snippets
 - nodes gain a make_return method in order to do the most useful
   thing when a return is requested
2010-03-21 22:21:55 +11:00
gfxmonk
8553a89af2 improve feedback when running the test task
- run synchronously, to ensure ordering is consistent
 - big red error message (and exit status)
 - don't bail early
 - don't bother printing a stack trace (it's useless
   until we can get line numbers in eval'd code)
2010-03-21 22:21:47 +11:00
Jeremy Ashkenas
566321d67a fixing infinite recursion when compiling if statements containing pure_statements 2010-03-20 10:36:06 -04:00
Jeremy Ashkenas
a2778bf06d resolving issues with comments in the middle of unfinished single-line expressions. 2010-03-20 00:58:25 -04:00
Jeremy Ashkenas
29eff23490 renaming test_curry to test_bind 2010-03-19 23:32:00 -04:00
Jeremy Ashkenas
4ebaa82563 removing the CoffeeScript.run named function from eval'd script scope by making it anonymous 2010-03-19 23:15:42 -04:00
Jeremy Ashkenas
69911209ea adding a pattern-matching-on-expression test 2010-03-19 22:48:55 -04:00
Jeremy Ashkenas
92688c89ef merging in matehat's nice refactor to splats (in arrays and otherwise) 2010-03-19 22:41:23 -04:00
matehat
fe04f8ce6b Added function call's flexibility with splats to array literals, factoring out splat compiling, and adjusted tests 2010-03-18 09:31:40 -04:00
Jeremy Ashkenas
b72641693d fixing doubled semis 2010-03-18 08:45:26 -04:00
Jeremy Ashkenas
0c6ee52cfc merging in matehat's curry branch. cleaning some loose ends up. adding some tests. 2010-03-18 00:42:26 -04:00
matehat
1f87094628 Slightly altered syntax, similar to Underscore's Function#bind form, highly simplified lexing and parsing and no polluted scope. Passing tests included. 2010-03-18 00:19:32 -04:00
matehat
3b22018296 Applied the new splat flexibility to function currying operator 2010-03-18 00:08:34 -04:00
matehat
5be437deb9 Added some inline docs 2010-03-18 00:08:34 -04:00
matehat
8d098194dd Added the '<-' currying operator, as heavily discussed in #251, along with tests. 2010-03-18 00:08:34 -04:00
matehat
256525bfa2 Fixed a small bug about flexible splats that occured when the leading array was a literal 2010-03-18 00:08:05 -04:00
Jeremy Ashkenas
79e4f30f69 fixing a bug where the Lexer assumed that values would always be strings. 2010-03-17 22:16:18 -04:00
Jeremy Ashkenas
884637468e fixing off-by-one error in compile_splat_arguments 2010-03-17 22:07:11 -04:00
Jeremy Ashkenas
6fd7810d89 can't use indexing[] into strings cross-browser, use substr() instead. 2010-03-17 21:41:00 -04:00
Jeremy Ashkenas
2f97d0d9b1 merging matehat's flexible splats (at any position within argument lists) 2010-03-17 21:15:54 -04:00
Jeremy Ashkenas
1bb9c57767 Merge branch 'splats' of git://github.com/matehat/coffee-script 2010-03-17 21:07:31 -04:00
Jeremy Ashkenas
d880b8b8f2 adding interpolation to heredocs, using the same rules as for strings 2010-03-17 20:47:27 -04:00
matehat
7129f518a4 Added the ability for function declaration to have a splat at an arbitrary position, not just at the end. Still restrict their number to 1. Adjusted tests accordingly. 2010-03-17 15:00:19 -04:00
matehat
fa6f1c2fb1 Fixed a tiny slicing bug 2010-03-17 15:00:19 -04:00
matehat
2bd1c3acca Added the ability to put as many splats in a function call as one wants. Also optimized the assembly into static arrays. Adjusted tests accordingly. 2010-03-17 15:00:19 -04:00
Jeremy Ashkenas
70cfc9500e pushing docs to the site 2010-03-16 23:18:54 -04:00
Jeremy Ashkenas
61b011cc28 fixing trailing whitespace on the final line 2010-03-16 19:57:39 -04:00
Jeremy Ashkenas
391135b1a5 fixing the relative path to 'grammar' 2010-03-16 19:36:08 -04:00
Jeremy Ashkenas
12d8d70573 fixing incorrectly-rooted relative paths in bin/cake and bin/coffee 2010-03-16 19:27:11 -04:00
Jeremy Ashkenas
04c5aeda2d Merge branch 'master' of git://github.com/matehat/coffee-script 2010-03-16 19:15:21 -04:00
Jeremy Ashkenas
25438be207 new docs for underscore 2010-03-16 19:13:13 -04:00
matehat
33f51d76f4 Added the possibility to end an identifier with '::', refering directly to its prototype. 2010-03-16 17:39:36 -04:00
Jeremy Ashkenas
e3021909c2 comments and tests 2010-03-16 06:54:49 -04:00
Jeremy Ashkenas
61dee1beba tweakin' 2010-03-15 23:10:14 -07:00
Jeremy Ashkenas
21e954eec3 updating module loading test 2010-03-15 23:08:58 -07:00
Jeremy Ashkenas
0b3054a348 merging in matehat's registerExtension patch for direct-requires of CoffeeScript. 2010-03-15 23:03:30 -07:00
Jeremy Ashkenas
02f4cb75dd removing deprecated references to process.mixin in favor of helpers.extend for Node 0.1.32 2010-03-15 22:53:25 -07:00
Jeremy Ashkenas
3aeb8c6bdb moving the contains-a-pure-statement-means-no-closure logic into ClosureNode.wrap itself. 2010-03-15 22:27:31 -07:00
Jeremy Ashkenas
8c2b2c7f80 merging in the fixed branch for gfxmonk/break_issue 2010-03-15 22:22:41 -07:00
Jeremy Ashkenas
745c635a55 fixing issue with break statements and for loops and closures and the value of 'this' 2010-03-15 22:20:29 -07:00
Jeremy Ashkenas
c7dd31846d merging in gfxmonk's fix for reporting line numbers for unclosed { [ ( opening symbols 2010-03-15 22:09:16 -07:00
gfxmonk
e87fa4293d report line number of opening token if a pair (eg bracket) is left open 2010-03-15 22:07:40 -07:00
gfxmonk
b269884f8d fixed non-recursive traverse() for CodeNode 2010-03-15 22:03:54 -07:00
Jeremy Ashkenas
3fed9761a6 let's make that non-greedy 2010-03-15 21:50:33 -07:00
Jeremy Ashkenas
6ccf196b61 adding another language extension test, with %w{} style ruby word array literals 2010-03-15 21:47:40 -07:00
Jeremy Ashkenas
a4bd8dc623 removing outdated arguments tests 2010-03-15 21:45:37 -07:00
Jeremy Ashkenas
34f01408c9 removing arguments-to-arrays from the docs 2010-03-15 20:53:43 -07:00
Jeremy Ashkenas
73074daa07 removing arguments-to-array-conversion from coffee 2010-03-15 20:46:14 -07:00
Jeremy Ashkenas
119b80d449 removing fiddling with require.paths from CoffeeScript 2010-03-15 20:39:46 -07:00
Jeremy Ashkenas
60b3103314 using granular helper imports, for nicer within. 2010-03-14 14:58:32 -07:00
Jeremy Ashkenas
75ffb9dc84 stop mixing in helpers (t(ticket #250) -- with a test 2010-03-14 14:48:43 -07:00
Jeremy Ashkenas
b306d40bf1 we don't need relative requires for the language 2010-03-14 13:48:58 -07:00
Jeremy Ashkenas
a27f146338 fixing 'cake test' to print out the name of the file with the failing test. 2010-03-14 09:33:41 -07:00
Jeremy Ashkenas
74995358cd updating the Cakefile for the new tmbundle location. 2010-03-14 08:59:55 -07:00
Jeremy Ashkenas
35da6c32b7 removing the tmbundle from the main repository. See jashkenas/coffee-script-tmbundle for the new one 2010-03-14 08:05:33 -07:00
Jeremy Ashkenas
701a5c7cb9 Merge branch 'master' of git://github.com/drnic/coffee-script 2010-03-14 07:39:02 -07:00
gfxmonk
3c3e7f666b added another "invalid break" example, with code not on the top-level 2010-03-14 13:02:36 +11:00
gfxmonk
89dfa1fd7a added code to illustrate an issue with break statements 2010-03-14 13:02:35 +11:00
gfxmonk
1da00f0ee3 added a test case for broken "break" statement 2010-03-14 11:35:56 +11:00
gfxmonk
5809a1637f fixed non-recursive traverse() for CodeNode 2010-03-14 00:05:51 +11:00
gfxmonk
e47bea34d5 report line number of opening token if a pair (eg bracket) is left open 2010-03-14 00:03:17 +11:00
matehat
709f17c278 Added an extension on node's 'require' module so it can import .coffee module and added some tests to make sure it works. 2010-03-12 14:22:01 -05:00
Jeremy Ashkenas
3c597dde72 no need to save the lookups 2010-03-10 22:32:00 -05:00
Jeremy Ashkenas
0379431812 tweaks 2010-03-10 21:53:33 -05:00
Jeremy Ashkenas
3f9fd85afb removing the unused CallNode#push 2010-03-10 20:53:31 -05:00
Jeremy Ashkenas
7b0a235c71 removing the nearly-unused notion of 'operation sensitive' 2010-03-10 20:19:32 -05:00
Jeremy Ashkenas
55cac23976 fixing indentation for prefix while nodes 2010-03-10 20:15:12 -05:00
Dr Nic Williams
22a16a3e33 added two snippets for creating functions; matching tab/key triggers from JavaScript bundle 2010-03-11 10:27:25 +10:00
Dr Nic Williams
db555d12ea can set Grammar via Shift+Ctrl+Alt+C 2010-03-11 10:16:34 +10:00
Jeremy Ashkenas
b9f1390405 adding more comment tests -- this terminator/comment as-block business really seems to have opened them up a bit 2010-03-10 16:44:50 -05:00
Jeremy Ashkenas
f2d0aee656 added Stan's fix for try/finally without catch 2010-03-10 16:27:30 -05:00
Jeremy Ashkenas
2a47727641 allowing terminator/comment as a block, so that you can have comment-only blocks 2010-03-10 16:18:17 -05:00
Jeremy Ashkenas
ccb7f63b8a fixing exports for the browser 2010-03-10 09:47:02 -05:00
Jeremy Ashkenas
1f9bb6a1c4 fixing broken multi-line optional-paren blocks 2010-03-10 09:28:00 -05:00
Jeremy Ashkenas
21b5d2cac5 tweaks to the helper docs, if they're going to be published 2010-03-10 00:05:30 -05:00
Jeremy Ashkenas
56eeeebed1 updating the docco 2010-03-09 23:53:21 -05:00
Jeremy Ashkenas
54627f6807 CoffeeScript language extensions are now working. 2010-03-09 23:44:29 -05:00
Jeremy Ashkenas
5754d36fdd adding the broken test 2010-03-09 23:32:54 -05:00
Jeremy Ashkenas
3d14d362a8 first draft of CoffeeScript language extensions. 2010-03-09 23:04:16 -05:00
Jeremy Ashkenas
472e027463 fixing the nested-implicit-parens-on-a-single-line 2010-03-09 21:54:44 -05:00
Jeremy Ashkenas
b297510d2b big refactor -- pulled all helper functions into helpers.coffee to facilitate sharing. 2010-03-09 21:24:30 -05:00
Jeremy Ashkenas
4932d25540 making balanced_string accept an array of delimiters, in hope of using it in the Rewriter 2010-03-09 20:53:56 -05:00
Jeremy Ashkenas
b6c3b743f0 Merge branch 'tm_highlighting' of git://github.com/cehoffman/coffee-script 2010-03-09 19:45:52 -05:00
Jeremy Ashkenas
1b4edd0e37 scrubbing all carriage returns from CoffeeScript source before compiling for the benefit of Windows users. 2010-03-08 23:07:26 -05:00
Jeremy Ashkenas
dcb00b4fe8 minor refactors to balanced_string 2010-03-08 22:48:14 -05:00
Jeremy Ashkenas
b33b688373 fixing more bugs in balance/interpolate/regexp/string/etc 2010-03-08 22:25:06 -05:00
Jeremy Ashkenas
4b97b15c0c more refactors to interpolation 2010-03-08 21:55:06 -05:00
Chris Hoffman
93c0774036 Regex interpolation highlighting 2010-03-08 20:48:23 -06:00
Chris Hoffman
645885d72d Merge branch 'master' of git://github.com/jashkenas/coffee-script 2010-03-08 20:34:36 -06:00
Jeremy Ashkenas
b5af5f66fb more regexp and string interpolation tweaks 2010-03-08 21:34:10 -05:00
Chris Hoffman
fb04f8900a Merge branch 'master' of git://github.com/jashkenas/coffee-script 2010-03-08 20:12:40 -06:00
Jeremy Ashkenas
3396dce2bb waypoint -- going to try to clean up regex_token 2010-03-08 20:57:28 -05:00
Jeremy Ashkenas
3291bd2a4a removing the 'supress' option from the lexer, just look at the slash. 2010-03-08 20:07:19 -05:00
Jeremy Ashkenas
121f01c06f merged stan's interpolation_3, a couple of tweaks 2010-03-08 19:43:12 -05:00
Jeremy Ashkenas
6cac2d57ba Merge commit 'StanAngeloff/interpolation_3' 2010-03-08 19:36:09 -05:00
Jeremy Ashkenas
c04b43e047 adding documentation for var shadowing 2010-03-08 19:27:38 -05:00
Jeremy Ashkenas
ff20732dd7 Merge branch 'tm_highlighting' of git://github.com/cehoffman/coffee-script 2010-03-08 19:14:34 -05:00
Stan Angeloff
81af8f296e Regular expression interpolations; fixed bug in string interpolations when all tokens were identifiers. 2010-03-08 20:06:51 +02:00
Stan Angeloff
830d1fb42b Merge branch 'master' of git://github.com/jashkenas/coffee-script into interpolation_3 2010-03-08 16:43:41 +02:00
Jeremy Ashkenas
e19cb48d3d Merge branch 'master' of git://github.com/uiru/coffee-script 2010-03-08 09:30:25 -05:00
Chris Hoffman
f755580b11 Match regex highlighting to how coffee parses it 2010-03-08 08:18:37 -06:00
Jeremy Ashkenas
81955005b9 doc tweaks 2010-03-08 09:13:15 -05:00
Will
62a871773b Include an extra line process.mixin require 'sys' on the top to let the .js output run using node (v0.1.31) 2010-03-09 01:03:43 +11:00
Chris Hoffman
5e52e7f19e While loop can be a single line expressions so don't indent when it is 2010-03-08 08:02:23 -06:00
Chris Hoffman
4c66a6a642 Merge branch 'master' of git://github.com/jashkenas/coffee-script 2010-03-08 07:33:45 -06:00
Chris Hoffman
9e1deecf13 Merge branch 'tm_highlighting' 2010-03-08 07:33:02 -06:00
Chris Hoffman
1ce93ccceb Indent function in symbol list based on indention in source 2010-03-08 07:30:15 -06:00
Chris Hoffman
4b04f8bec1 Add auto indent settings for textmate 2010-03-08 07:28:56 -06:00
Jeremy Ashkenas
5528bc7b2d scratch 'as seen above' 2010-03-08 06:44:47 -05:00
Jeremy Ashkenas
912f3b19f7 little tweaks to the docs 2010-03-08 06:40:54 -05:00
Chris Hoffman
9e5e85780b Don't highlight fresh[key]: val situations 2010-03-08 05:37:51 -06:00
Chris Hoffman
10aa3b3ae3 Revert "Properly highlight fresh[key]: val situations" 2010-03-08 05:37:07 -06:00
Jeremy Ashkenas
bcf7b3f95b CoffeeScript 0.5.5, with string interpolation and internal documentation 2010-03-08 06:34:07 -05:00
Chris Hoffman
07f1c784a4 Properly highlight fresh[key]: val situations 2010-03-08 05:29:01 -06:00
Chris Hoffman
465994cff9 Clean up some misplaced files 2010-03-08 05:26:38 -06:00
Chris Hoffman
697ad6cbda Merge remote branch 'origin' 2010-03-08 05:15:17 -06:00
Jeremy Ashkenas
a840671015 Finishing off the docs for nodes.coffee -- almost ready to roll. 2010-03-08 05:13:05 -06:00
Jeremy Ashkenas
7f0ab8308d making ThrowNode not a pure_statement -- it can jump out of the closure just fine 2010-03-08 05:13:05 -06:00
Jeremy Ashkenas
270b9fde04 waypoint -- documented down to the ThrowNode 2010-03-08 05:13:04 -06:00
Jeremy Ashkenas
993c9899cb Fixing up command-line args for --stdio and --eval. Now makes more sense with --run by default. 2010-03-08 05:13:04 -06:00
Jeremy Ashkenas
c8246e95f1 broke the flag for --no-wrap, fixed. 2010-03-08 05:13:04 -06:00
Stan Angeloff
f08de1ed4c Empty expression interpolations evaluate as empty strings now. 2010-03-08 05:13:04 -06:00
Jeremy Ashkenas
90f2e0dbb9 Merge branch 'tm_highlighting' of git://github.com/cehoffman/coffee-script 2010-03-08 06:11:15 -05:00
Chris Hoffman
80a3bd8951 Add variable assignment highlighting for textmate 2010-03-08 05:10:08 -06:00
Jeremy Ashkenas
b0aec3cbe2 Finishing off the docs for nodes.coffee -- almost ready to roll. 2010-03-08 05:42:57 -05:00
Jeremy Ashkenas
5f5e0634dd making ThrowNode not a pure_statement -- it can jump out of the closure just fine 2010-03-08 05:19:48 -05:00
Jeremy Ashkenas
049e605016 changing from storage.type... to variable.assignment -- it was a little garish in most color schemes I tried. 2010-03-08 05:16:45 -05:00
Jeremy Ashkenas
4687c3e140 Merge branch 'tm_highlighting' of git://github.com/cehoffman/coffee-script 2010-03-08 04:59:10 -05:00
Jeremy Ashkenas
6d74e223be waypoint -- documented down to the ThrowNode 2010-03-08 04:58:39 -05:00
Chris Hoffman
221427a6b4 Make variable assignment highlighting work in more cases 2010-03-08 03:55:03 -06:00
Chris Hoffman
3bf892128d Make old style classes show up as a function and don't let $\d be highlighted as a number 2010-03-08 03:47:49 -06:00
Chris Hoffman
abd7f939f2 Don't show object creation instances in symbol list for textmate 2010-03-08 03:46:38 -06:00
Jeremy Ashkenas
299e9918b9 Fixing up command-line args for --stdio and --eval. Now makes more sense with --run by default. 2010-03-08 04:46:24 -05:00
Chris Hoffman
eea83ff613 Add comment starter preference for textmate 2010-03-08 03:46:05 -06:00
Jeremy Ashkenas
9eceab667c broke the flag for --no-wrap, fixed. 2010-03-08 04:28:26 -05:00
Stan Angeloff
026e7649d5 Empty expression interpolations evaluate as empty strings now. 2010-03-08 04:13:59 -05:00
Chris Hoffman
c807da7664 Identify functions for symbol lookup and correct lookbehind assertion 2010-03-08 02:39:38 -06:00
Chris Hoffman
dde5db621d Add some TextMate triggers for string interpolation 2010-03-08 02:06:57 -06:00
Chris Hoffman
6b95cb4ee0 Fix the naked .property highlighting in interpolation to match coffee parsing 2010-03-08 01:40:04 -06:00
Stan Angeloff
a5f69ef716 Empty expression interpolations evaluate as empty strings now. 2010-03-08 09:31:31 +02:00
Chris Hoffman
accccb5f39 Allow $ to be the first character in a variable name for highlighting in textmate 2010-03-08 01:20:43 -06:00
Chris Hoffman
f8ddccd7d0 Escape $ in regexes where it was meant as character and not end of line 2010-03-08 01:05:52 -06:00
Chris Hoffman
e06e882962 Update highlighting for class definitions in textmate 2010-03-08 00:59:21 -06:00
Chris Hoffman
c3f74ca4f1 Add string interpolation highlighting and Cakefile highlighting 2010-03-08 00:43:04 -06:00
Jeremy Ashkenas
532464f7ae waypoint -- docs halfway down through the OpNode 2010-03-07 22:47:34 -05:00
Jeremy Ashkenas
570fb013e2 test tweaks 2010-03-07 22:29:46 -05:00
Jeremy Ashkenas
71ace9d8d0 allowing naked interpolation of dotted properties. .property 2010-03-07 22:26:25 -05:00
Jeremy Ashkenas
1cf0326183 unifying the CoffeeScript.compile and CoffeeScript.run apis to be the same -- source code and options hash. 2010-03-07 22:17:45 -05:00
Jeremy Ashkenas
5b9ebd19d5 adding source file information to all coffeescript compiles 2010-03-07 22:08:24 -05:00
Jeremy Ashkenas
6ce869b3fb adding a note about the 'git co lib' - build twice shuffle to the docs -- there's been more than one question about it already. 2010-03-07 21:57:08 -05:00
Jeremy Ashkenas
06b50ecb98 unifying all of the server-side evaluation under CoffeeScript.run -- this means that __filename and __dirname and relative requires should work from all angles under Node.js 2010-03-07 21:49:08 -05:00
Jeremy Ashkenas
0bc7719572 merging in Zaach's Jison updates 2010-03-07 19:11:03 -05:00
Jeremy Ashkenas
9028f79a27 Merge branch 'master' of git://github.com/zaach/coffee-script 2010-03-07 19:09:20 -05:00
Jeremy Ashkenas
a3e1693a75 waypoint -- docc'd down to the SplatNode 2010-03-07 19:07:37 -05:00
Zachary Carter
060b3e23c1 Merge branch 'master' of git://github.com/jashkenas/coffee-script 2010-03-07 18:59:54 -05:00
Zachary Carter
612c238157 Rebuild parser, now with skinnier parse table. 2010-03-07 18:53:23 -05:00
Zachary Carter
8adbc75811 Update Jison for table optimizations. 2010-03-07 18:48:15 -05:00
Jeremy Ashkenas
7485e5482c mention rlwrap in the docs on --interactive 2010-03-07 18:19:41 -05:00
Jeremy Ashkenas
659a5436a5 adding coffee-mode and rack-coffee to the Resources section of the docs 2010-03-07 17:52:14 -05:00
Jeremy Ashkenas
c6d7a27848 waypoint on the documentation -- almost halfway through the nodes 2010-03-07 17:31:39 -05:00
Jeremy Ashkenas
094b198d5d first little bit of commenting the nodes.coffee -- with some slight refactors 2010-03-07 16:41:06 -05:00
Jeremy Ashkenas
22b97a3b54 documenting scope.coffee -- nodes.coffee is the next, and last up to bat. 2010-03-07 15:45:45 -05:00
Jeremy Ashkenas
a4f7a5e248 documenting and cleaning up the Rewriter 2010-03-07 14:41:52 -05:00
Jeremy Ashkenas
45d8cf163e updating to the latest docco 2010-03-07 13:49:34 -05:00
Jeremy Ashkenas
d46daa1d7c documenting optparse.coffee and repl.coffee 2010-03-07 13:41:15 -05:00
Jeremy Ashkenas
4906cf1aff cleaned and commented the lexer (again) interpolate_string() continues to shrink 2010-03-07 12:47:03 -05:00
Stan Angeloff
f74fae58e3 Rewritting lexer.coffee to accept nested string interpolations. 2010-03-07 11:42:52 -05:00
Jeremy Ashkenas
1602e0e823 adding complete documentation for the grammar 2010-03-07 11:41:56 -05:00
Jeremy Ashkenas
202ebf06ff documentation for command.coffee 2010-03-07 00:28:58 -05:00
Jeremy Ashkenas
3e3b71724d making equality left-associative so that our chaining works properly with it. 2010-03-06 23:48:06 -05:00
Jeremy Ashkenas
893fb98522 moving command_line.coffee -> command.coffee 2010-03-06 22:18:15 -05:00
Jeremy Ashkenas
e267226438 commenting coffee-script.coffee for documentation 2010-03-06 20:30:40 -05:00
Jeremy Ashkenas
62626b712b Commenting cake.coffee for Docco docs. 2010-03-06 20:18:50 -05:00
Jeremy Ashkenas
7bdf14b210 Override process.argv as well as process.ARGV for eval'd scripts 2010-03-06 20:09:08 -05:00
Jeremy Ashkenas
87420e6504 updating the Function Binding docs with an improved explanation. 2010-03-06 19:29:41 -05:00
Jeremy Ashkenas
c73a3ec356 updating webserver example for node API 2010-03-06 19:23:25 -05:00
Jeremy Ashkenas
2e23e6a2dc removing narwhal.coffee and narwhal.js, because I don't think that anyone was using them. 2010-03-06 19:05:21 -05:00
Jeremy Ashkenas
5b3ef78101 adding a doc:source Cake task to document CoffeeScript's internals 2010-03-06 19:02:31 -05:00
Jeremy Ashkenas
9b262d56a5 allowing relative requires of JavaScript from directly-eval'd CoffeeScript. 2010-03-06 17:40:13 -05:00
Jeremy Ashkenas
453b43992d fixing line numbers in errors printed prior to parsing 2010-03-06 16:42:40 -05:00
Jeremy Ashkenas
a5e3617015 Adding a starts() helper to avoid substring() calls for simple matches. 2010-03-06 16:24:06 -05:00
Jeremy Ashkenas
c4ad6d1ee6 minor cleanups to balanced_group -> balanced_token, removing optional escaper (unused), and using it to implement interpolated javascript. 2010-03-06 16:06:47 -05:00
Stan Angeloff
f9cde1b46d Improving performance by removing call to bound function for every character in a string. Added a third option to \delimited\ to allow custom escape sequences. 2010-03-06 15:53:37 -05:00
Jeremy Ashkenas
03bc897b39 updating CoffeeScript docs to require Node 0.1.31 + 2010-03-06 15:48:20 -05:00
Stan Angeloff
83fd84745d Rewriting string tokenizer; allowing nested double-quoted strings inside expression interpolations. 2010-03-06 15:21:30 -05:00
Jeremy Ashkenas
e977967eb5 implementing the CoffeeScript compiler using interpolation where appropriate. 2010-03-06 13:59:11 -05:00
Jeremy Ashkenas
15b00cb3ca implementing string interpolation using string interpolation 2010-03-06 13:32:43 -05:00
Jeremy Ashkenas
18e5f72a84 done converting nodes.coffee code generation to use string interpolation where appropriate 2010-03-06 00:23:54 -05:00
Jeremy Ashkenas
47682de0f0 adding a test for intermingled identifier/expression interpolations 2010-03-05 22:54:39 -05:00
Jeremy Ashkenas
b4ea43cbd0 waypoint -- starting to implement nodes.coffee with interpolations, and fixing/shortening/combining the lexer implementation to allow identifier interpolations to be interleaved with expression interps 2010-03-05 22:52:28 -05:00
Jeremy Ashkenas
08341286a3 adding back parentheses wrapper around interpolated expressions -- we need it 2010-03-05 21:12:13 -05:00
Jeremy Ashkenas
4c3b0b9a74 allowing @properties to be referenced in naked interpolations 2010-03-05 21:05:31 -05:00
Jeremy Ashkenas
d250e9e9cc some edits to the interpolation path 2010-03-05 20:42:36 -05:00
Stan Angeloff
75be5eed62 Test line commented by mistake, no functional changes 2010-03-05 19:50:28 -05:00
Stan Angeloff
e2f86678a4 Allowing expressions to be used inside strings; syntax is $\{...\} 2010-03-05 19:50:20 -05:00
Stan Angeloff
fe7d5dfd19 Added string interpolation for identifiers 2010-03-05 19:49:48 -05:00
Jeremy Ashkenas
965034e16e add proper spacing to optparse by default 2010-03-04 22:59:03 -05:00
Jeremy Ashkenas
44398d044f Updating docs for CoffeeScript 0.5.4. Tag it and bag it. 2010-03-03 23:01:53 -05:00
Jeremy Ashkenas
3feb874b1e Merge branch 'path_fix' of git://github.com/cehoffman/coffee-script 2010-03-03 20:17:58 -05:00
Chris Hoffman
f7183e6918 Use new node api for resolving a chain of symlinks 2010-03-03 16:34:17 -06:00
Samuel Reis
707cd2d734 updated command_line.js 2010-03-03 14:32:28 +01:00
Samuel Reis
c11c3ed2f2 fix: process.watchFile has moved to fs.watchFile 2010-03-03 14:31:30 +01:00
Jeremy Ashkenas
5fd0972b5d improvement to comment handling that should ensure that they have no effect on indentation 2010-03-02 19:23:21 -05:00
Jeremy Ashkenas
70cb195e6f rebuilding extras/coffee-script.js 2010-03-02 16:52:55 -05:00
Jeremy Ashkenas
c219adffd5 removing special rule from rewriter for naked functions in arrays 2010-03-02 00:43:01 -05:00
Jeremy Ashkenas
cd6dd5abfd couple more tweaks to lexer.coffee 2010-02-28 21:39:07 -05:00
Jeremy Ashkenas
29ece0e6ba better commenting the coffeescript lexer as the first trial for docco 2010-02-28 20:44:33 -05:00
Jeremy Ashkenas
45bad556ab defining __filename and __dirname correctly as local variables for eval'd scripts 2010-02-28 19:56:00 -05:00
Jeremy Ashkenas
30cf63ec92 updating Underscore.coffee to Underscore.js version 0.6.0 2010-02-28 15:12:18 -05:00
Jeremy Ashkenas
969c2e528d a number of refactors to the Lexer. It should be a good bit clearer to read now. 2010-02-28 13:34:52 -05:00
Jeremy Ashkenas
bb2bf7ce57 allowing chaining of property accesses by indentation level (really nice for Node and jQuery work) ticket #221 2010-02-28 12:49:37 -05:00
Jeremy Ashkenas
2969e156c7 fixing require paths in the Cakefile so that build:jison will work, even if you don't have it installed. 2010-02-28 10:37:12 -05:00
Jeremy Ashkenas
b08995cbcc fixing heredocs with multiple double quotes (broken regex from the Ruby translation), with tests. 2010-02-28 10:29:30 -05:00
Jeremy Ashkenas
47f71f9193 updating docs to say 'Node.js greater than 0.1.30' 2010-02-28 10:11:01 -05:00
Jeremy Ashkenas
fec2eaef7e removing the (now-unused) inherits helper, and adding a helper for creating LiteralNodes 2010-02-28 00:22:06 -05:00
Jeremy Ashkenas
56eb474bf3 If you don't specify a constructor, one will be provided for you by the state. 2010-02-28 00:13:17 -05:00
Jeremy Ashkenas
62b2ab29cd CoffeeScript 0.5.3, with classes 2010-02-27 20:21:46 -05:00
Jeremy Ashkenas
a35693554c updating documentation for classes 2010-02-27 20:12:47 -05:00
Jeremy Ashkenas
f7427259ee reserving __extends and __hasProp 2010-02-27 20:03:57 -05:00
Jeremy Ashkenas
e02ab76edf converting the remainder of the CoffeeScript compiler (Rewriter, Scope, Optparse) to use classes 2010-02-27 19:46:45 -05:00
Jeremy Ashkenas
9f46c306e5 super is now possible in nodes/Expressions, where it wasn't possible before. 2010-02-27 19:42:10 -05:00
Jeremy Ashkenas
b5c9d779bd updating the Lexer to use classes and some of the older documentation 2010-02-27 19:40:53 -05:00
Jeremy Ashkenas
d2cb1f321e making sure that the body of extends only gets defined once per file. 2010-02-27 19:29:34 -05:00
Jeremy Ashkenas
8f871a8218 converting the nodes.coffee AST to use the new class system 2010-02-27 19:19:53 -05:00
Jeremy Ashkenas
4ec7514d10 making inner comments work within class definitions 2010-02-27 19:03:23 -05:00
Jeremy Ashkenas
1c7e4c4203 first draft of adding classes to CoffeeScript 2010-02-27 18:57:45 -05:00
Jeremy Ashkenas
7d39fe1c56 fixing multiple evaluation of splat sources, when it's an invoked function 2010-02-27 15:15:26 -05:00
Jeremy Ashkenas
afa26c37f1 fixing regexp literals versus division, with tests 2010-02-27 14:30:14 -05:00
Jeremy Ashkenas
2f658ba925 fixing multiple single-line function forms on the same line 2010-02-27 11:03:43 -05:00
Jeremy Ashkenas
0ab810e4cb fancy new fullscreen version of 'Try CoffeeScript' 2010-02-27 02:21:26 -05:00
Jeremy Ashkenas
37d086b670 rebuilding the browser code in anticipation of a page push 2010-02-27 01:38:50 -05:00
Jeremy Ashkenas
5e7f5f390a adding a traverse method to the AST, so we can do fancy processing from external scripts. 2010-02-27 01:22:21 -05:00
Jeremy Ashkenas
f4cd0bdf29 making --run the default option for consistency. If you want to save the file, use -c or --compile. 2010-02-27 00:38:04 -05:00
Jeremy Ashkenas
723ea53585 adding the long-ago-needed documentation for constructors with 'return this' 2010-02-26 20:09:49 -05:00
Jeremy Ashkenas
93f644fae2 finishing the second half of prefix installs. Using readLink to refer to the CoffeeScript installation reliably. 2010-02-26 19:49:12 -05:00
Jeremy Ashkenas
82951a469b adding favicon to docs 2010-02-26 19:10:56 -05:00
Jeremy Ashkenas
d2d5f649d3 caching the length property lookup for vanilla array comprehensions and rebuilding docs 2010-02-25 23:39:14 -05:00
Jeremy Ashkenas
5c7526a741 moving some of the fs methods over to sync methods, where it's alright and where it makes things clearer 2010-02-25 21:53:42 -05:00
Jeremy Ashkenas
17ea48c543 first draft of options for Cakefiles, using optparse.coffee, as well as a cake install task that takes --prefix. Still need to fix the lib/bin scripts 2010-02-25 21:43:42 -05:00
Jeremy Ashkenas
55ed202957 no outline on the Try CoffeeScript input for safari 2010-02-25 21:10:32 -05:00
Jeremy Ashkenas
d5df5505f9 hide the error div on initial page load 2010-02-25 20:48:54 -05:00
Jeremy Ashkenas
dc7f4b4be0 new live 'Try CoffeeScript' 2010-02-25 20:39:34 -05:00
Jeremy Ashkenas
406a18067d allowing merged short flags in optparse.coffee, via normalize_arguments 2010-02-25 19:06:08 -05:00
Jeremy Ashkenas
3ae2ebe5ea Merge branch 'fix_example_webserver' of git://github.com/hugs/coffee-script 2010-02-25 18:56:11 -05:00
Jeremy Ashkenas
a23dc6b753 raising an error on unrecognized options 2010-02-25 18:54:08 -05:00
Jeremy Ashkenas
5f1d3fd775 updating docs with the new flags 2010-02-25 18:43:33 -05:00
Jeremy Ashkenas
9d4e06e8a8 moving -tr --tree to -n --nodes, and --no-wrap gives up its -n short flag. 2010-02-25 18:42:35 -05:00
Jason Huggins
6bc61ec1a1 Fixed web_server example to be compatible with Node v0.1.30 2010-02-25 17:42:05 -06:00
Jeremy Ashkenas
c62f93f930 improving errors for undefined options, and error messages for compile attempts on nonexistent files 2010-02-25 18:36:43 -05:00
Jeremy Ashkenas
213ae1430e using text instead of html to escape entities in the rendered JS for Try CoffeeScript 2010-02-25 18:20:15 -05:00
Jeremy Ashkenas
ee5d738827 doc update 2010-02-25 17:18:28 -05:00
Jeremy Ashkenas
eab9bbf04f adding a test for nested pattern matching 2010-02-25 07:31:33 -05:00
Jeremy Ashkenas
4ed51536bb fixing patternmatched assigns within assigns within calls 2010-02-25 07:28:48 -05:00
Jeremy Ashkenas
b32a60585b improving CoffeeScript in browser script activation, and updating docs 2010-02-25 06:26:27 -05:00
Jeremy Ashkenas
66a6568fe7 cleaning and shrinking the option parser 2010-02-25 06:15:58 -05:00
Jeremy Ashkenas
fe32146adc cleaning and commenting cake.coffee 2010-02-25 01:17:43 -05:00
Jeremy Ashkenas
69feac3a01 adding return values for destructuring assignment. 2010-02-25 00:43:02 -05:00
150 changed files with 11492 additions and 6592 deletions

View File

@@ -1,5 +1,6 @@
fs: require 'fs'
coffee: require 'coffee-script'
helpers: require('./lib/helpers').helpers
CoffeeScript: require './lib/coffee-script'
# Run a CoffeeScript through our node/coffee interpreter.
run: (args) ->
@@ -7,59 +8,93 @@ run: (args) ->
proc.addListener 'error', (err) -> if err then puts err
task 'install', 'install CoffeeScript into /usr/local', ->
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options) ->
base: options.prefix or '/usr/local'
lib: "$base/lib/coffee-script"
bin: "$base/bin"
exec([
'mkdir -p /usr/local/lib/coffee-script'
'cp -rf bin lib LICENSE README package.json src vendor /usr/local/lib/coffee-script'
'ln -sf /usr/local/lib/coffee-script/lib/bin/coffee /usr/local/bin/coffee'
'ln -sf /usr/local/lib/coffee-script/lib/bin/cake /usr/local/bin/cake'
].join(' && '))
"mkdir -p $lib $bin"
"cp -rf bin lib LICENSE README package.json src vendor $lib"
"ln -sf $lib/bin/coffee $base/bin/coffee"
"ln -sf $lib/bin/cake $base/bin/cake"
].join(' && '), (err, stdout, stderr) ->
if err then print stderr
)
task 'build', 'build the CoffeeScript language from source', ->
fs.readdir 'src', (err, files) ->
files: 'src/' + file for file in files when file.match(/\.coffee$/)
run ['-o', 'lib'].concat(files)
files: fs.readdirSync 'src'
files: 'src/' + file for file in files when file.match(/\.coffee$/)
run ['-c', '-o', 'lib'].concat(files)
task 'build:full', 'rebuild the source twice, and run the tests', ->
exec 'bin/cake build && bin/cake build && bin/cake test', (err, stdout, stderr) ->
print stdout if stdout
print stderr if stderr
throw err if err
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
parser: require('grammar').parser
require.paths.unshift 'vendor/jison/lib'
parser: require('./lib/grammar').parser
js: parser.generate()
parser_path: 'lib/parser.js'
fs.writeFile parser_path, js
task 'build:ultraviolet', 'build and install the Ultraviolet syntax highlighter', ->
exec 'plist2syntax extras/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage', (err) ->
exec 'plist2syntax ../coffee-script-tmbundle/Syntaxes/CoffeeScript.tmLanguage', (err) ->
throw err if err
exec 'sudo mv coffeescript.yaml /usr/local/lib/ruby/gems/1.8/gems/ultraviolet-0.10.2/syntax/coffeescript.syntax'
task 'build:underscore', 'rebuild the Underscore.coffee documentation page', ->
exec 'uv -s coffeescript -t idle -h examples/underscore.coffee > documentation/underscore.html'
task 'build:browser', 'rebuild the merged script for inclusion in the browser', ->
exec 'rake browser'
exec 'rake browser', (err) ->
throw err if err
task 'doc', 'watch and continually rebuild the documentation', ->
task 'doc:site', 'watch and continually rebuild the documentation for the website', ->
exec 'rake doc'
task 'doc:source', 'rebuild the internal documentation', ->
exec 'docco src/*.coffee && cp -rf docs documentation && rm -r docs', (err) ->
throw err if err
task 'doc:underscore', 'rebuild the Underscore.coffee documentation page', ->
exec 'docco examples/underscore.coffee && cp -rf docs documentation && rm -r docs', (err) ->
throw err if err
task 'test', 'run the CoffeeScript language test suite', ->
process.mixin require 'assert'
test_count: 0
helpers.extend global, require 'assert'
passed_tests: failed_tests: 0
start_time: new Date()
[original_ok, original_throws]: [ok, throws]
process.mixin {
ok: (args...) -> test_count += 1; original_ok(args...)
throws: (args...) -> test_count += 1; original_throws(args...)
original_ok: ok
helpers.extend global, {
ok: (args...) -> passed_tests += 1; original_ok(args...)
CoffeeScript: CoffeeScript
}
process.addListener 'exit', ->
red: '\033[0;31m'
green: '\033[0;32m'
reset: '\033[0m'
on_exit: ->
time: ((new Date() - start_time) / 1000).toFixed(2)
puts '\033[0;32mpassed ' + test_count + ' tests in ' + time + ' seconds\033[0m'
message: "passed $passed_tests tests in $time seconds$reset"
puts(if failed_tests then "${red}failed $failed_tests and $message" else "$green$message")
process.addListener 'exit', on_exit
fs.readdir 'test', (err, files) ->
for file in files
fs.readFile 'test/' + file, (err, source) ->
js: coffee.compile source
process.compile js, file
files.forEach (file) ->
return unless file.match(/\.coffee$/i)
source: path.join 'test', file
fs.readFile source, (err, code) ->
try
CoffeeScript.run code, {source: source}
catch err
failed_tests += 1
puts "${red}failed:${reset} $source"
puts err.stack

23
README
View File

@@ -34,8 +34,27 @@
To suggest a feature, report a bug, or general discussion:
http://github.com/jashkenas/coffee-script/issues/
If you'd like to chat, drop by #coffeescript on Freenode.
If you'd like to chat, drop by #coffeescript on Freenode IRC,
or on webchat.freenode.net.
The source repository:
git://github.com/jashkenas/coffee-script.git
Contributors:
Stan Angeloff (StanAngeloff)
Jeremy Ashkenas (jashkenas)
Zach Carter (zaach)
Tim Cuthbertson (gfxmonk)
Mathieu D'Amours (matehat)
Chris Hoffman (cehoffman)
Jason Huggins (hugs)
Tim Jones (Tesco)
Matt Lyon (mattly)
Jeff Olson (olsonjeffery)
Samuel Reis (grgh)
Tom Robinson (tlrobinson)
Tim Smart (Tim-Smart)
Dr. Nic Williams (drnic)

View File

@@ -7,7 +7,7 @@ require 'yui/compressor'
desc "Build the documentation page"
task :doc do
source = 'documentation/index.html.erb'
child = fork { exec "bin/coffee documentation/coffee/*.coffee -o documentation/js -w" }
child = fork { exec "bin/coffee -c documentation/coffee/*.coffee -o documentation/js -w" }
at_exit { Process.kill("INT", child) }
Signal.trap("INT") { exit }
loop do
@@ -23,7 +23,7 @@ end
desc "Build the single concatenated and minified script for the browser"
task :browser do
sources = %w(rewriter.js lexer.js parser.js scope.js nodes.js coffee-script.js)
sources = %w(helpers.js rewriter.js lexer.js parser.js scope.js nodes.js coffee-script.js)
code = sources.map {|s| File.read('lib/' + s) }.join('')
code = YUI::JavaScriptCompressor.new.compress(code)
File.open('extras/coffee-script.js', 'w+') {|f| f.write(code) }

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env node
process.mixin(require('sys'));
var path = require('path');
var fs = require('fs');
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
require.paths.unshift(__dirname + '/../lib');
require('cake').run();
require(lib + '/helpers').helpers.extend(global, require('sys'));
require(lib + '/cake').run();

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env node
process.mixin(require('sys'));
var path = require('path');
var fs = require('fs');
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');
require.paths.unshift(__dirname + '/../lib');
require('command_line').run();
require(lib + '/helpers').helpers.extend(global, require('sys'));
require(lib + '/command').run();

View File

@@ -1,4 +0,0 @@
backwards: ->
alert arguments.reverse()
backwards "stairway", "to", "heaven"

View File

@@ -1,5 +1,5 @@
# Eat lunch.
lunch: eat(food) for food in ['toast', 'cheese', 'wine']
lunch: eat food for food in ['toast', 'cheese', 'wine']
# Naive collision detection.
for roid in asteroids

View File

@@ -0,0 +1,5 @@
url: "documentation/coffee/binding.coffee"
get_source: jQuery.get <- jQuery, url
get_source (response) -> alert response

View File

@@ -1,5 +1,3 @@
process.mixin require 'assert'
task 'test', 'run each of the unit tests', ->
for test in test_files
fs.readFile test, (err, code) -> eval coffee.compile code

View File

@@ -0,0 +1,29 @@
class Animal
move: (meters) ->
alert @name + " moved " + meters + "m."
class Snake extends Animal
constructor: (name) ->
@name: name
move: ->
alert "Slithering..."
super 5
class Horse extends Animal
constructor: (name) ->
@name: name
move: ->
alert "Galloping..."
super 45
sam: new Snake "Sammy the Python"
tom: new Horse "Tommy the Palomino"
sam.move()
tom.move()

View File

@@ -6,4 +6,4 @@ if happy and knows_it
date: if friday then sue else jill
expensive ||= do_the_math()
expensive: or do_the_math()

View File

@@ -0,0 +1,2 @@
author: "Wittgenstein"
quote: "A picture is a fact. -- $author"

View File

@@ -0,0 +1,6 @@
sentence: "${ 22 / 7 } is a decent approximation of π"
sep: "[.\\/\\- ]"
dates: /\d+$sep\d+$sep\d+/g

View File

@@ -0,0 +1,7 @@
tag: "<impossible>"
[open, contents..., close]: tag.split("")

View File

@@ -0,0 +1,2 @@
String::dasherize: ->
this.replace(/_/g, "-")

View File

@@ -1,34 +0,0 @@
Animal: ->
Animal::move: (meters) ->
alert @name + " moved " + meters + "m."
Snake: (name) ->
@name: name
this
Snake extends Animal
Snake::move: ->
alert "Slithering..."
super 5
Horse: (name) ->
@name: name
this
Horse extends Animal
Horse::move: ->
alert "Galloping..."
super 45
sam: new Snake "Sammy the Python"
tom: new Horse "Tommy the Palomino"
sam.move()
tom.move()

View File

@@ -8,7 +8,7 @@ div.container {
width: 950px;
margin: 100px 0 50px 50px;
}
p {
p, li {
width: 625px;
}
a {
@@ -105,6 +105,7 @@ div.code {
position: fixed;
z-index: 100;
height: 50px;
min-width: 490px;
left: 40px; right: 40px; top: 25px;
background: #ddd;
padding-left: 235px;
@@ -117,10 +118,23 @@ div.code {
#logo {
display: block;
width: 215px; height: 50px;
background: url('logo.png');
background: url('../images/logo.png');
position: absolute;
top: 0px; left: 10px;
}
#error {
position: absolute;
-webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px;
right: 15px; top: 15px; left: 722px;
height: 15px;
padding: 2px 5px;
background: #fdcdcc;
color: #864544;
border: 1px solid #864544;
font: 10px/15px Arial;
overflow: hidden;
text-transform: uppercase;
}
.navigation {
height: 50px;
font: bold 11px/50px Arial;
@@ -129,11 +143,14 @@ div.code {
float: left;
padding: 0 20px;
border: 1px solid #bbb;
border-top: 0; border-bottom: 0;
border-top: 0; border-bottom: 0; border-left-width: 0;
cursor: pointer;
}
.navigation.try {
border-left: 0;
body.full_screen .navigation {
position: static;
}
.navigation.toc {
border-left-width: 1px;
}
.navigation:hover,
.navigation.active {
@@ -161,20 +178,36 @@ div.code {
width: 700px;
padding: 0;
}
body.full_screen .navigation .contents.repl_wrapper {
position: fixed;
width: auto; height: auto;
left: 60px; top: 75px; right: 60px; bottom: 30px;
}
.navigation .contents.repl_wrapper .code {
-webkit-box-shadow: none; -moz-box-shadow: none;
background: transparent;
border: 0;
position: static;
}
body.full_screen .navigation .contents.repl_wrapper .code {
height: 100%;
padding: 0; margin: 0;
}
.navigation .code button {
bottom: 10px;
text-transform: none;
}
.navigation .compile {
left: 240px; right: auto;
.navigation .full_screen, .navigation .minimize {
right: auto;
left: 10px;
display: none;
}
body.minimized .full_screen, body.full_screen .minimize {
display: inline;
}
.navigation .contents a {
display: block;
width: 300px;
width: 290px;
text-transform: none;
text-decoration: none;
font-weight: normal;
@@ -195,19 +228,40 @@ div.code {
#repl_source, #repl_results {
background: transparent;
outline: none;
margin: 5px 0 20px;
}
#repl_source {
border: 0;
padding: 5px 7px;
#repl_source_wrap {
margin-left: 5px;
min-height: 250px;
resize: none;
width: 295px;
height: 250px;
width: 307px;
position: relative;
float: left;
}
#repl_source {
width: 96%;
height: 100%;
border: 0;
resize: none;
}
#repl_results {
font-family: Monaco, Consolas, "Lucida Console", monospace;
text-transform: none;
font-weight: normal;
min-height: 260px;
width: 355px;
}
height: 260px;
margin-bottom: 25px;
overflow-y: auto;
width: 370px;
}
body.full_screen #repl_results, body.full_screen #repl_source_wrap {
width: auto; height: auto;
position: absolute;
margin-bottom: 0;
top: 10px; left: 10px; right: 10px; bottom: 40px;
}
body.full_screen #repl_source_wrap {
right: 50%;
}
body.full_screen #repl_results {
left: 50%;
}

View File

@@ -57,6 +57,7 @@ pre.idle .FunctionName {
color: #21439C;
}
pre.idle .Variable {
color: #A535AE;
}
pre.idle .Comment {
color: #919191;

View File

@@ -0,0 +1,43 @@
<!DOCTYPE html> <html> <head> <title>cake.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> cake.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p><code>cake</code> is a simplified version of <a href="http://www.gnu.org/software/make/">Make</a>
(<a href="http://rake.rubyforge.org/">Rake</a>, <a href="http://github.com/280north/jake">Jake</a>)
for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
and can call them from the command line, or invoke them from other tasks.</p>
<p>Running <code>cake</code> with no arguments will print out a list of all the tasks in the
current directory's Cakefile.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>External dependencies.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs: </span> <span class="nx">require</span> <span class="s1">&#39;fs&#39;</span>
<span class="nv">path: </span> <span class="nx">require</span> <span class="s1">&#39;path&#39;</span>
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./helpers&#39;</span><span class="p">).</span><span class="nx">helpers</span>
<span class="nv">optparse: </span> <span class="nx">require</span> <span class="s1">&#39;./optparse&#39;</span>
<span class="nv">CoffeeScript: </span><span class="nx">require</span> <span class="s1">&#39;./coffee-script&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Keep track of the list of defined tasks, the accepted options, and so on.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tasks: </span><span class="p">{}</span>
<span class="nv">options: </span><span class="p">{}</span>
<span class="nv">switches: </span><span class="p">[]</span>
<span class="nv">oparse: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Mixin the top-level Cake functions for Cakefiles to use directly.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Define a Cake task with a short name, a sentence description,
and the function to run as the action itself.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">task: </span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">description</span><span class="p">,</span> <span class="nx">action</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="p">{</span><span class="nv">name: </span><span class="nx">name</span><span class="p">,</span> <span class="nv">description: </span><span class="nx">description</span><span class="p">,</span> <span class="nv">action: </span><span class="nx">action</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Define an option that the Cakefile accepts. The parsed options hash,
containing all of the command-line options passed, will be made available
as the first argument to the action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">option: </span><span class="p">(</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">switches</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Invoke another task in the current Cakefile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">invoke: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">no_such_task</span> <span class="nx">name</span> <span class="nx">unless</span> <span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span>
<span class="nx">tasks</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nx">action</span> <span class="nx">options</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Run <code>cake</code>. Executes all of the tasks you pass, in order. Note that Node's
asynchrony may cause tasks to execute in a different order than you'd expect.
If no tasks are passed, print the help screen.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run: </span><span class="o">-&gt;</span>
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="s1">&#39;Cakefile&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">exists</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&quot;Cakefile not found in ${process.cwd()}&quot;</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">exists</span>
<span class="nv">args: </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">...</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s1">&#39;Cakefile&#39;</span><span class="p">),</span> <span class="p">{</span><span class="nv">source: </span><span class="s1">&#39;Cakefile&#39;</span><span class="p">}</span>
<span class="nv">oparse: </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">switches</span>
<span class="k">return</span> <span class="nx">print_tasks</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">options: </span><span class="nx">oparse</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
<span class="nx">invoke</span> <span class="nx">arg</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Display the list of Cake tasks in a format similar to <code>rake -T</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">print_tasks: </span><span class="o">-&gt;</span>
<span class="nx">puts</span> <span class="s1">&#39;&#39;</span>
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">task</span> <span class="k">of</span> <span class="nx">tasks</span>
<span class="nv">spaces: </span><span class="mi">20</span> <span class="o">-</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">spaces: </span><span class="k">if</span> <span class="nx">spaces</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">then</span> <span class="p">(</span><span class="s1">&#39; &#39;</span> <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">..</span><span class="nx">spaces</span><span class="p">]).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nx">puts</span> <span class="s2">&quot;cake $name$spaces # ${task.description}&quot;</span>
<span class="nx">puts</span> <span class="nx">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Print an error and exit when attempting to all an undefined task.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">no_such_task: </span><span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">writeError</span> <span class="s2">&quot;No such task: \&quot;$task\&quot;\n&quot;</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,65 @@
<!DOCTYPE html> <html> <head> <title>coffee-script.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> coffee-script.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>CoffeeScript can be used both on the server, as a command-line compiler based
on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
contains the main entry functions for tokenzing, parsing, and compiling source
CoffeeScript into JavaScript.</p>
<p>If included on a webpage, it will automatically sniff out, compile, and
execute all scripts present in <code>text/coffeescript</code> tags.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up dependencies correctly for both the server and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
<span class="nv">path: </span> <span class="nx">require</span> <span class="s1">&#39;path&#39;</span>
<span class="nv">Lexer: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./lexer&#39;</span><span class="p">).</span><span class="nx">Lexer</span>
<span class="nv">parser: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./parser&#39;</span><span class="p">).</span><span class="nx">parser</span>
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./helpers&#39;</span><span class="p">).</span><span class="nx">helpers</span>
<span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="nx">require</span> <span class="s1">&#39;./nodes&#39;</span>
<span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span>
<span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span> <span class="s1">&#39;.coffee&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">compile</span> <span class="nx">content</span>
<span class="k">else</span>
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span><span class="p">.</span><span class="nv">CoffeeScript: </span><span class="p">{}</span>
<span class="nv">Lexer: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Lexer</span>
<span class="nv">parser: </span> <span class="k">this</span><span class="p">.</span><span class="nx">parser</span>
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The current CoffeeScript version number.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.VERSION: </span><span class="s1">&#39;0.6.0&#39;</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Instantiate a Lexer for our use here.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lexer: </span><span class="k">new</span> <span class="nx">Lexer</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.compile: compile: </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">options: </span><span class="o">or</span> <span class="p">{}</span>
<span class="k">try</span>
<span class="p">(</span><span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">options</span>
<span class="k">catch</span> <span class="nx">err</span>
<span class="nv">err.message: </span><span class="s2">&quot;In ${options.source}, ${err.message}&quot;</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">source</span>
<span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.tokens: </span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Tokenize and parse a string of CoffeeScript code, and return the AST. You can
then compile it by calling <code>.compile()</code> on the root, or traverse it by using
<code>.traverse()</code> with a callback.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.nodes: </span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Compile and execute a string of CoffeeScript (on the server), correctly
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run: </span><span class="p">((</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">module.filename: __filename: </span><span class="nx">options</span><span class="p">.</span><span class="nx">source</span>
<span class="nv">__dirname: </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">__filename</span><span class="p">)</span>
<span class="nb">eval</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span>
<span class="p">)</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Extend CoffeeScript with a custom language extension. It should hook in to
the <strong>Lexer</strong> (as a peer of any of the lexer's tokenizing methods), and
push a token on to the stack that contains a <strong>Node</strong> as the value (as a
peer of the nodes in <a href="nodes.html">nodes.coffee</a>).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.extend: </span><span class="p">(</span><span class="nx">func</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">Lexer</span><span class="p">.</span><span class="nx">extensions</span><span class="p">.</span><span class="nx">push</span> <span class="nx">func</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
thin wrapper around it, compatible with the Jison API. We can then pass it
directly as a "Jison lexer".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parser.lexer: </span><span class="p">{</span>
<span class="nv">lex: </span><span class="o">-&gt;</span>
<span class="nv">token: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">@pos</span><span class="p">]</span> <span class="o">or</span> <span class="p">[</span><span class="s2">&quot;&quot;</span><span class="p">]</span>
<span class="vi">@pos: </span><span class="o">+</span> <span class="mi">1</span>
<span class="k">this</span><span class="p">.</span><span class="nv">yylineno: </span><span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="k">this</span><span class="p">.</span><span class="nv">yytext: </span> <span class="nx">token</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">setInput: </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@tokens: </span><span class="nx">tokens</span>
<span class="vi">@pos: </span><span class="mi">0</span>
<span class="nv">upcomingInput: </span><span class="o">-&gt;</span> <span class="s2">&quot;&quot;</span>
<span class="nv">showPosition: </span><span class="o">-&gt;</span> <span class="nx">@pos</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Activate CoffeeScript in the browser by having it compile and evaluate
all script tags with a content-type of <code>text/coffeescript</code>. This happens
on page load. Unfortunately, the text contents of remote scripts cannot be
accessed from the browser, so only inline script tags will work.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nb">document</span><span class="o">?</span> <span class="o">and</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span>
<span class="nv">process_scripts: </span><span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">&#39;script&#39;</span><span class="p">)</span> <span class="k">when</span> <span class="nx">tag</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">&#39;text/coffeescript&#39;</span>
<span class="nb">eval</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">tag</span><span class="p">.</span><span class="nx">innerHTML</span>
<span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span> <span class="s1">&#39;load&#39;</span><span class="p">,</span> <span class="nx">process_scripts</span><span class="p">,</span> <span class="kc">false</span>
<span class="k">else</span> <span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">attachEvent</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">attachEvent</span> <span class="s1">&#39;onload&#39;</span><span class="p">,</span> <span class="nx">process_scripts</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,115 @@
<!DOCTYPE html> <html> <head> <title>command.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> command.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
into various forms: saved into <code>.js</code> files or printed to stdout, piped to
<a href="http://javascriptlint.com/">JSLint</a> or recompiled every time the source is
saved, printed as a token stream or as the syntax tree, or launch an
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>External dependencies.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs: </span> <span class="nx">require</span> <span class="s1">&#39;fs&#39;</span>
<span class="nv">path: </span> <span class="nx">require</span> <span class="s1">&#39;path&#39;</span>
<span class="nv">optparse: </span> <span class="nx">require</span> <span class="s1">&#39;./optparse&#39;</span>
<span class="nv">CoffeeScript: </span><span class="nx">require</span> <span class="s1">&#39;./coffee-script&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER: </span><span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> coffee compiles CoffeeScript source files into JavaScript.</span>
<span class="s1"> Usage:</span>
<span class="s1"> coffee path/to/script.coffee</span>
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>The list of all the valid option flags that <code>coffee</code> knows how to handle.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SWITCHES: </span><span class="p">[</span>
<span class="p">[</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--compile&#39;</span><span class="p">,</span> <span class="s1">&#39;compile to JavaScript and save as .js files&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-i&#39;</span><span class="p">,</span> <span class="s1">&#39;--interactive&#39;</span><span class="p">,</span> <span class="s1">&#39;run an interactive CoffeeScript REPL&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-o&#39;</span><span class="p">,</span> <span class="s1">&#39;--output [DIR]&#39;</span><span class="p">,</span> <span class="s1">&#39;set the directory for compiled JavaScript&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-w&#39;</span><span class="p">,</span> <span class="s1">&#39;--watch&#39;</span><span class="p">,</span> <span class="s1">&#39;watch scripts for changes, and recompile&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-p&#39;</span><span class="p">,</span> <span class="s1">&#39;--print&#39;</span><span class="p">,</span> <span class="s1">&#39;print the compiled JavaScript to stdout&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-l&#39;</span><span class="p">,</span> <span class="s1">&#39;--lint&#39;</span><span class="p">,</span> <span class="s1">&#39;pipe the compiled JavaScript through JSLint&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-s&#39;</span><span class="p">,</span> <span class="s1">&#39;--stdio&#39;</span><span class="p">,</span> <span class="s1">&#39;listen for and compile scripts over stdio&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-e&#39;</span><span class="p">,</span> <span class="s1">&#39;--eval&#39;</span><span class="p">,</span> <span class="s1">&#39;compile a string from the command line&#39;</span><span class="p">]</span>
<span class="p">[</span> <span class="s1">&#39;--no-wrap&#39;</span><span class="p">,</span> <span class="s1">&#39;compile without the top-level function wrapper&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-t&#39;</span><span class="p">,</span> <span class="s1">&#39;--tokens&#39;</span><span class="p">,</span> <span class="s1">&#39;print the tokens that the lexer produces&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-n&#39;</span><span class="p">,</span> <span class="s1">&#39;--nodes&#39;</span><span class="p">,</span> <span class="s1">&#39;print the parse tree that Jison produces&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-v&#39;</span><span class="p">,</span> <span class="s1">&#39;--version&#39;</span><span class="p">,</span> <span class="s1">&#39;display CoffeeScript version&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-h&#39;</span><span class="p">,</span> <span class="s1">&#39;--help&#39;</span><span class="p">,</span> <span class="s1">&#39;display this help message&#39;</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Top-level objects shared by all the functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">options: </span><span class="p">{}</span>
<span class="nv">sources: </span><span class="p">[]</span>
<span class="nv">option_parser: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Run <code>coffee</code> by parsing passed options and determining what action to take.
Many flags cause us to divert before compiling anything. Flags passed after
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run: </span><span class="o">-&gt;</span>
<span class="nx">parse_options</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">help</span>
<span class="k">return</span> <span class="nx">version</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">version</span>
<span class="k">return</span> <span class="nx">require</span> <span class="s1">&#39;./repl&#39;</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">interactive</span>
<span class="k">return</span> <span class="nx">compile_stdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">stdio</span>
<span class="k">return</span> <span class="nx">compile_script</span> <span class="s1">&#39;console&#39;</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nb">eval</span>
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">separator: </span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;--&#39;</span>
<span class="nv">flags: </span><span class="p">[]</span>
<span class="k">if</span> <span class="nx">separator</span> <span class="o">&gt;=</span> <span class="mi">0</span>
<span class="nv">flags: </span><span class="nx">sources</span><span class="p">[(</span><span class="nx">separator</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)...</span><span class="nx">sources</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span>
<span class="nv">sources: </span><span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">separator</span><span class="p">]</span>
<span class="nv">process.ARGV: process.argv: </span><span class="nx">flags</span>
<span class="nx">watch_scripts</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">watch</span>
<span class="nx">compile_scripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
compile them.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_scripts: </span><span class="o">-&gt;</span>
<span class="nv">compile: </span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">exists</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;File not found: $source&quot;</span> <span class="nx">unless</span> <span class="nx">exists</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">compile_script</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span>
<span class="nx">compile</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Compile a single source script, containing the given code, according to the
requested options. Both compile_scripts and watch_scripts share this method
in common. If evaluating the script directly sets <code>__filename</code>, <code>__dirname</code>
and <code>module.filename</code> to be correct relative to the script's path.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_script: </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o: </span><span class="nx">options</span>
<span class="nv">code_opts: </span><span class="nx">compile_options</span> <span class="nx">source</span>
<span class="k">try</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">tokens</span> <span class="k">then</span> <span class="nx">print_tokens</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">tokens</span> <span class="nx">code</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">puts</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</span><span class="p">(</span><span class="nx">code</span><span class="p">).</span><span class="nx">toString</span><span class="p">()</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">code_opts</span>
<span class="k">else</span>
<span class="nv">js: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">code_opts</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">write_js</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">js</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span> <span class="k">then</span> <span class="nx">lint</span> <span class="nx">js</span>
<span class="k">catch</span> <span class="nx">err</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">puts</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="k">else</span> <span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
and write them back to <strong>stdout</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_stdio: </span><span class="o">-&gt;</span>
<span class="nv">code: </span><span class="s1">&#39;&#39;</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">open</span><span class="p">()</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">code: </span><span class="o">+</span> <span class="nx">string</span> <span class="k">if</span> <span class="nx">string</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
<span class="nx">compile_script</span> <span class="s1">&#39;stdio&#39;</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Watch a list of source CoffeeScript files using <code>fs.watchFile</code>, recompiling
them every time the files are updated. May be used in combination with other
options, such as <code>--lint</code> or <code>--print</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">watch_scripts: </span><span class="o">-&gt;</span>
<span class="nv">watch: </span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">watchFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">{</span><span class="nv">persistent: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">interval: </span><span class="mi">500</span><span class="p">},</span> <span class="p">(</span><span class="nx">curr</span><span class="p">,</span> <span class="nx">prev</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">curr</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span> <span class="o">is</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">compile_script</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span>
<span class="nx">watch</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
are written out in <code>cwd</code> as <code>.js</code> files with the same name, but the output
directory can be customized with <code>--output</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">write_js: </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">js</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">filename: </span><span class="nx">path</span><span class="p">.</span><span class="nx">basename</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">))</span> <span class="o">+</span> <span class="s1">&#39;.js&#39;</span>
<span class="nv">dir: </span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span>
<span class="nv">js_path: </span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">filename</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">js_path</span><span class="p">,</span> <span class="nx">js</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
any errors or warnings that arise.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lint: </span><span class="p">(</span><span class="nx">js</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">jsl: </span><span class="nx">process</span><span class="p">.</span><span class="nx">createChildProcess</span><span class="p">(</span><span class="s1">&#39;jsl&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;-nologo&#39;</span><span class="p">,</span> <span class="s1">&#39;-stdin&#39;</span><span class="p">])</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">&#39;output&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">puts</span> <span class="nx">result</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="nx">result</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">puts</span> <span class="nx">result</span> <span class="k">if</span> <span class="nx">result</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">close</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">print_tokens: </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">strings: </span><span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">tokens</span>
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">token</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toString</span><span class="p">().</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/</span><span class="p">,</span> <span class="s1">&#39;\\n&#39;</span><span class="p">)]</span>
<span class="s2">&quot;[$tag $value]&quot;</span>
<span class="nx">puts</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parse_options: </span><span class="o">-&gt;</span>
<span class="nv">option_parser: </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
<span class="nv">o: options: </span> <span class="nx">option_parser</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">)</span>
<span class="nv">options.run: </span> <span class="o">not</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span><span class="p">)</span>
<span class="nv">options.print: </span><span class="o">!!</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nb">eval</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">stdio</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span><span class="p">))</span>
<span class="nv">sources: </span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">[</span><span class="mi">2</span><span class="p">...</span><span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_options: </span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o: </span><span class="p">{</span><span class="nv">source: </span><span class="nx">source</span><span class="p">}</span>
<span class="nx">o</span><span class="p">[</span><span class="s1">&#39;no_wrap&#39;</span><span class="p">]</span><span class="o">:</span> <span class="nx">options</span><span class="p">[</span><span class="s1">&#39;no-wrap&#39;</span><span class="p">]</span>
<span class="nx">o</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Print the <code>--help</code> usage message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">usage: </span><span class="o">-&gt;</span>
<span class="nx">puts</span> <span class="nx">option_parser</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Print the <code>--version</code> message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">version: </span><span class="o">-&gt;</span>
<span class="nx">puts</span> <span class="s2">&quot;CoffeeScript version ${CoffeeScript.VERSION}&quot;</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,185 @@
/*--------------------- Layout and Typography ----------------------------*/
body {
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
font-size: 16px;
line-height: 24px;
color: #252519;
margin: 0; padding: 0;
}
a {
color: #261a3b;
}
a:visited {
color: #261a3b;
}
p {
margin: 0 0 15px 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 40px 0 15px 0;
}
h3, h4, h5, h6 {
margin-top: 20px;
}
#container {
position: relative;
}
#background {
position: fixed;
top: 0; left: 580px; right: 0; bottom: 0;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
z-index: -1;
}
#jump_to, #jump_page {
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 10px Arial;
text-transform: uppercase;
cursor: pointer;
text-align: right;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
display: none;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 5px 10px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
table td {
border: 0;
outline: 0;
}
td.docs, th.docs {
max-width: 500px;
min-width: 500px;
min-height: 5px;
padding: 10px 25px 1px 50px;
vertical-align: top;
text-align: left;
}
.docs pre {
margin: 15px 0 15px;
padding-left: 15px;
}
.docs p tt, .docs p code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
.octowrap {
position: relative;
}
.octothorpe {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
td.docs:hover .octothorpe {
opacity: 1;
}
td.code, th.code {
padding: 14px 15px 16px 50px;
width: 100%;
vertical-align: top;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
}
pre, tt, code {
font-size: 12px; line-height: 18px;
font-family: Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
body .hll { background-color: #ffffcc }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #954121 } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #954121 } /* Keyword.Constant */
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #954121 } /* Keyword.Pseudo */
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #219161 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #954121 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
body .nv { color: #19469D } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #219161 } /* Literal.String.Backtick */
body .sc { color: #219161 } /* Literal.String.Char */
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #219161 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #219161 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { color: #954121 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #219161 } /* Literal.String.Single */
body .ss { color: #19469D } /* Literal.String.Symbol */
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
body .vc { color: #19469D } /* Name.Variable.Class */
body .vg { color: #19469D } /* Name.Variable.Global */
body .vi { color: #19469D } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@@ -0,0 +1,410 @@
<!DOCTYPE html> <html> <head> <title>grammar.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> grammar.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript parser is generated by <a href="http://github.com/zaach/jison">Jison</a>
from this grammar file. Jison is a bottom-up parser generator, similar in
style to <a href="http://www.gnu.org/software/bison">Bison</a>, implemented in JavaScript.
It can recognize <a href="http://en.wikipedia.org/wiki/LR_grammar">LALR(1), LR(0), SLR(1), and LR(1)</a>
type grammars. To create the Jison parser, we list the pattern to match
on the left-hand side, and the action to take (usually the creation of syntax
tree nodes) on the right. As the parser runs, it
shifts tokens from our token stream, from left to right, and
<a href="http://en.wikipedia.org/wiki/Bottom-up_parsing">attempts to match</a>
the token sequence against the rules below. When a match can be made, it
reduces into the <a href="http://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols">nonterminal</a>
(the enclosing name at the top), and we proceed from there.</p>
<p>If you run the <code>cake build:parser</code> command, Jison constructs a parse table
from our rules and saves it into <code>lib/parser.js</code>.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>The only dependency is on the <strong>Jison.Parser</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">Parser: </span><span class="nx">require</span><span class="p">(</span><span class="s1">&#39;jison&#39;</span><span class="p">).</span><span class="nx">Parser</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <h2>Jison DSL</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Since we're going to be wrapped in a function by Jison in any case, if our
action immediately returns a value, we can optimize by removing the function
wrapper and just returning the value directly.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">unwrap: </span><span class="sr">/function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Our handy DSL for Jison grammar generation, thanks to
<a href="http://github.com/creationix">Tim Caswell</a>. For every rule in the grammar,
we pass the pattern-defining string, the action to run, and extra options,
optionally. If no action is specified, we simply pass the value of the
previous nonterminal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">o: </span><span class="p">(</span><span class="nx">pattern_string</span><span class="p">,</span> <span class="nx">action</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="p">[</span><span class="nx">pattern_string</span><span class="p">,</span> <span class="s1">&#39;$$ = $1;&#39;</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">action</span>
<span class="nv">action: </span><span class="k">if</span> <span class="nv">match: </span><span class="p">(</span><span class="nx">action</span> <span class="o">+</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">match</span><span class="p">(</span><span class="nx">unwrap</span><span class="p">)</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="s2">&quot;($action())&quot;</span>
<span class="p">[</span><span class="nx">pattern_string</span><span class="p">,</span> <span class="s2">&quot;$$ = $action;&quot;</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <h2>Grammatical Rules</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>In all of the rules that follow, you'll see the name of the nonterminal as
the key to a list of alternative matches. With each match's action, the
dollar-sign variables are provided by Jison as references to the value of
their numeric position, so in this rule:</p>
<pre><code>"Expression UNLESS Expression"
</code></pre>
<p><code>$1</code> would be the value of the first <code>Expression</code>, <code>$2</code> would be the token
for the <code>UNLESS</code> terminal, and <code>$3</code> would be the value of the second
<code>Expression</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">grammar: </span><span class="p">{</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>The <strong>Root</strong> is the top-level node in the syntax tree. Since we parse bottom-up,
all parsing must end here.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Root: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
<span class="nx">o</span> <span class="s2">&quot;TERMINATOR&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
<span class="nx">o</span> <span class="s2">&quot;Expressions&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Block TERMINATOR&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Any list of expressions or method body, seperated by line breaks or
semicolons.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Expressions: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;Expressions TERMINATOR Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expressions TERMINATOR&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>All the different types of expressions in our language. The basic unit of
CoffeeScript is the <strong>Expression</strong> -- you'll notice that there is no
"statement" nonterminal. Expressions serve as the building blocks
of many other rules, making them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Expression: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Value&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Call&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Curry&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Code&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Operation&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Assign&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;If&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Try&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Throw&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Return&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;While&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;For&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Switch&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Extends&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Class&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Splat&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Existence&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Comment&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Extension&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>A an indented block of expressions. Note that the <a href="rewriter.html">Rewriter</a>
will convert some postfix forms into blocks for us, by adjusting the
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Block: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;INDENT Expressions OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;INDENT OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
<span class="nx">o</span> <span class="s2">&quot;TERMINATOR Comment&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>A literal identifier, a variable name or property.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Identifier: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;IDENTIFIER&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
they can also serve as keys in object literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AlphaNumeric: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;NUMBER&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="nx">o</span> <span class="s2">&quot;STRING&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>All of our immediate values. These can (in general), be passed straight
through and printed to JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Literal: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;AlphaNumeric&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;JS&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="nx">o</span> <span class="s2">&quot;REGEX&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="nx">o</span> <span class="s2">&quot;BREAK&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="nx">o</span> <span class="s2">&quot;CONTINUE&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="nx">o</span> <span class="s2">&quot;TRUE&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s2">&quot;FALSE&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
<span class="nx">o</span> <span class="s2">&quot;YES&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s2">&quot;NO&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
<span class="nx">o</span> <span class="s2">&quot;ON&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s2">&quot;OFF&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Assignment of a variable, property, or index to a value.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assign: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Assignable ASSIGN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Assignment when it happens within an object literal. The difference from
the ordinary <strong>Assign</strong> is that these allow numbers and strings as keys.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AssignObj: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Identifier ASSIGN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">$1</span><span class="p">),</span> <span class="nx">$3</span><span class="p">,</span> <span class="s1">&#39;object&#39;</span>
<span class="nx">o</span> <span class="s2">&quot;AlphaNumeric ASSIGN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">$1</span><span class="p">),</span> <span class="nx">$3</span><span class="p">,</span> <span class="s1">&#39;object&#39;</span>
<span class="nx">o</span> <span class="s2">&quot;Comment&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>A return statement from a function body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Return: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;RETURN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ReturnNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;RETURN&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ReturnNode</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">&#39;null&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>A comment. Because CoffeeScript passes comments through to JavaScript, we
have to parse comments like any other construct, and identify all of the
positions in which they can occur in the grammar.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Comment: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;COMMENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CommentNode</span> <span class="nx">yytext</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p><a href="http://jashkenas.github.com/coffee-script/#existence">The existential operator</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Existence: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Expression ?&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ExistenceNode</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>The <strong>Code</strong> node is the function literal. It's defined by an indented block
of <strong>Expressions</strong> preceded by a function arrow, with an optional parameter
list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Code: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;PARAM_START ParamList PARAM_END FuncGlyph Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CodeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span><span class="p">,</span> <span class="nx">$4</span>
<span class="nx">o</span> <span class="s2">&quot;FuncGlyph Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CodeNode</span> <span class="p">[],</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>CoffeeScript has two different symbols for functions. <code>-&gt;</code> is for ordinary
functions, and <code>=&gt;</code> is for functions bound to the current value of <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">FuncGlyph: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;-&gt;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="s1">&#39;func&#39;</span>
<span class="nx">o</span> <span class="s2">&quot;=&gt;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="s1">&#39;boundfunc&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>The list of parameters that a function accepts can be of any length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ParamList: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[]</span>
<span class="nx">o</span> <span class="s2">&quot;Param&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ParamList , Param&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>A single parameter in a function definition can be ordinary, or a splat
that hoovers up the remaining arguments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Param: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;PARAM&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
<span class="nx">o</span> <span class="s2">&quot;Param . . .&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">SplatNode</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Splat: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Expression . . .&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">SplatNode</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">SimpleAssignable: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s2">&quot;Value Accessor&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;Invocation Accessor&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ThisProperty&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assignable: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;SimpleAssignable&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Array&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s2">&quot;Object&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
as functions, indexed into, named as a class, etc.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Value: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Assignable&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Literal&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s2">&quot;Parenthetical&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s2">&quot;Range&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s2">&quot;This&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;NULL&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">&#39;null&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>The general group of accessors into an object, by property, by prototype
or by array index or slice.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Accessor: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;PROPERTY_ACCESS Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;PROTOTYPE_ACCESS Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">&#39;prototype&#39;</span>
<span class="nx">o</span> <span class="s2">&quot;::&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AccessorNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">LiteralNode</span><span class="p">(</span><span class="s1">&#39;prototype&#39;</span><span class="p">))</span>
<span class="nx">o</span> <span class="s2">&quot;SOAK_ACCESS Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">&#39;soak&#39;</span>
<span class="nx">o</span> <span class="s2">&quot;Index&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Slice&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">SliceNode</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Index: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;INDEX_START Expression INDEX_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IndexNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;SOAKED_INDEX_START Expression SOAKED_INDEX_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IndexNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">&#39;soak&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;{ AssignList }&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;{ IndentedAssignList }&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;{ AssignList , }&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;{ IndentedAssignList , }&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>Assignment of properties within an object literal can be separated by
comma, as in JavaScript, or simply by newline.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AssignList: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[]</span>
<span class="nx">o</span> <span class="s2">&quot;AssignObj&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;AssignList , AssignObj&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;AssignList TERMINATOR AssignObj&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;AssignList , TERMINATOR AssignObj&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$4</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>An <strong>AssignList</strong> within a block indentation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IndentedAssignList: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;INDENT AssignList OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;INDENT AssignList , OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <p>Class definitions have optional bodies of prototype property assignments,
and optional references to the superclass.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Class: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;CLASS SimpleAssignable&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;CLASS SimpleAssignable EXTENDS Value&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span>
<span class="nx">o</span> <span class="s2">&quot;CLASS SimpleAssignable INDENT ClassBody OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$4</span>
<span class="nx">o</span> <span class="s2">&quot;CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$6</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <p>Assignments that can happen directly inside a class declaration.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ClassAssign: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;AssignObj&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s2">&quot;ThisProperty ASSIGN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">$1</span><span class="p">),</span> <span class="nx">$3</span><span class="p">,</span> <span class="s1">&#39;this&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>A list of assignments to a class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ClassBody: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[]</span>
<span class="nx">o</span> <span class="s2">&quot;ClassAssign&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ClassBody TERMINATOR ClassAssign&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-36">#</a> </div> <p>The three flavors of function call: normal, object instantiation with <code>new</code>,
and calling <code>super()</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Call: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Invocation&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;NEW Invocation&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">new_instance</span><span class="p">()</span>
<span class="nx">o</span> <span class="s2">&quot;Super&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-37">#</a> </div> <p>Binds a function call to a context and/or arguments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Curry: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Value &lt;- Arguments&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CurryNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-38">#</a> </div> <p>Extending an object by setting its prototype chain to reference a parent
object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Extends: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;SimpleAssignable EXTENDS Value&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ExtendsNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-39">#</a> </div> <p>Ordinary function invocation, or a chained series of calls.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Invocation: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Value Arguments&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;Invocation Arguments&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Arguments: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;CALL_START ArgList CALL_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;CALL_START ArgList , CALL_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>Calling super.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Super: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;SUPER CALL_START ArgList CALL_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">&#39;super&#39;</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;SUPER CALL_START ArgList , CALL_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">&#39;super&#39;</span><span class="p">,</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">This: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;THIS&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">&#39;this&#39;</span>
<span class="nx">o</span> <span class="s2">&quot;@&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">&#39;this&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ThisProperty: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;@ Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span><span class="p">(</span><span class="s1">&#39;this&#39;</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">AccessorNode</span><span class="p">(</span><span class="nx">$2</span><span class="p">)]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Range: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;[ Expression . . Expression ]&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span>
<span class="nx">o</span> <span class="s2">&quot;[ Expression . . . Expression ]&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>The slice literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Slice: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;INDEX_START Expression . . Expression INDEX_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span>
<span class="nx">o</span> <span class="s2">&quot;INDEX_START Expression . . . Expression INDEX_END&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</a> </div> <p>The array literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Array</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;[ ArgList ]&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;[ ArgList , ]&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</a> </div> <p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
as well as the contents of an array literal
(i.e. comma-separated expressions). Newlines work as well.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ArgList: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[]</span>
<span class="nx">o</span> <span class="s2">&quot;Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;INDENT Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ArgList , Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ArgList TERMINATOR Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ArgList , TERMINATOR Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$4</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ArgList , INDENT Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$4</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;ArgList OUTDENT&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;ArgList , OUTDENT&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
this to be separate from the <strong>ArgList</strong> for use in <strong>Switch</strong> blocks, where
having the newlines wouldn't make sense.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">SimpleArgs: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Expression&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;SimpleArgs , Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">$1</span> <span class="k">instanceof</span> <span class="nb">Array</span> <span class="k">then</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span><span class="p">([</span><span class="nx">$3</span><span class="p">])</span> <span class="k">else</span> <span class="p">[</span><span class="nx">$1</span><span class="p">].</span><span class="nx">concat</span><span class="p">([</span><span class="nx">$3</span><span class="p">])</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>The variants of <em>try/catch/finally</em> exception handling blocks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Try: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;TRY Block Catch&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">TryNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;TRY Block FINALLY Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">TryNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$4</span>
<span class="nx">o</span> <span class="s2">&quot;TRY Block Catch FINALLY Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">TryNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">$5</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p>A catch clause names its error and runs a block of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Catch: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;CATCH Identifier Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Throw: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;THROW Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ThrowNode</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
not an <strong>Expression</strong>, so if you need to use an expression in a place
where only values are accepted, wrapping it in parentheses will always do
the trick.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Parenthetical: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;( Expression )&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ParentheticalNode</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</a> </div> <p>A language extension to CoffeeScript from the outside. We simply pass
it through unaltered.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Extension: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;EXTENSION&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">yytext</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-54">#</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">WhileSource: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;WHILE Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;WHILE Expression WHEN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">filter : </span><span class="nx">$4</span><span class="p">}</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-55">#</a> </div> <p>The while loop can either be normal, with a block of expressions to execute,
or postfix, with a single expression. There is no do..while.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">While: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;WhileSource Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_body</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;Expression WhileSource&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">add_body</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-56">#</a> </div> <p>Array, object, and range comprehensions, at the most generic level.
Comprehensions can either be normal, with a block of expressions to execute,
or postfix, with a single expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">For: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Expression FOR ForVariables ForSource&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;FOR ForVariables ForSource Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-57">#</a> </div> <p>An array or range comprehension has variables for the current element and
(optional) reference to the current index. Or, <em>key, value</em>, in the case
of object comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ForVariables: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s2">&quot;Identifier , Identifier&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-58">#</a> </div> <p>The source of a comprehension is an array or object with an optional filter
clause. If it's an array comprehension, you can also choose to step through
in fixed-size increments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ForSource: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;IN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;OF Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;IN Expression WHEN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;OF Expression WHEN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;IN Expression BY Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;IN Expression WHEN Expression BY Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">;</span> <span class="nv">step: </span> <span class="nx">$6</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;IN Expression BY Expression WHEN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$6</span><span class="p">}</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-59">#</a> </div> <p>The CoffeeScript switch/when/else block replaces the JavaScript
switch/case/default by compiling into an if-else chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Switch: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;SWITCH Expression INDENT Whens OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$4</span><span class="p">.</span><span class="nx">rewrite_condition</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;SWITCH Expression INDENT Whens ELSE Block OUTDENT&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$4</span><span class="p">.</span><span class="nx">rewrite_condition</span><span class="p">(</span><span class="nx">$2</span><span class="p">).</span><span class="nx">add_else</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-60">#</a> </div> <p>The inner list of whens is left recursive. At code-generation time, the
IfNode will rewrite them into a proper chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Whens: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;When&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Whens When&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-61">#</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">When: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;LEADING_WHEN SimpleArgs Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;LEADING_WHEN SimpleArgs Block TERMINATOR&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;Comment TERMINATOR When&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nv">$3.comment: </span><span class="nx">$1</span><span class="p">;</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-62">#</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
if-related rules are broken up along these lines in order to avoid
ambiguity.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfStart: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;IF Expression Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;IfStart ElsIf&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-63">#</a> </div> <p>An <strong>IfStart</strong> can optionally be followed by an else block.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfBlock: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;IfStart&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;IfStart ELSE Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-64">#</a> </div> <p>An <em>else if</em> continuation of the <em>if</em> expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ElsIf: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;ELSE IF Expression Block&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="k">new</span> <span class="nx">IfNode</span><span class="p">(</span><span class="nx">$3</span><span class="p">,</span> <span class="nx">$4</span><span class="p">)).</span><span class="nx">force_statement</span><span class="p">()</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-65">#</a> </div> <p>The full complement of <em>if</em> expressions, including postfix one-liner
<em>if</em> and <em>unless</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">If: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;IfBlock&quot;</span>
<span class="nx">o</span> <span class="s2">&quot;Expression IF Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
<span class="nx">o</span> <span class="s2">&quot;Expression UNLESS Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-66">#</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
Here they are grouped by order of precedence. The actual precedence rules
are defined at the bottom of the page. It would be shorter if we could
combine most of these rules into a single generic <em>Operand OpSymbol Operand</em>
-type rule, but in order to make the precedence binding possible, separate
rules are necessary.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Operation: </span><span class="p">[</span>
<span class="nx">o</span> <span class="s2">&quot;! Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;!&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;!! Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;!!&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span><span class="p">(</span><span class="s2">&quot;- Expression&quot;</span><span class="p">,</span> <span class="p">(</span><span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="nx">$2</span><span class="p">)),</span> <span class="p">{</span><span class="nv">prec: </span><span class="s1">&#39;UMINUS&#39;</span><span class="p">})</span>
<span class="nx">o</span><span class="p">(</span><span class="s2">&quot;+ Expression&quot;</span><span class="p">,</span> <span class="p">(</span><span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span><span class="p">(</span><span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="nx">$2</span><span class="p">)),</span> <span class="p">{</span><span class="nv">prec: </span><span class="s1">&#39;UPLUS&#39;</span><span class="p">})</span>
<span class="nx">o</span> <span class="s2">&quot;~ Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;~&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;-- Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;--&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;++ Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;++&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;DELETE Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;delete&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;TYPEOF Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;typeof&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s2">&quot;Expression --&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;--&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s2">&quot;Expression ++&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;++&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s2">&quot;Expression * Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;*&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression / Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression % Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;%&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression + Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression - Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &lt;&lt; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&lt;&lt;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &gt;&gt; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&gt;&gt;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &gt;&gt;&gt; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&gt;&gt;&gt;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &amp; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&amp;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression | Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;|&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression ^ Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;^&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &lt;= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&lt;=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &lt; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&lt;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &gt; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &gt;= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&gt;=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression == Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;==&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression != Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;!=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &amp;&amp; Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&amp;&amp;&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression || Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;||&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression ? Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;?&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression -= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;-=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression += Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;+=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression /= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;/=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression *= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;*=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression %= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;%=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression ||= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;||=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression &amp;&amp;= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;&amp;&amp;=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression ?= Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;?=&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression INSTANCEOF Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;instanceof&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s2">&quot;Expression IN Expression&quot;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">&#39;in&#39;</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="p">]</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-67">#</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-68">#</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
<pre><code>2 + (3 * 4)
</code></pre>
<p>And not:</p>
<pre><code>(2 + 3) * 4
</code></pre> </td> <td class="code"> <div class="highlight"><pre><span class="nv">operators: </span><span class="p">[</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;?&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;nonassoc&quot;</span><span class="p">,</span> <span class="s1">&#39;UMINUS&#39;</span><span class="p">,</span> <span class="s1">&#39;UPLUS&#39;</span><span class="p">,</span> <span class="s1">&#39;!&#39;</span><span class="p">,</span> <span class="s1">&#39;!!&#39;</span><span class="p">,</span> <span class="s1">&#39;~&#39;</span><span class="p">,</span> <span class="s1">&#39;++&#39;</span><span class="p">,</span> <span class="s1">&#39;--&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">,</span> <span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="s1">&#39;%&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;-&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;&lt;&lt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&gt;&gt;&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;&amp;&#39;</span><span class="p">,</span> <span class="s1">&#39;|&#39;</span><span class="p">,</span> <span class="s1">&#39;^&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;&lt;=&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;DELETE&#39;</span><span class="p">,</span> <span class="s1">&#39;INSTANCEOF&#39;</span><span class="p">,</span> <span class="s1">&#39;TYPEOF&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;==&#39;</span><span class="p">,</span> <span class="s1">&#39;!=&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;&amp;&amp;&#39;</span><span class="p">,</span> <span class="s1">&#39;||&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;-=&#39;</span><span class="p">,</span> <span class="s1">&#39;+=&#39;</span><span class="p">,</span> <span class="s1">&#39;/=&#39;</span><span class="p">,</span> <span class="s1">&#39;*=&#39;</span><span class="p">,</span> <span class="s1">&#39;%=&#39;</span><span class="p">,</span> <span class="s1">&#39;||=&#39;</span><span class="p">,</span> <span class="s1">&#39;&amp;&amp;=&#39;</span><span class="p">,</span> <span class="s1">&#39;?=&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;.&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;WHEN&#39;</span><span class="p">,</span> <span class="s1">&#39;LEADING_WHEN&#39;</span><span class="p">,</span> <span class="s1">&#39;IN&#39;</span><span class="p">,</span> <span class="s1">&#39;OF&#39;</span><span class="p">,</span> <span class="s1">&#39;BY&#39;</span><span class="p">,</span> <span class="s1">&#39;THROW&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;FOR&#39;</span><span class="p">,</span> <span class="s1">&#39;NEW&#39;</span><span class="p">,</span> <span class="s1">&#39;SUPER&#39;</span><span class="p">,</span> <span class="s1">&#39;CLASS&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;left&quot;</span><span class="p">,</span> <span class="s1">&#39;EXTENDS&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;ASSIGN&#39;</span><span class="p">,</span> <span class="s1">&#39;RETURN&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s2">&quot;right&quot;</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;-&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#39;</span><span class="p">,</span> <span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;WHILE&#39;</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-69">#</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-70">#</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
terminals (every symbol which does not appear as the name of a rule above)
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tokens: </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">alternatives</span> <span class="k">of</span> <span class="nx">grammar</span>
<span class="nx">grammar</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="k">for</span> <span class="nx">alt</span> <span class="k">in</span> <span class="nx">alternatives</span>
<span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">alt</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">split</span> <span class="s1">&#39; &#39;</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span> <span class="nx">unless</span> <span class="nx">grammar</span><span class="p">[</span><span class="nx">token</span><span class="p">]</span>
<span class="nx">alt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;return ${alt[1]}&quot;</span> <span class="k">if</span> <span class="nx">name</span> <span class="o">is</span> <span class="s1">&#39;Root&#39;</span>
<span class="nx">alt</span></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-71">#</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
rules, and the name of the root. Reverse the operators because Jison orders
precedence from low to high, and we have it high to low
(as in <a href="http://dinosaur.compilertools.net/yacc/index.html">Yacc</a>).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.parser: </span><span class="k">new</span> <span class="nx">Parser</span> <span class="p">{</span>
<span class="nv">tokens: </span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">join</span> <span class="s1">&#39; &#39;</span>
<span class="nv">bnf: </span> <span class="nx">grammar</span>
<span class="nv">operators: </span> <span class="nx">operators</span><span class="p">.</span><span class="nx">reverse</span><span class="p">()</span>
<span class="nv">startSymbol: </span> <span class="s1">&#39;Root&#39;</span>
<span class="p">}</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,59 @@
<!DOCTYPE html> <html> <head> <title>helpers.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> helpers.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>This file contains the common helper functions that we'd like to share among
the <strong>Lexer</strong>, <strong>Rewriter</strong>, and the <strong>Nodes</strong>. Merge objects, flatten
arrays, count characters, that sort of thing.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both <strong>Node.js</strong> and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">process</span><span class="o">?</span>
<span class="nv">helpers: exports.helpers: </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Does a list include a value?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.include: include: </span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">list</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Peek at the beginning of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.starts: starts: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">start</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">string</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">start</span><span class="p">,</span> <span class="p">(</span><span class="nx">start</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="o">is</span> <span class="nx">literal</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.compact: compact: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Count the number of occurences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.count: count: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">num: </span><span class="mi">0</span>
<span class="nv">pos: </span><span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">letter</span><span class="p">)</span>
<span class="k">while</span> <span class="nx">pos</span> <span class="o">isnt</span> <span class="o">-</span><span class="mi">1</span>
<span class="nv">num: </span><span class="o">+</span> <span class="mi">1</span>
<span class="nv">pos: </span><span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="nx">num</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Merge objects, returning a fresh copy with attributes from both sides.
Used every time <code>BaseNode#compile</code> is called, to allow properties in the
options hash to propagate down the tree without polluting other branches.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.merge: merge: </span><span class="p">(</span><span class="nx">options</span><span class="p">,</span> <span class="nx">overrides</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">fresh: </span><span class="p">{}</span>
<span class="p">(</span><span class="nx">fresh</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">options</span>
<span class="p">(</span><span class="nx">fresh</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">overrides</span> <span class="k">if</span> <span class="nx">overrides</span>
<span class="nx">fresh</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Extend a source object with the properties of another object (shallow copy).
We use this to simulate Node's deprecated <code>process.mixin</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.extend: extend: </span><span class="p">(</span><span class="nx">object</span><span class="p">,</span> <span class="nx">properties</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Return a completely flattened version of an array. Handy for getting a
list of <code>children</code> from the nodes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.flatten: flatten: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">memo: </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span>
<span class="k">if</span> <span class="nx">item</span> <span class="k">instanceof</span> <span class="nb">Array</span> <span class="k">then</span> <span class="nv">memo: </span><span class="nx">memo</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="k">else</span> <span class="nx">memo</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span>
<span class="nx">memo</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Delete a key from an object, returning the value. Useful when a node is
looking for a particular method in an options hash.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.del: del: </span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">val: </span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
<span class="k">delete</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
<span class="nx">val</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Matches a balanced group such as a single or double-quoted string. Pass in
a series of delimiters, all of which must be nested correctly within the
contents of the string. This method allows us to have strings within
interpolations within strings, ad infinitum.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.balanced_string: balanced_string: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">delimited</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">options: </span><span class="o">or</span> <span class="p">{}</span>
<span class="nv">slash: </span><span class="nx">delimited</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;/&#39;</span>
<span class="nv">levels: </span><span class="p">[]</span>
<span class="nv">i: </span><span class="mi">0</span>
<span class="k">while</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span>
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">&#39;\\&#39;</span><span class="p">,</span> <span class="nx">i</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="k">else</span>
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">delimited</span>
<span class="p">[</span><span class="nx">open</span><span class="p">,</span> <span class="nx">close</span><span class="p">]</span><span class="o">:</span> <span class="nx">pair</span>
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">and</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">close</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">and</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="nx">pair</span>
<span class="nx">levels</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nv">i: </span><span class="o">+</span> <span class="nx">close</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span>
<span class="k">break</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">i</span>
<span class="nx">levels</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">pair</span><span class="p">)</span>
<span class="nv">i: </span><span class="o">+</span> <span class="nx">open</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">break</span>
<span class="k">break</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span> <span class="o">or</span> <span class="nx">slash</span> <span class="o">and</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span><span class="p">,</span> <span class="nx">i</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="k">if</span> <span class="nx">levels</span><span class="p">.</span><span class="nx">length</span>
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">slash</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}&quot;</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">i</span> <span class="k">then</span> <span class="kc">false</span> <span class="k">else</span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,375 @@
<!DOCTYPE html> <html> <head> <title>lexer.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lexer.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
matches against the beginning of the source code. When a match is found,
a token is produced, we consume the match, and start again. Tokens are in the
form:</p>
<pre><code>[tag, value, line_number]
</code></pre>
<p>Which is a format that can be fed directly into <a href="http://github.com/zaach/jison">Jison</a>.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up the Lexer for both Node.js and the browser, depending on where we are.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
<span class="nv">Rewriter: </span><span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./rewriter&#39;</span><span class="p">).</span><span class="nx">Rewriter</span>
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./helpers&#39;</span><span class="p">).</span><span class="nx">helpers</span>
<span class="k">else</span>
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
<span class="nv">Rewriter: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Rewriter</span>
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">include: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">include</span>
<span class="nv">count: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">count</span>
<span class="nv">starts: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">starts</span>
<span class="nv">compact: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span>
<span class="nv">balanced_string: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">balanced_string</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <h2>The Lexer Class</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
tokens. Some potential ambiguity in the grammar has been avoided by
pushing some extra smarts into the Lexer.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Lexer: </span><span class="nx">class</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p><strong>tokenize</strong> is the Lexer's main method. Scan by attempting to match tokens
one at a time, using a regular expression anchored at the start of the
remaining code, or a custom recursive token-matching method
(for interpolations). When the next token has been recorded, we move forward
within the code past the token, and begin again.</p>
<p>Each tokenizing method is responsible for incrementing <code>@i</code> by the number of
characters it has consumed. <code>@i</code> can be thought of as our finger on the page
of source.</p>
<p>Before returning the token stream, run it through the <a href="rewriter.html">Rewriter</a>
unless explicitly asked not to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tokenize: </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">code : </span><span class="nx">code</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/(\r|\s+$)/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span>
<span class="nv">o : </span><span class="nx">options</span> <span class="o">or</span> <span class="p">{}</span>
<span class="vi">@code : </span><span class="nx">code</span> <span class="c1"># The remainder of the source code.</span>
<span class="vi">@i : </span><span class="mi">0</span> <span class="c1"># Current character position we&#39;re parsing.</span>
<span class="vi">@line : </span><span class="nx">o</span><span class="p">.</span><span class="nx">line</span> <span class="o">or</span> <span class="mi">0</span> <span class="c1"># The current line.</span>
<span class="vi">@indent : </span><span class="mi">0</span> <span class="c1"># The current indentation level.</span>
<span class="vi">@indents : </span><span class="p">[]</span> <span class="c1"># The stack of all current indentation levels.</span>
<span class="vi">@tokens : </span><span class="p">[]</span> <span class="c1"># Stream of parsed tokens in the form [&#39;TYPE&#39;, value, line]</span>
<span class="k">while</span> <span class="nx">@i</span> <span class="o">&lt;</span> <span class="nx">@code</span><span class="p">.</span><span class="nx">length</span>
<span class="vi">@chunk: </span><span class="nx">@code</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">@i</span>
<span class="nx">@extract_next_token</span><span class="p">()</span>
<span class="nx">@close_indentation</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">@tokens</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">rewrite</span> <span class="o">is</span> <span class="kc">off</span>
<span class="p">(</span><span class="k">new</span> <span class="nx">Rewriter</span><span class="p">()).</span><span class="nx">rewrite</span> <span class="nx">@tokens</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>At every position, run through this list of attempted matches,
short-circuiting if any of them succeed. Their order determines precedence:
<code>@literal_token</code> is the fallback catch-all.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">extract_next_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@extension_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@identifier_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@number_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@heredoc_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@regex_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@comment_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@line_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@whitespace_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@js_token</span><span class="p">()</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@string_token</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">@literal_token</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <h2>Tokenizers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Language extensions get the highest priority, first chance to tag tokens
as something else.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">extension_token: </span><span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">extension</span> <span class="k">in</span> <span class="nx">Lexer</span><span class="p">.</span><span class="nx">extensions</span>
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">extension</span><span class="p">.</span><span class="nx">call</span> <span class="k">this</span>
<span class="kc">false</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Matches identifying literals: variables, keywords, method names, etc.
Check to ensure that JavaScript reserved words aren't being used as
identifiers. Because CoffeeScript reserves a handful of keywords that are
allowed in JavaScript, we're careful not to tag them as keywords when
referenced as property names here, so you can still do <code>jQuery.is()</code> even
though <code>is</code> means <code>===</code> otherwise.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifier_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">id: </span><span class="nx">@match</span> <span class="nx">IDENTIFIER</span><span class="p">,</span> <span class="mi">1</span>
<span class="nx">@name_access_type</span><span class="p">()</span>
<span class="nv">accessed: </span><span class="nx">include</span> <span class="nx">ACCESSORS</span><span class="p">,</span> <span class="nx">@tag</span> <span class="mi">0</span>
<span class="nv">tag: </span><span class="s1">&#39;IDENTIFIER&#39;</span>
<span class="nv">tag: </span><span class="nx">id</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">()</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">accessed</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">KEYWORDS</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span>
<span class="nx">@identifier_error</span> <span class="nx">id</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">RESERVED</span><span class="p">,</span> <span class="nx">id</span>
<span class="nv">tag: </span><span class="s1">&#39;LEADING_WHEN&#39;</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;WHEN&#39;</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">id</span><span class="p">.</span><span class="nx">length</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">accessed</span>
<span class="nv">tag: id: </span><span class="nx">CONVERSIONS</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">COFFEE_ALIASES</span><span class="p">,</span> <span class="nx">id</span>
<span class="k">return</span> <span class="nx">@tag_half_assignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">@prev</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@prev</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;ASSIGN&#39;</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">id</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Matches numbers, including decimals, hex, and exponential notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">number_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">number: </span><span class="nx">@match</span> <span class="nx">NUMBER</span><span class="p">,</span> <span class="mi">1</span>
<span class="nx">@token</span> <span class="s1">&#39;NUMBER&#39;</span><span class="p">,</span> <span class="nx">number</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">number</span><span class="p">.</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Matches strings, including multi-line strings. Ensures that quotation marks
are balanced within the string's contents, and within nested interpolations.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">string_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">@chunk</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">)</span> <span class="o">or</span> <span class="nx">starts</span><span class="p">(</span><span class="nx">@chunk</span><span class="p">,</span> <span class="s2">&quot;&#39;&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">string:</span>
<span class="nx">@balanced_token</span><span class="p">([</span><span class="s1">&#39;&quot;&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;${&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">])</span> <span class="o">or</span>
<span class="nx">@balanced_token</span> <span class="p">[</span><span class="s2">&quot;&#39;&quot;</span><span class="p">,</span> <span class="s2">&quot;&#39;&quot;</span><span class="p">]</span>
<span class="nx">@interpolate_string</span> <span class="nx">string</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">STRING_NEWLINES</span><span class="p">,</span> <span class="s2">&quot; \\\n&quot;</span>
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">string</span><span class="p">,</span> <span class="s2">&quot;\n&quot;</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Matches heredocs, adjusting indentation to the correct level, as heredocs
preserve whitespace, but ignore indentation to the left.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">heredoc_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">HEREDOC</span><span class="p">)</span>
<span class="nv">quote: </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">substr</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
<span class="nv">doc: </span><span class="nx">@sanitize_heredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">or</span> <span class="nx">match</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="nx">quote</span>
<span class="nx">@interpolate_string</span> <span class="s2">&quot;$quote$doc$quote&quot;</span>
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">&quot;\n&quot;</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">js_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">starts</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="s1">&#39;`&#39;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">script: </span><span class="nx">@balanced_token</span> <span class="p">[</span><span class="s1">&#39;`&#39;</span><span class="p">,</span> <span class="s1">&#39;`&#39;</span><span class="p">]</span>
<span class="nx">@token</span> <span class="s1">&#39;JS&#39;</span><span class="p">,</span> <span class="nx">script</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">JS_CLEANER</span><span class="p">,</span> <span class="s1">&#39;&#39;</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">script</span><span class="p">.</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Matches regular expression literals. Lexing regular expressions is difficult
to distinguish from division, so we borrow some basic heuristics from
JavaScript and Ruby, borrow slash balancing from <code>@balanced_token</code>, and
borrow interpolation from <code>@interpolate_string</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">regex_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">REGEX_START</span>
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">NOT_REGEX</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">regex: </span><span class="nx">@balanced_token</span> <span class="p">[</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="s1">&#39;/&#39;</span><span class="p">]</span>
<span class="nv">regex: </span><span class="o">+</span> <span class="p">(</span><span class="nv">flags: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">length</span><span class="p">).</span><span class="nx">match</span> <span class="nx">REGEX_FLAGS</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">match</span> <span class="nx">REGEX_INTERPOLATION</span>
<span class="nv">str: </span><span class="nx">regex</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">str: </span><span class="nx">str</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">REGEX_ESCAPE</span><span class="p">,</span> <span class="p">(</span><span class="nx">escaped</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s1">&#39;\\&#39;</span> <span class="o">+</span> <span class="nx">escaped</span>
<span class="vi">@tokens: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[[</span><span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;NEW&#39;</span><span class="p">,</span> <span class="s1">&#39;new&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;RegExp&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;CALL_START&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">]]</span>
<span class="nx">@interpolate_string</span> <span class="s2">&quot;\&quot;$str\&quot;&quot;</span><span class="p">,</span> <span class="kc">yes</span>
<span class="vi">@tokens: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[[</span><span class="s1">&#39;,&#39;</span><span class="p">,</span> <span class="s1">&#39;,&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s2">&quot;\&quot;$flags\&quot;&quot;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">]]</span>
<span class="k">else</span>
<span class="nx">@token</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="nx">regex</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Matches a token in which which the passed delimiter pairs must be correctly
balanced (ie. strings, JS literals).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">balanced_token: </span><span class="p">(</span><span class="nx">delimited</span><span class="p">...)</span> <span class="o">-&gt;</span>
<span class="nx">balanced_string</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="nx">delimited</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Matches and conumes comments. We pass through comments into JavaScript,
so they're treated as real tokens, like any other part of the language.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">comment_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">comment: </span><span class="nx">@match</span> <span class="nx">COMMENT</span><span class="p">,</span> <span class="mi">1</span>
<span class="vi">@line: </span><span class="o">+</span> <span class="p">(</span><span class="nx">comment</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">)</span> <span class="o">or</span> <span class="p">[]).</span><span class="nx">length</span>
<span class="nv">lines: </span><span class="nx">compact</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">COMMENT_CLEANER</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">split</span> <span class="nx">MULTILINER</span>
<span class="nv">i: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">if</span> <span class="nx">@unfinished</span><span class="p">()</span>
<span class="nv">i: </span><span class="o">-</span> <span class="mi">1</span> <span class="k">while</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;COMMENT&#39;</span><span class="p">,</span> <span class="nx">lines</span><span class="p">,</span> <span class="nx">@line</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span><span class="p">,</span> <span class="nx">@line</span><span class="p">])</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Matches newlines, indents, and outdents, and determines which is which.
If we can detect that the current line is continued onto the the next line,
then the newline is suppressed:</p>
<pre><code>elements
.each( ... )
.map( ... )
</code></pre>
<p>Keeps track of the level of indentation, because a single outdent token
can close multiple indents, so we need to know how far in we happen to be.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">line_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">indent: </span><span class="nx">@match</span> <span class="nx">MULTI_DENT</span><span class="p">,</span> <span class="mi">1</span>
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">).</span><span class="nx">length</span>
<span class="vi">@i : </span><span class="o">+</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="nv">size: </span><span class="nx">indent</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LAST_DENTS</span><span class="p">).</span><span class="nx">reverse</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">match</span><span class="p">(</span><span class="nx">LAST_DENT</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
<span class="nv">next_character: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTI_DENT</span><span class="p">)[</span><span class="mi">4</span><span class="p">]</span>
<span class="nv">no_newlines: </span><span class="nx">next_character</span> <span class="o">is</span> <span class="s1">&#39;.&#39;</span> <span class="o">or</span> <span class="nx">@unfinished</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">size</span> <span class="o">is</span> <span class="nx">@indent</span>
<span class="k">return</span> <span class="nx">@suppress_newlines</span><span class="p">()</span> <span class="k">if</span> <span class="nx">no_newlines</span>
<span class="k">return</span> <span class="nx">@newline_token</span> <span class="nx">indent</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">size</span> <span class="o">&gt;</span> <span class="nx">@indent</span>
<span class="k">return</span> <span class="nx">@suppress_newlines</span><span class="p">()</span> <span class="k">if</span> <span class="nx">no_newlines</span>
<span class="nv">diff: </span><span class="nx">size</span> <span class="o">-</span> <span class="nx">@indent</span>
<span class="nx">@token</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="nx">diff</span>
<span class="nx">@indents</span><span class="p">.</span><span class="nx">push</span> <span class="nx">diff</span>
<span class="k">else</span>
<span class="nx">@outdent_token</span> <span class="nx">@indent</span> <span class="o">-</span> <span class="nx">size</span><span class="p">,</span> <span class="nx">no_newlines</span>
<span class="vi">@indent: </span><span class="nx">size</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>Record an outdent token or multiple tokens, if we happen to be moving back
inwards past several recorded indents.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">outdent_token: </span><span class="p">(</span><span class="nx">move_out</span><span class="p">,</span> <span class="nx">no_newlines</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">while</span> <span class="nx">move_out</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">@indents</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">last_indent: </span><span class="nx">@indents</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">@token</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">,</span> <span class="nx">last_indent</span>
<span class="nv">move_out: </span><span class="o">-</span> <span class="nx">last_indent</span>
<span class="nx">@token</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s2">&quot;\n&quot;</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;TERMINATOR&#39;</span> <span class="o">or</span> <span class="nx">no_newlines</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Matches and consumes non-meaningful whitespace. Tag the previous token
as being "spaced", because there are some cases where it makes a difference.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">whitespace_token: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">space: </span><span class="nx">@match</span> <span class="nx">WHITESPACE</span><span class="p">,</span> <span class="mi">1</span>
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">()</span>
<span class="nv">prev.spaced: </span><span class="kc">true</span> <span class="k">if</span> <span class="nx">prev</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">space</span><span class="p">.</span><span class="nx">length</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Generate a newline token. Consecutive newlines get merged together.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">newline_token: </span><span class="p">(</span><span class="nx">newlines</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@token</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s2">&quot;\n&quot;</span> <span class="nx">unless</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;TERMINATOR&#39;</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>Use a <code>\</code> at a line-ending to suppress the newline.
The slash is removed here once its job is done.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">suppress_newlines: </span><span class="o">-&gt;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s2">&quot;\\&quot;</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>We treat all other single characters as a token. Eg.: <code>( ) , . !</code>
Multi-character operators are also literal tokens, so that Jison can assign
the proper order of operations. There are some symbols that we tag specially
here. <code>;</code> and newlines are both treated as a <code>TERMINATOR</code>, we distinguish
parentheses that indicate a method call from regular parentheses, and so on.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">literal_token: </span><span class="o">-&gt;</span>
<span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">OPERATOR</span>
<span class="nv">value: </span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nv">space: </span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="nx">@tag_parameters</span><span class="p">()</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">and</span> <span class="nx">value</span><span class="p">.</span><span class="nx">match</span> <span class="nx">CODE</span>
<span class="nv">value: </span><span class="o">or</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
<span class="nv">prev_spaced: </span><span class="nx">@prev</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@prev</span><span class="p">().</span><span class="nx">spaced</span>
<span class="nv">tag: </span><span class="nx">value</span>
<span class="k">if</span> <span class="nx">value</span><span class="p">.</span><span class="nx">match</span> <span class="nx">ASSIGNMENT</span>
<span class="nv">tag: </span><span class="s1">&#39;ASSIGN&#39;</span>
<span class="nx">@assignment_error</span><span class="p">()</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">JS_FORBIDDEN</span><span class="p">,</span> <span class="nx">@value</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;;&#39;</span>
<span class="nv">tag: </span><span class="s1">&#39;TERMINATOR&#39;</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;[&#39;</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;?&#39;</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev_spaced</span>
<span class="nv">tag: </span><span class="s1">&#39;SOAKED_INDEX_START&#39;</span>
<span class="vi">@soaked_index: </span><span class="kc">true</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;]&#39;</span> <span class="o">and</span> <span class="nx">@soaked_index</span>
<span class="nv">tag: </span><span class="s1">&#39;SOAKED_INDEX_END&#39;</span>
<span class="vi">@soaked_index: </span><span class="kc">false</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">CALLABLE</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">())</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev_spaced</span>
<span class="nv">tag: </span><span class="s1">&#39;CALL_START&#39;</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;(&#39;</span>
<span class="nv">tag: </span><span class="s1">&#39;INDEX_START&#39;</span> <span class="k">if</span> <span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;[&#39;</span>
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">value</span><span class="p">.</span><span class="nx">length</span>
<span class="k">return</span> <span class="nx">@tag_half_assignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">space</span> <span class="o">and</span> <span class="nx">prev_spaced</span> <span class="o">and</span> <span class="nx">@prev</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;ASSIGN&#39;</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <h2>Token Manipulators</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>As we consume a new <code>IDENTIFIER</code>, look at the previous token to determine
if it's a special kind of accessor.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">name_access_type: </span><span class="o">-&gt;</span>
<span class="nx">@tag</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;PROTOTYPE_ACCESS&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;::&#39;</span>
<span class="k">if</span> <span class="nx">@value</span><span class="p">()</span> <span class="o">is</span> <span class="s1">&#39;.&#39;</span> <span class="o">and</span> <span class="o">not</span> <span class="p">(</span><span class="nx">@value</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;.&#39;</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">@tag</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;?&#39;</span>
<span class="nx">@tag</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;SOAK_ACCESS&#39;</span><span class="p">)</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">else</span>
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;PROPERTY_ACCESS&#39;</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Sanitize a heredoc by escaping internal double quotes and erasing all
external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">sanitize_heredoc: </span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">quote</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">indent: </span><span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">HEREDOC_INDENT</span><span class="p">)</span> <span class="o">or</span> <span class="p">[</span><span class="s1">&#39;&#39;</span><span class="p">]).</span><span class="nx">sort</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">&quot;^&quot;</span> <span class="o">+</span><span class="nx">indent</span><span class="p">,</span> <span class="s1">&#39;gm&#39;</span><span class="p">),</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">,</span> <span class="s2">&quot;\\n&quot;</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="nx">quote</span><span class="p">,</span> <span class="s1">&#39;g&#39;</span><span class="p">),</span> <span class="s1">&#39;\\&quot;&#39;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>Tag a half assignment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag_half_assignment: </span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">last: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s2">&quot;$tag=&quot;</span><span class="p">,</span> <span class="s2">&quot;$tag=&quot;</span><span class="p">,</span> <span class="nx">last</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>A source of ambiguity in our grammar used to be parameter lists in function
definitions versus argument lists in function calls. Walk backwards, tagging
parameters specially in order to make things easier for the parser.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag_parameters: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">()</span> <span class="o">isnt</span> <span class="s1">&#39;)&#39;</span>
<span class="nv">i: </span><span class="mi">0</span>
<span class="k">while</span> <span class="kc">true</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">i</span>
<span class="k">return</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">tok</span>
<span class="k">switch</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">when</span> <span class="s1">&#39;IDENTIFIER&#39;</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;PARAM&#39;</span>
<span class="k">when</span> <span class="s1">&#39;)&#39;</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;PARAM_END&#39;</span>
<span class="k">when</span> <span class="s1">&#39;(&#39;</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;PARAM_START&#39;</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Close up all remaining open blocks at the end of the file.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">close_indentation: </span><span class="o">-&gt;</span>
<span class="nx">@outdent_token</span> <span class="nx">@indent</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>The error for when you try to use a forbidden word in JavaScript as
an identifier.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifier_error: </span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;SyntaxError: Reserved word \&quot;$word\&quot; on line ${@line + 1}&quot;</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>The error for when you try to assign to a reserved word in JavaScript,
like "function" or "default".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assignment_error: </span><span class="o">-&gt;</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;SyntaxError: Reserved word \&quot;${@value()}\&quot; on line ${@line + 1} can&#39;t be assigned&quot;</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>Expand variables and expressions inside double-quoted strings using
<a href="http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation">ECMA Harmony's interpolation syntax</a>
for substitution of bare variables as well as arbitrary expressions.</p>
<pre><code>"Hello $name."
"Hello ${name.capitalize()}."
</code></pre>
<p>If it encounters an interpolation, this method will recursively create a
new Lexer, tokenize the interpolated contents, and merge them into the
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">interpolate_string: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">escape_quotes</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="mi">3</span> <span class="o">or</span> <span class="o">not</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span>
<span class="nx">@token</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="nx">str</span>
<span class="k">else</span>
<span class="nv">lexer: </span> <span class="k">new</span> <span class="nx">Lexer</span><span class="p">()</span>
<span class="nv">tokens: </span> <span class="p">[]</span>
<span class="nv">quote: </span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
<span class="p">[</span><span class="nx">i</span><span class="p">,</span> <span class="nx">pi</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>
<span class="k">while</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">if</span> <span class="nx">starts</span> <span class="nx">str</span><span class="p">,</span> <span class="s1">&#39;\\&#39;</span><span class="p">,</span> <span class="nx">i</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="k">else</span> <span class="k">if</span> <span class="nv">match: </span><span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">match</span> <span class="nx">INTERPOLATION</span>
<span class="p">[</span><span class="nx">group</span><span class="p">,</span> <span class="nx">interp</span><span class="p">]</span><span class="o">:</span> <span class="nx">match</span>
<span class="nv">interp: </span><span class="s2">&quot;this.${ interp.substring(1) }&quot;</span> <span class="k">if</span> <span class="nx">starts</span> <span class="nx">interp</span><span class="p">,</span> <span class="s1">&#39;@&#39;</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s2">&quot;$quote${ str.substring(pi, i) }$quote&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="nx">pi</span> <span class="o">&lt;</span> <span class="nx">i</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="nx">interp</span><span class="p">]</span>
<span class="nv">i: </span><span class="o">+</span> <span class="nx">group</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nv">pi: </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nv">expr: </span><span class="nx">balanced_string</span> <span class="nx">str</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">i</span><span class="p">),</span> <span class="p">[[</span><span class="s1">&#39;${&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">]])</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s2">&quot;$quote${ str.substring(pi, i) }$quote&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="nx">pi</span> <span class="o">&lt;</span> <span class="nx">i</span>
<span class="nv">inner: </span><span class="nx">expr</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">inner</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">nested: </span><span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="s2">&quot;($inner)&quot;</span><span class="p">,</span> <span class="p">{</span><span class="nv">rewrite: </span><span class="kc">no</span><span class="p">,</span> <span class="nv">line: </span><span class="nx">@line</span><span class="p">}</span>
<span class="nx">nested</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;TOKENS&#39;</span><span class="p">,</span> <span class="nx">nested</span><span class="p">]</span>
<span class="k">else</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s2">&quot;$quote$quote&quot;</span><span class="p">]</span>
<span class="nv">i: </span><span class="o">+</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nv">pi: </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s2">&quot;$quote${ str.substring(pi, i) }$quote&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="nx">pi</span> <span class="o">&lt;</span> <span class="nx">i</span> <span class="o">and</span> <span class="nx">pi</span> <span class="o">&lt;</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">unshift</span> <span class="p">[</span><span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;&quot;&#39;</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;STRING&#39;</span>
<span class="k">for</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">tokens</span>
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span><span class="o">:</span> <span class="nx">token</span>
<span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;TOKENS&#39;</span>
<span class="vi">@tokens: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">value</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;STRING&#39;</span> <span class="o">and</span> <span class="nx">escape_quotes</span>
<span class="nv">escaped: </span><span class="nx">value</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nx">value</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/&quot;/g</span><span class="p">,</span> <span class="s1">&#39;\\&quot;&#39;</span><span class="p">)</span>
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="s2">&quot;\&quot;$escaped\&quot;&quot;</span>
<span class="k">else</span>
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span>
<span class="nx">@token</span> <span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;+&#39;</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nx">tokens</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <h2>Helpers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <p>Add a token to the results, taking note of the line number.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">token: </span><span class="p">(</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">@line</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>Peek at a tag in the current token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag: </span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">index</span>
<span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">tag</span><span class="o">?</span>
<span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-36">#</a> </div> <p>Peek at a value in the current token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">value: </span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">index</span>
<span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span><span class="o">?</span>
<span class="nx">tok</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-37">#</a> </div> <p>Peek at a previous token, entire.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">prev: </span><span class="p">(</span><span class="nx">index</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@tokens</span><span class="p">[</span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="p">(</span><span class="nx">index</span> <span class="o">or</span> <span class="mi">1</span><span class="p">)]</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-38">#</a> </div> <p>Attempt to match a string against the current chunk, returning the indexed
match if successful, and <code>false</code> otherwise.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">match: </span><span class="p">(</span><span class="nx">regex</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">m: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">regex</span>
<span class="k">if</span> <span class="nx">m</span> <span class="k">then</span> <span class="nx">m</span><span class="p">[</span><span class="nx">index</span><span class="p">]</span> <span class="k">else</span> <span class="kc">false</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-39">#</a> </div> <p>Are we in the midst of an unfinished expression?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">unfinished: </span><span class="o">-&gt;</span>
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="nx">@value</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="nx">NO_NEWLINE</span><span class="p">)</span> <span class="o">and</span>
<span class="nx">prev</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;.&#39;</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@value</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="nx">CODE</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <h2>Lexer Properties</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>There are no exensions to the core lexer by default.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="vi">@extensions: </span><span class="p">[]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>Keywords that CoffeeScript shares in common with JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_KEYWORDS: </span><span class="p">[</span>
<span class="s2">&quot;if&quot;</span><span class="p">,</span> <span class="s2">&quot;else&quot;</span><span class="p">,</span>
<span class="s2">&quot;true&quot;</span><span class="p">,</span> <span class="s2">&quot;false&quot;</span><span class="p">,</span>
<span class="s2">&quot;new&quot;</span><span class="p">,</span> <span class="s2">&quot;return&quot;</span><span class="p">,</span>
<span class="s2">&quot;try&quot;</span><span class="p">,</span> <span class="s2">&quot;catch&quot;</span><span class="p">,</span> <span class="s2">&quot;finally&quot;</span><span class="p">,</span> <span class="s2">&quot;throw&quot;</span><span class="p">,</span>
<span class="s2">&quot;break&quot;</span><span class="p">,</span> <span class="s2">&quot;continue&quot;</span><span class="p">,</span>
<span class="s2">&quot;for&quot;</span><span class="p">,</span> <span class="s2">&quot;in&quot;</span><span class="p">,</span> <span class="s2">&quot;while&quot;</span><span class="p">,</span>
<span class="s2">&quot;delete&quot;</span><span class="p">,</span> <span class="s2">&quot;instanceof&quot;</span><span class="p">,</span> <span class="s2">&quot;typeof&quot;</span><span class="p">,</span>
<span class="s2">&quot;switch&quot;</span><span class="p">,</span> <span class="s2">&quot;super&quot;</span><span class="p">,</span> <span class="s2">&quot;extends&quot;</span><span class="p">,</span> <span class="s2">&quot;class&quot;</span><span class="p">,</span>
<span class="s2">&quot;this&quot;</span><span class="p">,</span> <span class="s2">&quot;null&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
be used standalone, but you can reference them as an attached property.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">COFFEE_ALIASES: </span> <span class="p">[</span><span class="s2">&quot;and&quot;</span><span class="p">,</span> <span class="s2">&quot;or&quot;</span><span class="p">,</span> <span class="s2">&quot;is&quot;</span><span class="p">,</span> <span class="s2">&quot;isnt&quot;</span><span class="p">,</span> <span class="s2">&quot;not&quot;</span><span class="p">]</span>
<span class="nv">COFFEE_KEYWORDS: </span><span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span>
<span class="s2">&quot;then&quot;</span><span class="p">,</span> <span class="s2">&quot;unless&quot;</span><span class="p">,</span>
<span class="s2">&quot;yes&quot;</span><span class="p">,</span> <span class="s2">&quot;no&quot;</span><span class="p">,</span> <span class="s2">&quot;on&quot;</span><span class="p">,</span> <span class="s2">&quot;off&quot;</span><span class="p">,</span>
<span class="s2">&quot;of&quot;</span><span class="p">,</span> <span class="s2">&quot;by&quot;</span><span class="p">,</span> <span class="s2">&quot;where&quot;</span><span class="p">,</span> <span class="s2">&quot;when&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>The combined list of keywords is the superset that gets passed verbatim to
the parser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">KEYWORDS: </span><span class="nx">JS_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">COFFEE_KEYWORDS</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</a> </div> <p>The list of keywords that are reserved by JavaScript, but not used, or are
used by CoffeeScript internally. We throw an error when these are encountered,
to avoid having a JavaScript error at runtime.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">RESERVED: </span><span class="p">[</span>
<span class="s2">&quot;case&quot;</span><span class="p">,</span> <span class="s2">&quot;default&quot;</span><span class="p">,</span> <span class="s2">&quot;do&quot;</span><span class="p">,</span> <span class="s2">&quot;function&quot;</span><span class="p">,</span> <span class="s2">&quot;var&quot;</span><span class="p">,</span> <span class="s2">&quot;void&quot;</span><span class="p">,</span> <span class="s2">&quot;with&quot;</span>
<span class="s2">&quot;const&quot;</span><span class="p">,</span> <span class="s2">&quot;let&quot;</span><span class="p">,</span> <span class="s2">&quot;debugger&quot;</span><span class="p">,</span> <span class="s2">&quot;enum&quot;</span><span class="p">,</span> <span class="s2">&quot;export&quot;</span><span class="p">,</span> <span class="s2">&quot;import&quot;</span><span class="p">,</span> <span class="s2">&quot;native&quot;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</a> </div> <p>The superset of both JavaScript keywords and reserved words, none of which may
be used as identifiers or properties.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_FORBIDDEN: </span><span class="nx">JS_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Token matching regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER : </span><span class="sr">/^([a-zA-Z\$_](\w|\$)*)/</span>
<span class="nv">NUMBER : </span><span class="sr">/^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i</span>
<span class="nv">HEREDOC : </span><span class="sr">/^(&quot;{6}|&#39;{6}|&quot;{3}\n?([\s\S]*?)\n?([ \t]*)&quot;{3}|&#39;{3}\n?([\s\S]*?)\n?([ \t]*)&#39;{3})/</span>
<span class="nv">INTERPOLATION : </span><span class="sr">/^\$([a-zA-Z_@]\w*(\.\w+)*)/</span>
<span class="nv">OPERATOR : </span><span class="sr">/^([+\*&amp;|\/\-%=&lt;&gt;:!?]+)([ \t]*)/</span>
<span class="nv">WHITESPACE : </span><span class="sr">/^([ \t]+)/</span>
<span class="nv">COMMENT : </span><span class="sr">/^(((\n?[ \t]*)?#[^\n]*)+)/</span>
<span class="nv">CODE : </span><span class="sr">/^((-|=)&gt;)/</span>
<span class="nv">MULTI_DENT : </span><span class="sr">/^((\n([ \t]*))+)(\.)?/</span>
<span class="nv">LAST_DENTS : </span><span class="sr">/\n([ \t]*)/g</span>
<span class="nv">LAST_DENT : </span><span class="sr">/\n([ \t]*)/</span>
<span class="nv">ASSIGNMENT : </span><span class="sr">/^(:|=)$/</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>Regex-matching-regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REGEX_START : </span><span class="sr">/^\/[^\/ ]/</span>
<span class="nv">REGEX_INTERPOLATION: </span><span class="sr">/([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/</span>
<span class="nv">REGEX_FLAGS : </span><span class="sr">/^[imgy]{0,4}/</span>
<span class="nv">REGEX_ESCAPE : </span><span class="sr">/\\[^\$]/g</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p>Token cleaning regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_CLEANER : </span><span class="sr">/(^`|`$)/g</span>
<span class="nv">MULTILINER : </span><span class="sr">/\n/g</span>
<span class="nv">STRING_NEWLINES : </span><span class="sr">/\n[ \t]*/g</span>
<span class="nv">COMMENT_CLEANER : </span><span class="sr">/(^[ \t]*#|\n[ \t]*$)/mg</span>
<span class="nv">NO_NEWLINE : </span><span class="sr">/^([+\*&amp;|\/\-%=&lt;&gt;:!.\\][&lt;&gt;=&amp;|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/</span>
<span class="nv">HEREDOC_INDENT : </span><span class="sr">/^[ \t]+/mg</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Tokens which a regular expression will never immediately follow, but which
a division operator might.</p>
<p>See: <a href='http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions'>http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</a></p>
<p>Our list is shorter, due to sans-parentheses method calls.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">NOT_REGEX: </span><span class="p">[</span>
<span class="s1">&#39;NUMBER&#39;</span><span class="p">,</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="s1">&#39;++&#39;</span><span class="p">,</span> <span class="s1">&#39;--&#39;</span><span class="p">,</span> <span class="s1">&#39;FALSE&#39;</span><span class="p">,</span> <span class="s1">&#39;NULL&#39;</span><span class="p">,</span> <span class="s1">&#39;TRUE&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <p>Tokens which could legitimately be invoked or indexed. A opening
parentheses or bracket following these tokens will be recorded as the start
of a function invocation or indexing operation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CALLABLE: </span><span class="p">[</span><span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;SUPER&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">,</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s1">&#39;@&#39;</span><span class="p">,</span> <span class="s1">&#39;THIS&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</a> </div> <p>Tokens that indicate an access -- keywords immediately following will be
treated as identifiers.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSORS: </span><span class="p">[</span><span class="s1">&#39;PROPERTY_ACCESS&#39;</span><span class="p">,</span> <span class="s1">&#39;PROTOTYPE_ACCESS&#39;</span><span class="p">,</span> <span class="s1">&#39;SOAK_ACCESS&#39;</span><span class="p">,</span> <span class="s1">&#39;@&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-54">#</a> </div> <p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
occurs at the start of a line. We disambiguate these from trailing whens to
avoid an ambiguity in the grammar.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LINE_BREAK: </span><span class="p">[</span><span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-55">#</a> </div> <p>Half-assignments...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">HALF_ASSIGNMENTS: </span><span class="p">[</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="s1">&#39;*&#39;</span><span class="p">,</span> <span class="s1">&#39;%&#39;</span><span class="p">,</span> <span class="s1">&#39;||&#39;</span><span class="p">,</span> <span class="s1">&#39;&amp;&amp;&#39;</span><span class="p">,</span> <span class="s1">&#39;?&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-56">#</a> </div> <p>Conversions from CoffeeScript operators into JavaScript ones.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CONVERSIONS: </span><span class="p">{</span>
<span class="s1">&#39;and&#39;</span><span class="o">:</span> <span class="s1">&#39;&amp;&amp;&#39;</span>
<span class="s1">&#39;or&#39;</span><span class="o">:</span> <span class="s1">&#39;||&#39;</span>
<span class="s1">&#39;is&#39;</span><span class="o">:</span> <span class="s1">&#39;==&#39;</span>
<span class="s1">&#39;isnt&#39;</span><span class="o">:</span> <span class="s1">&#39;!=&#39;</span>
<span class="s1">&#39;not&#39;</span><span class="o">:</span> <span class="s1">&#39;!&#39;</span>
<span class="p">}</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,926 @@
<!DOCTYPE html> <html> <head> <title>nodes.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> nodes.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p><code>nodes.coffee</code> contains all of the node classes for the syntax tree. Most
nodes are created as the result of actions in the <a href="grammar.html">grammar</a>,
but some are created by other nodes as a method of code generation. To convert
the syntax tree into a string of JavaScript code, call <code>compile()</code> on the root.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up for both <strong>Node.js</strong> and the browser, by
including the <a href="scope.html">Scope</a> class and the <a href="helpers.html">helper</a> functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
<span class="nv">Scope: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./scope&#39;</span><span class="p">).</span><span class="nx">Scope</span>
<span class="nv">helpers: </span><span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./helpers&#39;</span><span class="p">).</span><span class="nx">helpers</span>
<span class="k">else</span>
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span>
<span class="nv">Scope: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Scope</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we plan to use.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compact: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span>
<span class="nv">flatten: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">flatten</span>
<span class="nv">merge: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">merge</span>
<span class="nv">del: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">del</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Helper function that marks a node as a JavaScript <em>statement</em>, or as a
<em>pure_statement</em>. Statements must be wrapped in a closure when used as an
expression, and nodes tagged as <em>pure_statement</em> cannot be closure-wrapped
without losing their meaning.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">statement: </span><span class="p">(</span><span class="nx">klass</span><span class="p">,</span> <span class="nx">only</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">klass::is_statement: </span><span class="o">-&gt;</span> <span class="kc">true</span>
<span class="p">(</span><span class="nv">klass::is_pure_statement: </span><span class="o">-&gt;</span> <span class="kc">true</span><span class="p">)</span> <span class="k">if</span> <span class="nx">only</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <h3>BaseNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>The <strong>BaseNode</strong> is the abstract base class for all nodes in the syntax tree.
Each subclass implements the <code>compile_node</code> method, which performs the
code generation for that node. To compile a node to JavaScript,
call <code>compile</code> on it, which wraps <code>compile_node</code> in some generic extra smarts,
to know when the generated code needs to be wrapped up in a closure.
An options hash is passed and cloned throughout, containing information about
the environment from higher in the tree (such as if a returned value is
being requested by the surrounding function), information about the current
scope, and indentation level.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.BaseNode: </span><span class="nx">class</span> <span class="nx">BaseNode</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Common logic for determining whether to wrap this node in a closure before
compiling it, or to compile directly. We need to wrap if this node is a
<em>statement</em>, and it's not a <em>pure_statement</em>, and we're not at
the top level of a block (which would be unnecessary), and we haven't
already been asked to return the result (because statements know how to
return results).</p>
<p>If a Node is <em>top_sensitive</em>, that means that it needs to compile differently
depending on whether it's being used as part of a larger expression, or is a
top-level statement within the function body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@options: </span><span class="nx">merge</span> <span class="nx">o</span> <span class="o">or</span> <span class="p">{}</span>
<span class="vi">@tab: </span> <span class="nx">o</span><span class="p">.</span><span class="nx">indent</span>
<span class="nx">del</span> <span class="nx">@options</span><span class="p">,</span> <span class="s1">&#39;operation&#39;</span> <span class="nx">unless</span> <span class="k">this</span> <span class="k">instanceof</span> <span class="nx">ValueNode</span>
<span class="nv">top: </span> <span class="k">if</span> <span class="nx">@top_sensitive</span><span class="p">()</span> <span class="k">then</span> <span class="nx">@options</span><span class="p">.</span><span class="nx">top</span> <span class="k">else</span> <span class="nx">del</span> <span class="nx">@options</span><span class="p">,</span> <span class="s1">&#39;top&#39;</span>
<span class="nv">closure: </span> <span class="nx">@is_statement</span><span class="p">()</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@is_pure_statement</span><span class="p">()</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">top</span> <span class="o">and</span>
<span class="o">not</span> <span class="nx">@options</span><span class="p">.</span><span class="nx">as_statement</span> <span class="o">and</span> <span class="o">not</span> <span class="p">(</span><span class="k">this</span> <span class="k">instanceof</span> <span class="nx">CommentNode</span><span class="p">)</span> <span class="o">and</span>
<span class="o">not</span> <span class="nx">@contains_pure_statement</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">closure</span> <span class="k">then</span> <span class="nx">@compile_closure</span><span class="p">(</span><span class="nx">@options</span><span class="p">)</span> <span class="k">else</span> <span class="nx">@compile_node</span><span class="p">(</span><span class="nx">@options</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Statements converted into expressions via closure-wrapping share a scope
object with their parent closure, to preserve the expected lexical scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_closure: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@tab: </span><span class="nx">o</span><span class="p">.</span><span class="nx">indent</span>
<span class="nv">o.shared_scope: </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span>
<span class="nx">ClosureNode</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>If the code generation wishes to use the result of a complex expression
in multiple places, ensure that the expression is only ever evaluated once,
by assigning it to a temporary variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_reference: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">reference: </span><span class="nx">literal</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">compiled: </span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="nx">reference</span><span class="p">,</span> <span class="k">this</span>
<span class="p">[</span><span class="nx">compiled</span><span class="p">,</span> <span class="nx">reference</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Convenience method to grab the current indentation level, plus tabbing in.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">idt: </span><span class="p">(</span><span class="nx">tabs</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">idt: </span><span class="nx">@tab</span> <span class="o">or</span> <span class="s1">&#39;&#39;</span>
<span class="nv">num: </span><span class="p">(</span><span class="nx">tabs</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nv">idt: </span><span class="o">+</span> <span class="nx">TAB</span> <span class="k">while</span> <span class="nv">num: </span><span class="o">-</span> <span class="mi">1</span>
<span class="nx">idt</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Construct a node that returns the current node's result.
Note that this is overridden for smarter behavior for
many statement nodes (eg IfNode, ForNode)...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="k">new</span> <span class="nx">ReturnNode</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Does this node, or any of its children, contain a node of a certain kind?
Recursively traverses down the <em>children</em> of the nodes, yielding to a block
and returning true when the block finds a match. <code>contains</code> does not cross
scope boundaries.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">contains: </span><span class="p">(</span><span class="nx">block</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">@children</span>
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">block</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">contains</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">block</span>
<span class="kc">false</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Is this node of a certain type, or does it contain the type?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">contains_type: </span><span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">this</span> <span class="k">instanceof</span> <span class="nx">type</span> <span class="o">or</span> <span class="nx">@contains</span> <span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">n</span> <span class="k">instanceof</span> <span class="nx">type</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Convenience for the most common use of contains. Does the node contain
a pure statement?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">contains_pure_statement: </span><span class="o">-&gt;</span>
<span class="nx">@is_pure_statement</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@contains</span> <span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">n</span><span class="p">.</span><span class="nx">is_pure_statement</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Perform an in-order traversal of the AST. Crosses scope boundaries.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">traverse: </span><span class="p">(</span><span class="nx">block</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">@children</span>
<span class="nx">block</span> <span class="nx">node</span>
<span class="nx">node</span><span class="p">.</span><span class="nx">traverse</span> <span class="nx">block</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">traverse</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p><code>toString</code> representation of the node, for inspecting the parse tree.
This is what <code>coffee --nodes</code> prints out.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">toString: </span><span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">idt: </span><span class="o">or</span> <span class="s1">&#39;&#39;</span>
<span class="s1">&#39;\n&#39;</span> <span class="o">+</span> <span class="nx">idt</span> <span class="o">+</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="p">(</span><span class="nx">child</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="nx">idt</span> <span class="o">+</span> <span class="nx">TAB</span><span class="p">)</span> <span class="k">for</span> <span class="nx">child</span> <span class="k">in</span> <span class="nx">@children</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Default implementations of the common node identification methods. Nodes
will override these with custom logic, if needed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">unwrap: </span> <span class="o">-&gt;</span> <span class="k">this</span>
<span class="nv">children: </span> <span class="p">[]</span>
<span class="nv">is_statement: </span> <span class="o">-&gt;</span> <span class="kc">false</span>
<span class="nv">is_pure_statement: </span> <span class="o">-&gt;</span> <span class="kc">false</span>
<span class="nv">top_sensitive: </span> <span class="o">-&gt;</span> <span class="kc">false</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <h3>Expressions</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>The expressions body is the list of expressions that forms the body of an
indented block of code -- the implementation of a function, a clause in an
<code>if</code>, <code>switch</code>, or <code>try</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Expressions: </span><span class="nx">class</span> <span class="nx">Expressions</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">nodes</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: @expressions: </span><span class="nx">compact</span> <span class="nx">flatten</span> <span class="nx">nodes</span> <span class="o">or</span> <span class="p">[]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Tack an expression on to the end of this expression list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">push: </span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Add an expression at the beginning of this expression list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">unshift: </span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">unshift</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>If this Expressions consists of just a single node, unwrap it by pulling
it back out.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">unwrap: </span><span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">1</span> <span class="k">then</span> <span class="nx">@expressions</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">else</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>Is this an empty block of code?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">empty: </span><span class="o">-&gt;</span>
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>Make a copy of this node.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">copy: </span><span class="o">-&gt;</span>
<span class="k">new</span> <span class="nx">Expressions</span> <span class="nx">@children</span><span class="p">.</span><span class="nx">slice</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>An Expressions node does not return its entire body, rather it
ensures that the final expression is returned.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="nv">idx: </span> <span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nv">last: </span><span class="nx">@expressions</span><span class="p">[</span><span class="nx">idx</span><span class="p">]</span>
<span class="nv">last: </span><span class="nx">@expressions</span><span class="p">[</span><span class="nv">idx: </span><span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="nx">last</span> <span class="k">instanceof</span> <span class="nx">CommentNode</span>
<span class="k">return</span> <span class="k">this</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">last</span> <span class="o">or</span> <span class="nx">last</span> <span class="k">instanceof</span> <span class="nx">ReturnNode</span>
<span class="nx">@expressions</span><span class="p">[</span><span class="nx">idx</span><span class="p">]</span><span class="o">:</span> <span class="nx">last</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">last</span><span class="p">.</span><span class="nx">contains_pure_statement</span><span class="p">()</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>An <strong>Expressions</strong> is the only node that can serve as the root.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o: </span><span class="o">or</span> <span class="p">{}</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span> <span class="k">then</span> <span class="k">super</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="nx">@compile_root</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">@compile_expression</span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">))</span> <span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">@expressions</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s2">&quot;\n&quot;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>If we happen to be the top-level <strong>Expressions</strong>, wrap everything in
a safety closure, unless requested not to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_root: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o.indent: </span><span class="vi">@tab: </span><span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">no_wrap</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="nx">TAB</span>
<span class="nv">o.scope: </span><span class="k">new</span> <span class="nx">Scope</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="kc">null</span><span class="p">)</span>
<span class="nv">code: </span><span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">globals</span> <span class="k">then</span> <span class="nx">@compile_node</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="nx">@compile_with_declarations</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">code: </span><span class="nx">code</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">TRAILING_WHITESPACE</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">no_wrap</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">&quot;(function(){\n$code\n})();\n&quot;</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>Compile the expressions body for the contents of a function, with
declarations of all inner variables pushed up to the top.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_with_declarations: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">code: </span><span class="nx">@compile_node</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">code: </span><span class="s2">&quot;${@tab}var ${o.scope.compiled_assignments()};\n$code&quot;</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">has_assignments</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="nv">code: </span><span class="s2">&quot;${@tab}var ${o.scope.compiled_declarations()};\n$code&quot;</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">has_declarations</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Compiles a single expression within the expressions body. If we need to
return the result, and it's an expression, simply return it. If it's a
statement, ask the statement to do so.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_expression: </span><span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@tab: </span><span class="nx">o</span><span class="p">.</span><span class="nx">indent</span>
<span class="nv">compiled_node: </span><span class="nx">node</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">merge</span> <span class="nx">o</span><span class="p">,</span> <span class="p">{</span><span class="nv">top: </span><span class="kc">true</span><span class="p">}</span>
<span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()</span> <span class="k">then</span> <span class="nx">compiled_node</span> <span class="k">else</span> <span class="s2">&quot;${@idt()}$compiled_node;&quot;</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>Wrap up the given nodes as an <strong>Expressions</strong>, unless it already happens
to be one.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">Expressions.wrap: </span><span class="p">(</span><span class="nx">nodes</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="nx">nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">nodes</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">instanceof</span> <span class="nx">Expressions</span>
<span class="k">new</span> <span class="nx">Expressions</span><span class="p">(</span><span class="nx">nodes</span><span class="p">)</span>
<span class="nx">statement</span> <span class="nx">Expressions</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <h3>LiteralNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>Literals are static values that can be passed through directly into
JavaScript without translation, such as: strings, numbers,
<code>true</code>, <code>false</code>, <code>null</code>...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.LiteralNode: </span><span class="nx">class</span> <span class="nx">LiteralNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@value: </span><span class="nx">value</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <p>Break and continue must be treated as pure statements -- they lose their
meaning when wrapped in a closure.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">is_statement: </span><span class="o">-&gt;</span>
<span class="nx">@value</span> <span class="o">is</span> <span class="s1">&#39;break&#39;</span> <span class="o">or</span> <span class="nx">@value</span> <span class="o">is</span> <span class="s1">&#39;continue&#39;</span>
<span class="nv">is_pure_statement: </span><span class="nx">LiteralNode</span><span class="o">::</span><span class="nx">is_statement</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">idt: </span><span class="k">if</span> <span class="nx">@is_statement</span><span class="p">()</span> <span class="k">then</span> <span class="nx">@idt</span><span class="p">()</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">end: </span><span class="k">if</span> <span class="nx">@is_statement</span><span class="p">()</span> <span class="k">then</span> <span class="s1">&#39;;&#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="s2">&quot;$idt$@value$end&quot;</span>
<span class="nv">toString: </span><span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="s2">&quot; \&quot;$@value\&quot;&quot;</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <h3>ReturnNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>A <code>return</code> is a <em>pure_statement</em> -- wrapping it in a closure wouldn't
make sense.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ReturnNode: </span><span class="nx">class</span> <span class="nx">ReturnNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">expression</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@expression: </span><span class="nx">expression</span><span class="p">]</span>
<span class="nv">top_sensitive: </span><span class="o">-&gt;</span>
<span class="kc">true</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">expr: </span><span class="nx">@expression</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">ReturnNode</span>
<span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;top&#39;</span>
<span class="nv">o.as_statement: </span><span class="kc">true</span> <span class="k">if</span> <span class="nx">@expression</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()</span>
<span class="s2">&quot;${@tab}return ${@expression.compile(o)};&quot;</span>
<span class="nx">statement</span> <span class="nx">ReturnNode</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-36">#</a> </div> <h3>ValueNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-37">#</a> </div> <p>A value, variable or literal or parenthesized, indexed or dotted into,
or vanilla.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ValueNode: </span><span class="nx">class</span> <span class="nx">ValueNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">SOAK: </span><span class="s2">&quot; == undefined ? undefined : &quot;</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-38">#</a> </div> <p>A <strong>ValueNode</strong> has a base and a list of property accesses.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">constructor: </span><span class="p">(</span><span class="nx">base</span><span class="p">,</span> <span class="nx">properties</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span> <span class="nx">flatten</span> <span class="p">[</span><span class="vi">@base: </span><span class="nx">base</span><span class="p">,</span> <span class="vi">@properties: </span><span class="p">(</span><span class="nx">properties</span> <span class="o">or</span> <span class="p">[])]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-39">#</a> </div> <p>Add a property access to the list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">push: </span><span class="p">(</span><span class="nx">prop</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@properties</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">prop</span><span class="p">)</span>
<span class="nx">@children</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">prop</span><span class="p">)</span>
<span class="k">this</span>
<span class="nv">has_properties: </span><span class="o">-&gt;</span>
<span class="o">!!</span><span class="nx">@properties</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-40">#</a> </div> <p>Some boolean checks for the benefit of other nodes.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">is_array: </span><span class="o">-&gt;</span>
<span class="nx">@base</span> <span class="k">instanceof</span> <span class="nx">ArrayNode</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@has_properties</span><span class="p">()</span>
<span class="nv">is_object: </span><span class="o">-&gt;</span>
<span class="nx">@base</span> <span class="k">instanceof</span> <span class="nx">ObjectNode</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@has_properties</span><span class="p">()</span>
<span class="nv">is_splice: </span><span class="o">-&gt;</span>
<span class="nx">@has_properties</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@properties</span><span class="p">[</span><span class="nx">@properties</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="k">instanceof</span> <span class="nx">SliceNode</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@has_properties</span><span class="p">()</span> <span class="k">then</span> <span class="k">super</span><span class="p">()</span> <span class="k">else</span> <span class="nx">@base</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-41">#</a> </div> <p>The value can be unwrapped as its inner node, if there are no attached
properties.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">unwrap: </span><span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">length</span> <span class="k">then</span> <span class="k">this</span> <span class="k">else</span> <span class="nx">@base</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <p>Values are considered to be statements if their base is a statement.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">is_statement: </span><span class="o">-&gt;</span>
<span class="nx">@base</span><span class="p">.</span><span class="nx">is_statement</span> <span class="o">and</span> <span class="nx">@base</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@has_properties</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>We compile a value to JavaScript by compiling and joining each property.
Things get much more insteresting if the chain of properties has <em>soak</em>
operators <code>?.</code> interspersed. Then we have to take care not to accidentally
evaluate a anything twice when building the soak chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">soaked: </span> <span class="kc">false</span>
<span class="nv">only: </span> <span class="nx">del</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;only_first&#39;</span><span class="p">)</span>
<span class="nv">op: </span> <span class="nx">del</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;operation&#39;</span><span class="p">)</span>
<span class="nv">props: </span> <span class="k">if</span> <span class="nx">only</span> <span class="k">then</span> <span class="nx">@properties</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">@properties</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="nx">@properties</span>
<span class="nv">baseline: </span><span class="nx">@base</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">baseline: </span><span class="s2">&quot;($baseline)&quot;</span> <span class="k">if</span> <span class="nx">@base</span> <span class="k">instanceof</span> <span class="nx">ObjectNode</span> <span class="o">and</span> <span class="nx">@has_properties</span><span class="p">()</span>
<span class="nv">complete: </span><span class="vi">@last: </span><span class="nx">baseline</span>
<span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">props</span>
<span class="vi">@source: </span><span class="nx">baseline</span>
<span class="k">if</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">soak_node</span>
<span class="nv">soaked: </span><span class="kc">true</span>
<span class="k">if</span> <span class="nx">@base</span> <span class="k">instanceof</span> <span class="nx">CallNode</span> <span class="o">and</span> <span class="nx">prop</span> <span class="o">is</span> <span class="nx">props</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">temp: </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">complete: </span><span class="s2">&quot;($temp = $complete)$@SOAK&quot;</span> <span class="o">+</span> <span class="p">(</span><span class="nv">baseline: </span><span class="nx">temp</span> <span class="o">+</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">))</span>
<span class="k">else</span>
<span class="nv">complete: </span><span class="nx">complete</span> <span class="o">+</span> <span class="nx">@SOAK</span> <span class="o">+</span> <span class="p">(</span><span class="nv">baseline: </span><span class="o">+</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">))</span>
<span class="k">else</span>
<span class="nv">part: </span><span class="nx">prop</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">baseline: </span><span class="o">+</span> <span class="nx">part</span>
<span class="nv">complete: </span><span class="o">+</span> <span class="nx">part</span>
<span class="vi">@last: </span><span class="nx">part</span>
<span class="k">if</span> <span class="nx">op</span> <span class="o">and</span> <span class="nx">soaked</span> <span class="k">then</span> <span class="s2">&quot;($complete)&quot;</span> <span class="k">else</span> <span class="nx">complete</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <h3>CommentNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>CoffeeScript passes through comments as JavaScript comments at the
same position.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.CommentNode: </span><span class="nx">class</span> <span class="nx">CommentNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">lines</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@lines: </span><span class="nx">lines</span>
<span class="k">this</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="k">this</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="s2">&quot;$@tab//&quot;</span> <span class="o">+</span> <span class="nx">@lines</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&quot;\n$@tab//&quot;</span><span class="p">)</span>
<span class="nx">statement</span> <span class="nx">CommentNode</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-46">#</a> </div> <h3>CallNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</a> </div> <p>Node for a function invocation. Takes care of converting <code>super()</code> calls into
calls against the prototype's function of the same name.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.CallNode: </span><span class="nx">class</span> <span class="nx">CallNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">variable</span><span class="p">,</span> <span class="nx">args</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@is_new: </span> <span class="kc">false</span>
<span class="vi">@is_super: </span><span class="nx">variable</span> <span class="o">is</span> <span class="s1">&#39;super&#39;</span>
<span class="vi">@variable: </span><span class="k">if</span> <span class="nx">@is_super</span> <span class="k">then</span> <span class="kc">null</span> <span class="k">else</span> <span class="nx">variable</span>
<span class="vi">@children: </span><span class="nx">compact</span> <span class="nx">flatten</span> <span class="p">[</span><span class="nx">@variable</span><span class="p">,</span> <span class="vi">@args: </span><span class="p">(</span><span class="nx">args</span> <span class="o">or</span> <span class="p">[])]</span>
<span class="vi">@compile_splat_arguments: </span><span class="nx">SplatNode</span><span class="p">.</span><span class="nx">compile_mixed_array</span> <span class="o">&lt;-</span> <span class="err">@</span><span class="p">,</span> <span class="nx">@args</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Tag this invocation as creating a new instance.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">new_instance: </span><span class="o">-&gt;</span>
<span class="vi">@is_new: </span><span class="kc">true</span>
<span class="k">this</span>
<span class="nv">prefix: </span><span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@is_new</span> <span class="k">then</span> <span class="s1">&#39;new &#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>Compile a vanilla function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">@args</span>
<span class="k">return</span> <span class="nx">@compile_splat</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">arg</span> <span class="k">instanceof</span> <span class="nx">SplatNode</span>
<span class="nv">args: </span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">@args</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;, &#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="nx">@compile_super</span><span class="p">(</span><span class="nx">args</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@is_super</span>
<span class="s2">&quot;${@prefix()}${@variable.compile(o)}($args)&quot;</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p><code>super()</code> is converted into a call against the superclass's implementation
of the current function.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_super: </span><span class="p">(</span><span class="nx">args</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">methname: </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">method</span><span class="p">.</span><span class="nx">name</span>
<span class="nv">meth: </span><span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">method</span><span class="p">.</span><span class="nx">proto</span>
<span class="s2">&quot;${o.scope.method.proto}.__superClass__.$methname&quot;</span>
<span class="k">else</span>
<span class="s2">&quot;${methname}.__superClass__.constructor&quot;</span>
<span class="s2">&quot;${meth}.call(this${ if args.length then &#39;, &#39; else &#39;&#39; }$args)&quot;</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>If you call a function with a splat, it's converted into a JavaScript
<code>.apply()</code> call to allow an array of arguments to be passed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_splat: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">meth: </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">obj: </span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">source</span> <span class="o">or</span> <span class="s1">&#39;this&#39;</span>
<span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/\(/</span><span class="p">)</span>
<span class="nv">temp: </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">obj: </span> <span class="nx">temp</span>
<span class="nv">meth: </span><span class="s2">&quot;($temp = ${ @variable.source })${ @variable.last }&quot;</span>
<span class="s2">&quot;${@prefix()}${meth}.apply($obj, ${ @compile_splat_arguments(o) })&quot;</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <h3>CurryNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</a> </div> <p>Binds a context object and a list of arguments to a function,
returning the bound function. After ECMAScript 5, Prototype.js, and
Underscore's <code>bind</code> functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.CurryNode: </span><span class="nx">class</span> <span class="nx">CurryNode</span> <span class="k">extends</span> <span class="nx">CallNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">meth</span><span class="p">,</span> <span class="nx">args</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span> <span class="nx">flatten</span> <span class="p">[</span><span class="vi">@meth: </span><span class="nx">meth</span><span class="p">,</span> <span class="vi">@context: </span><span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="vi">@args: </span><span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">or</span> <span class="p">[])]</span>
<span class="vi">@compile_splat_arguments: </span><span class="nx">SplatNode</span><span class="p">.</span><span class="nx">compile_mixed_array</span> <span class="o">&lt;-</span> <span class="err">@</span><span class="p">,</span> <span class="nx">@args</span>
<span class="nv">arguments: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">@args</span>
<span class="k">return</span> <span class="nx">@compile_splat_arguments</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">arg</span> <span class="k">instanceof</span> <span class="nx">SplatNode</span>
<span class="p">(</span><span class="k">new</span> <span class="nx">ArrayNode</span><span class="p">(</span><span class="nx">@args</span><span class="p">)).</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">utility</span> <span class="s1">&#39;slice&#39;</span>
<span class="nv">ref: </span><span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">literal</span> <span class="nx">utility</span> <span class="s1">&#39;bind&#39;</span>
<span class="p">(</span><span class="k">new</span> <span class="nx">CallNode</span><span class="p">(</span><span class="nx">ref</span><span class="p">,</span> <span class="p">[</span><span class="nx">@meth</span><span class="p">,</span> <span class="nx">@context</span><span class="p">,</span> <span class="nx">literal</span><span class="p">(</span><span class="nx">@arguments</span><span class="p">(</span><span class="nx">o</span><span class="p">))])).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-54">#</a> </div> <h3>ExtendsNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-55">#</a> </div> <p>Node to extend an object's prototype with an ancestor object.
After <code>goog.inherits</code> from the
<a href="http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.html">Closure Library</a>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ExtendsNode: </span><span class="nx">class</span> <span class="nx">ExtendsNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">child</span><span class="p">,</span> <span class="nx">parent</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span> <span class="p">[</span><span class="vi">@child: </span><span class="nx">child</span><span class="p">,</span> <span class="vi">@parent: </span><span class="nx">parent</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-56">#</a> </div> <p>Hooks one constructor into another's prototype chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">ref: </span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">literal</span> <span class="nx">utility</span> <span class="s1">&#39;extends&#39;</span>
<span class="p">(</span><span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">ref</span><span class="p">,</span> <span class="p">[</span><span class="nx">@child</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">]).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-57">#</a> </div> <h3>AccessorNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-58">#</a> </div> <p>A <code>.</code> accessor into a property of a value, or the <code>::</code> shorthand for
an accessor into the object's prototype.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.AccessorNode: </span><span class="nx">class</span> <span class="nx">AccessorNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span> <span class="p">[</span><span class="vi">@name: </span><span class="nx">name</span><span class="p">]</span>
<span class="nx">@prototype</span><span class="o">:</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;prototype&#39;</span>
<span class="vi">@soak_node: </span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;soak&#39;</span>
<span class="k">this</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">proto_part: </span><span class="k">if</span> <span class="nx">@prototype</span> <span class="k">then</span> <span class="s1">&#39;prototype.&#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="s2">&quot;.$proto_part${@name.compile(o)}&quot;</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-59">#</a> </div> <h3>IndexNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-60">#</a> </div> <p>A <code>[ ... ]</code> indexed accessor into an array or object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.IndexNode: </span><span class="nx">class</span> <span class="nx">IndexNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span> <span class="p">[</span><span class="vi">@index: </span><span class="nx">index</span><span class="p">]</span>
<span class="vi">@soak_node: </span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;soak&#39;</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">idx: </span><span class="nx">@index</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="s2">&quot;[$idx]&quot;</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-61">#</a> </div> <h3>RangeNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-62">#</a> </div> <p>A range literal. Ranges can be used to extract portions (slices) of arrays,
to specify a range for comprehensions, or as a value, to be expanded into the
corresponding array of integers at runtime.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.RangeNode: </span><span class="nx">class</span> <span class="nx">RangeNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">from</span><span class="p">,</span> <span class="nx">to</span><span class="p">,</span> <span class="nx">exclusive</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span> <span class="p">[</span><span class="vi">@from: </span><span class="nx">from</span><span class="p">,</span> <span class="vi">@to: </span><span class="nx">to</span><span class="p">]</span>
<span class="vi">@exclusive: </span><span class="o">!!</span><span class="nx">exclusive</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-63">#</a> </div> <p>Compiles the range's source variables -- where it starts and where it ends.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_variables: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@tab: </span><span class="nx">o</span><span class="p">.</span><span class="nx">indent</span>
<span class="p">[</span><span class="nx">@from_var</span><span class="p">,</span> <span class="nx">@to_var</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">(),</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()]</span>
<span class="p">[</span><span class="nx">from</span><span class="p">,</span> <span class="nx">to</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@from</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">@to</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)]</span>
<span class="s2">&quot;$@from_var = $from; $@to_var = $to;\n$@tab&quot;</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-64">#</a> </div> <p>When compiled normally, the range returns the contents of the <em>for loop</em>
needed to iterate over the values in the range. Used by comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="nx">@compile_array</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">o</span><span class="p">.</span><span class="nx">index</span>
<span class="nv">idx: </span> <span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;index&#39;</span>
<span class="nv">step: </span> <span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;step&#39;</span>
<span class="nv">vars: </span> <span class="s2">&quot;$idx = $@from_var&quot;</span>
<span class="nv">step: </span> <span class="k">if</span> <span class="nx">step</span> <span class="k">then</span> <span class="nx">step</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;1&#39;</span>
<span class="nv">equals: </span> <span class="k">if</span> <span class="nx">@exclusive</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="s1">&#39;=&#39;</span>
<span class="nv">intro: </span> <span class="s2">&quot;($@from_var &lt;= $@to_var ? $idx&quot;</span>
<span class="nv">compare: </span> <span class="s2">&quot;$intro &lt;$equals $@to_var : $idx &gt;$equals $@to_var)&quot;</span>
<span class="nv">incr: </span> <span class="s2">&quot;$intro += $step : $idx -= $step)&quot;</span>
<span class="s2">&quot;$vars; $compare; $incr&quot;</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-65">#</a> </div> <p>When used as a value, expand the range into the equivalent array. In the
future, the code this generates should probably be cleaned up by handwriting
it instead of wrapping nodes.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_array: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">name: </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">body: </span><span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">literal</span><span class="p">(</span><span class="nx">name</span><span class="p">)])</span>
<span class="nv">arr: </span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="k">new</span> <span class="nx">ForNode</span><span class="p">(</span><span class="nx">body</span><span class="p">,</span> <span class="p">{</span><span class="nv">source: </span><span class="p">(</span><span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="k">this</span><span class="p">))},</span> <span class="nx">literal</span><span class="p">(</span><span class="nx">name</span><span class="p">))])</span>
<span class="p">(</span><span class="k">new</span> <span class="nx">ParentheticalNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">CallNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">CodeNode</span><span class="p">([],</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">make_return</span><span class="p">())))).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-66">#</a> </div> <h3>SliceNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-67">#</a> </div> <p>An array slice literal. Unlike JavaScript's <code>Array#slice</code>, the second parameter
specifies the index of the end of the slice, just as the first parameter
is the index of the beginning.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.SliceNode: </span><span class="nx">class</span> <span class="nx">SliceNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">range</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@range: </span><span class="nx">range</span><span class="p">]</span>
<span class="k">this</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">from: </span> <span class="nx">@range</span><span class="p">.</span><span class="nx">from</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">to: </span> <span class="nx">@range</span><span class="p">.</span><span class="nx">to</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">plus_part: </span> <span class="k">if</span> <span class="nx">@range</span><span class="p">.</span><span class="nx">exclusive</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="s1">&#39; + 1&#39;</span>
<span class="s2">&quot;.slice($from, $to$plus_part)&quot;</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-68">#</a> </div> <h3>ObjectNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-69">#</a> </div> <p>An object literal, nothing fancy.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ObjectNode: </span><span class="nx">class</span> <span class="nx">ObjectNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: @objects: @properties: </span><span class="nx">props</span> <span class="o">or</span> <span class="p">[]</span></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-70">#</a> </div> <p>All the mucking about with commas is to make sure that CommentNodes and
AssignNodes get interleaved correctly, with no trailing commas or
commas affixed to comments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o.indent: </span><span class="nx">@idt</span> <span class="mi">1</span>
<span class="nv">non_comments: </span><span class="nx">prop</span> <span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">@properties</span> <span class="k">when</span> <span class="o">not</span> <span class="p">(</span><span class="nx">prop</span> <span class="k">instanceof</span> <span class="nx">CommentNode</span><span class="p">)</span>
<span class="nv">last_noncom: </span> <span class="nx">non_comments</span><span class="p">[</span><span class="nx">non_comments</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
<span class="nv">props: </span><span class="k">for</span> <span class="nx">prop</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@properties</span>
<span class="nv">join: </span> <span class="s2">&quot;,\n&quot;</span>
<span class="nv">join: </span> <span class="s2">&quot;\n&quot;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">prop</span> <span class="o">is</span> <span class="nx">last_noncom</span><span class="p">)</span> <span class="o">or</span> <span class="p">(</span><span class="nx">prop</span> <span class="k">instanceof</span> <span class="nx">CommentNode</span><span class="p">)</span>
<span class="nv">join: </span> <span class="s1">&#39;&#39;</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nv">indent: </span><span class="k">if</span> <span class="nx">prop</span> <span class="k">instanceof</span> <span class="nx">CommentNode</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="nx">@idt</span> <span class="mi">1</span>
<span class="nx">indent</span> <span class="o">+</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="nx">join</span>
<span class="nv">props: </span><span class="nx">props</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
<span class="nv">inner: </span><span class="k">if</span> <span class="nx">props</span> <span class="k">then</span> <span class="s1">&#39;\n&#39;</span> <span class="o">+</span> <span class="nx">props</span> <span class="o">+</span> <span class="s1">&#39;\n&#39;</span> <span class="o">+</span> <span class="nx">@idt</span><span class="p">()</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="s2">&quot;{$inner}&quot;</span></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-71">#</a> </div> <h3>ArrayNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-72">#</a> </div> <p>An array literal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ArrayNode: </span><span class="nx">class</span> <span class="nx">ArrayNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">objects</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: @objects: </span><span class="nx">objects</span> <span class="o">or</span> <span class="p">[]</span>
<span class="vi">@compile_splat_literal: </span><span class="nx">SplatNode</span><span class="p">.</span><span class="nx">compile_mixed_array</span> <span class="o">&lt;-</span> <span class="err">@</span><span class="p">,</span> <span class="nx">@objects</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o.indent: </span><span class="nx">@idt</span> <span class="mi">1</span>
<span class="nv">objects: </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@objects</span>
<span class="nv">code: </span><span class="nx">obj</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">SplatNode</span>
<span class="k">return</span> <span class="nx">@compile_splat_literal</span> <span class="nx">@objects</span><span class="p">,</span> <span class="nx">o</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">CommentNode</span>
<span class="nx">objects</span><span class="p">.</span><span class="nx">push</span> <span class="s2">&quot;\n$code\n$o.indent&quot;</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="nx">@objects</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nx">objects</span><span class="p">.</span><span class="nx">push</span> <span class="nx">code</span>
<span class="k">else</span>
<span class="nx">objects</span><span class="p">.</span><span class="nx">push</span> <span class="s2">&quot;$code, &quot;</span>
<span class="nv">objects: </span><span class="nx">objects</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
<span class="nv">ending: </span><span class="k">if</span> <span class="nx">objects</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">&#39;\n&#39;</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="k">then</span> <span class="s2">&quot;\n$@tab]&quot;</span> <span class="k">else</span> <span class="s1">&#39;]&#39;</span>
<span class="s2">&quot;[$objects$ending&quot;</span></pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-73">#</a> </div> <h3>ClassNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-74"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-74">#</a> </div> <p>The CoffeeScript class definition.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ClassNode: </span><span class="nx">class</span> <span class="nx">ClassNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span></pre></div> </td> </tr> <tr id="section-75"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-75">#</a> </div> <p>Initialize a <strong>ClassNode</strong> with its name, an optional superclass, and a
list of prototype property assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">constructor: </span><span class="p">(</span><span class="nx">variable</span><span class="p">,</span> <span class="nx">parent</span><span class="p">,</span> <span class="nx">props</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="nx">compact</span> <span class="nx">flatten</span> <span class="p">[</span><span class="vi">@variable: </span><span class="nx">variable</span><span class="p">,</span> <span class="vi">@parent: </span><span class="nx">parent</span><span class="p">,</span> <span class="vi">@properties: </span><span class="nx">props</span> <span class="o">or</span> <span class="p">[]]</span>
<span class="vi">@returns: </span> <span class="kc">false</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="vi">@returns: </span><span class="kc">true</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-76"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-76">#</a> </div> <p>Instead of generating the JavaScript string directly, we build up the
equivalent syntax tree and compile that, in pieces. You can see the
constructor, property assignments, and inheritance getting built out below.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">extension: </span> <span class="nx">@parent</span> <span class="o">and</span> <span class="k">new</span> <span class="nx">ExtendsNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">)</span>
<span class="nv">constructor: </span><span class="kc">null</span>
<span class="nv">props: </span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
<span class="nv">o.top: </span> <span class="kc">true</span>
<span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">@properties</span>
<span class="p">[</span><span class="nx">pvar</span><span class="p">,</span> <span class="nx">func</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">prop</span><span class="p">.</span><span class="nx">variable</span><span class="p">,</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">value</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">pvar</span> <span class="o">and</span> <span class="nx">pvar</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;constructor&#39;</span> <span class="o">and</span> <span class="nx">func</span> <span class="k">instanceof</span> <span class="nx">CodeNode</span>
<span class="nx">func</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">new</span> <span class="nx">ReturnNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;this&#39;</span><span class="p">)))</span>
<span class="nv">constructor: </span><span class="k">new</span> <span class="nx">AssignNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span>
<span class="k">else</span>
<span class="k">if</span> <span class="nx">pvar</span>
<span class="nv">access: </span><span class="k">if</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">context</span> <span class="o">is</span> <span class="s1">&#39;this&#39;</span> <span class="k">then</span> <span class="nx">pvar</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">properties</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">else</span> <span class="k">new</span> <span class="nx">AccessorNode</span><span class="p">(</span><span class="nx">pvar</span><span class="p">,</span> <span class="s1">&#39;prototype&#39;</span><span class="p">)</span>
<span class="nv">val: </span> <span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="p">[</span><span class="nx">access</span><span class="p">])</span>
<span class="nv">prop: </span> <span class="k">new</span> <span class="nx">AssignNode</span><span class="p">(</span><span class="nx">val</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span>
<span class="nx">props</span><span class="p">.</span><span class="nx">push</span> <span class="nx">prop</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">constructor</span>
<span class="k">if</span> <span class="nx">@parent</span>
<span class="nv">applied: </span><span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">@parent</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">AccessorNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;apply&#39;</span><span class="p">))])</span>
<span class="nv">constructor: </span><span class="k">new</span> <span class="nx">AssignNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="k">new</span> <span class="nx">CodeNode</span><span class="p">([],</span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">([</span>
<span class="k">new</span> <span class="nx">CallNode</span><span class="p">(</span><span class="nx">applied</span><span class="p">,</span> <span class="p">[</span><span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;this&#39;</span><span class="p">),</span> <span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;arguments&#39;</span><span class="p">)])</span>
<span class="p">])))</span>
<span class="k">else</span>
<span class="nv">constructor: </span><span class="k">new</span> <span class="nx">AssignNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="k">new</span> <span class="nx">CodeNode</span><span class="p">())</span>
<span class="nv">construct: </span> <span class="nx">@idt</span><span class="p">()</span> <span class="o">+</span> <span class="nx">constructor</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;;\n&#39;</span>
<span class="nv">props: </span> <span class="k">if</span> <span class="nx">props</span><span class="p">.</span><span class="nx">empty</span><span class="p">()</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="nx">props</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;\n&#39;</span>
<span class="nv">extension: </span><span class="k">if</span> <span class="nx">extension</span> <span class="k">then</span> <span class="nx">@idt</span><span class="p">()</span> <span class="o">+</span> <span class="nx">extension</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;;\n&#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">returns: </span> <span class="k">if</span> <span class="nx">@returns</span> <span class="k">then</span> <span class="k">new</span> <span class="nx">ReturnNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="s2">&quot;$construct$extension$props$returns&quot;</span>
<span class="nx">statement</span> <span class="nx">ClassNode</span></pre></div> </td> </tr> <tr id="section-77"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-77">#</a> </div> <h3>AssignNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-78"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-78">#</a> </div> <p>The <strong>AssignNode</strong> is used to assign a local variable to value, or to set the
property of an object -- including within object literals.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.AssignNode: </span><span class="nx">class</span> <span class="nx">AssignNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span></pre></div> </td> </tr> <tr id="section-79"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-79">#</a> </div> <p>Matchers for detecting prototype assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">PROTO_ASSIGN: </span><span class="sr">/^(\S+)\.prototype/</span>
<span class="nv">LEADING_DOT: </span> <span class="sr">/^\.(prototype\.)?/</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">variable</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">context</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@variable: </span><span class="nx">variable</span><span class="p">,</span> <span class="vi">@value: </span><span class="nx">value</span><span class="p">]</span>
<span class="vi">@context: </span><span class="nx">context</span>
<span class="nv">top_sensitive: </span><span class="o">-&gt;</span>
<span class="kc">true</span>
<span class="nv">is_value: </span><span class="o">-&gt;</span>
<span class="nx">@variable</span> <span class="k">instanceof</span> <span class="nx">ValueNode</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="k">this</span><span class="p">,</span> <span class="k">new</span> <span class="nx">ReturnNode</span><span class="p">(</span><span class="nx">@variable</span><span class="p">)]</span>
<span class="nv">is_statement: </span><span class="o">-&gt;</span>
<span class="nx">@is_value</span><span class="p">()</span> <span class="o">and</span> <span class="p">(</span><span class="nx">@variable</span><span class="p">.</span><span class="nx">is_array</span><span class="p">()</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">is_object</span><span class="p">())</span></pre></div> </td> </tr> <tr id="section-80"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-80">#</a> </div> <p>Compile an assignment, delegating to <code>compile_pattern_match</code> or
<code>compile_splice</code> if appropriate. Keep track of the name of the base object
we've been assigned to, for correct internal references. If the variable
has not been seen yet within the current scope, declare it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">top: </span> <span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;top&#39;</span>
<span class="k">return</span> <span class="nx">@compile_pattern_match</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@is_statement</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">@compile_splice</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@is_value</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">is_splice</span><span class="p">()</span>
<span class="nv">stmt: </span> <span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;as_statement&#39;</span>
<span class="nv">name: </span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">last: </span> <span class="k">if</span> <span class="nx">@is_value</span><span class="p">()</span> <span class="k">then</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">last</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">@LEADING_DOT</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">else</span> <span class="nx">name</span>
<span class="nv">match: </span> <span class="nx">name</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">@PROTO_ASSIGN</span><span class="p">)</span>
<span class="nv">proto: </span> <span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">@value</span> <span class="k">instanceof</span> <span class="nx">CodeNode</span>
<span class="vi">@value.name: </span> <span class="nx">last</span> <span class="k">if</span> <span class="nx">last</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">IDENTIFIER</span><span class="p">)</span>
<span class="vi">@value.proto: </span><span class="nx">proto</span> <span class="k">if</span> <span class="nx">proto</span>
<span class="nv">val: </span><span class="nx">@value</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="k">return</span> <span class="s2">&quot;$name: $val&quot;</span> <span class="k">if</span> <span class="nx">@context</span> <span class="o">is</span> <span class="s1">&#39;object&#39;</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">find</span> <span class="nx">name</span> <span class="nx">unless</span> <span class="nx">@is_value</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">has_properties</span><span class="p">()</span>
<span class="nv">val: </span><span class="s2">&quot;$name = $val&quot;</span>
<span class="k">return</span> <span class="s2">&quot;$@tab$val;&quot;</span> <span class="k">if</span> <span class="nx">stmt</span>
<span class="k">if</span> <span class="nx">top</span> <span class="k">then</span> <span class="nx">val</span> <span class="k">else</span> <span class="s2">&quot;($val)&quot;</span></pre></div> </td> </tr> <tr id="section-81"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-81">#</a> </div> <p>Brief implementation of recursive pattern matching, when assigning array or
object literals to a value. Peeks at their properties to assign inner names.
See the <a href="http://wiki.ecmascript.org/doku.php?id=harmony:destructuring">ECMAScript Harmony Wiki</a>
for details.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_pattern_match: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">val_var: </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">value: </span><span class="k">if</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()</span> <span class="k">then</span> <span class="nx">ClosureNode</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="nx">@value</span><span class="p">)</span> <span class="k">else</span> <span class="nx">@value</span>
<span class="nv">assigns: </span><span class="p">[</span><span class="s2">&quot;$@tab$val_var = ${ value.compile(o) };&quot;</span><span class="p">]</span>
<span class="nv">o.top: </span><span class="kc">true</span>
<span class="nv">o.as_statement: </span><span class="kc">true</span>
<span class="nv">splat: </span><span class="kc">false</span>
<span class="k">for</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">objects</span>
<span class="nv">idx: </span><span class="nx">i</span>
<span class="p">[</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">idx</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">obj</span><span class="p">.</span><span class="nx">value</span><span class="p">,</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">variable</span><span class="p">.</span><span class="nx">base</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">is_object</span><span class="p">()</span>
<span class="nv">access_class: </span><span class="k">if</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">is_array</span><span class="p">()</span> <span class="k">then</span> <span class="nx">IndexNode</span> <span class="k">else</span> <span class="nx">AccessorNode</span>
<span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">SplatNode</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">splat</span>
<span class="nv">val: </span><span class="nx">literal</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">compile_value</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">val_var</span><span class="p">,</span>
<span class="p">(</span><span class="nv">oindex: </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">obj</span><span class="p">)),</span>
<span class="p">(</span><span class="nv">olength: </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">objects</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="o">-</span> <span class="nx">oindex</span> <span class="o">-</span> <span class="mi">1</span><span class="p">))</span>
<span class="nv">splat: </span><span class="kc">true</span>
<span class="k">else</span>
<span class="nv">idx: </span><span class="nx">literal</span><span class="p">(</span><span class="k">if</span> <span class="nx">splat</span> <span class="k">then</span> <span class="s2">&quot;${val_var}.length - ${olength - idx}&quot;</span> <span class="k">else</span> <span class="nx">idx</span><span class="p">)</span> <span class="k">if</span> <span class="k">typeof</span> <span class="nx">idx</span> <span class="o">isnt</span> <span class="s1">&#39;object&#39;</span>
<span class="nv">val: </span><span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="nx">val_var</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">access_class</span><span class="p">(</span><span class="nx">idx</span><span class="p">)])</span>
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">new</span> <span class="nx">AssignNode</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">val</span><span class="p">).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">))</span>
<span class="nv">code: </span><span class="nx">assigns</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&quot;\n&quot;</span><span class="p">)</span>
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-82"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-82">#</a> </div> <p>Compile the assignment from an array splice literal, using JavaScript's
<code>Array#splice</code> method.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_splice: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">name: </span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">merge</span> <span class="nx">o</span><span class="p">,</span> <span class="p">{</span><span class="nv">only_first: </span><span class="kc">true</span><span class="p">}</span>
<span class="nv">l: </span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">range: </span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">properties</span><span class="p">[</span><span class="nx">l</span> <span class="o">-</span> <span class="mi">1</span><span class="p">].</span><span class="nx">range</span>
<span class="nv">plus: </span> <span class="k">if</span> <span class="nx">range</span><span class="p">.</span><span class="nx">exclusive</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="s1">&#39; + 1&#39;</span>
<span class="nv">from: </span> <span class="nx">range</span><span class="p">.</span><span class="nx">from</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">to: </span> <span class="nx">range</span><span class="p">.</span><span class="nx">to</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39; - &#39;</span> <span class="o">+</span> <span class="nx">from</span> <span class="o">+</span> <span class="nx">plus</span>
<span class="nv">val: </span> <span class="nx">@value</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="s2">&quot;${name}.splice.apply($name, [$from, $to].concat($val))&quot;</span></pre></div> </td> </tr> <tr id="section-83"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-83">#</a> </div> <h3>CodeNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-84"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-84">#</a> </div> <p>A function definition. This is the only node that creates a new Scope.
When for the purposes of walking the contents of a function body, the CodeNode
has no <em>children</em> -- they're within the inner scope.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.CodeNode: </span><span class="nx">class</span> <span class="nx">CodeNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">params</span><span class="p">,</span> <span class="nx">body</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@params: </span> <span class="nx">params</span> <span class="o">or</span> <span class="p">[]</span>
<span class="vi">@body: </span> <span class="nx">body</span> <span class="o">or</span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
<span class="vi">@bound: </span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;boundfunc&#39;</span></pre></div> </td> </tr> <tr id="section-85"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-85">#</a> </div> <p>Compilation creates a new scope unless explicitly asked to share with the
outer scope. Handles splat parameters in the parameter list by peeking at
the JavaScript <code>arguments</code> objects. If the function is bound with the <code>=&gt;</code>
arrow, generates a wrapper that saves the current value of <code>this</code> through
a closure.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">shared_scope: </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;shared_scope&#39;</span>
<span class="nv">top: </span> <span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;top&#39;</span>
<span class="nv">o.scope: </span> <span class="nx">shared_scope</span> <span class="o">or</span> <span class="k">new</span> <span class="nx">Scope</span><span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">,</span> <span class="nx">@body</span><span class="p">,</span> <span class="k">this</span><span class="p">)</span>
<span class="nv">o.top: </span> <span class="kc">true</span>
<span class="nv">o.indent: </span> <span class="nx">@idt</span><span class="p">(</span><span class="k">if</span> <span class="nx">@bound</span> <span class="k">then</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">1</span><span class="p">)</span>
<span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;no_wrap&#39;</span>
<span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;globals&#39;</span>
<span class="nv">i: </span><span class="mi">0</span>
<span class="nv">splat: </span><span class="kc">undefined</span>
<span class="nv">params: </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">param</span> <span class="k">in</span> <span class="nx">@params</span>
<span class="k">if</span> <span class="nx">param</span> <span class="k">instanceof</span> <span class="nx">SplatNode</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">splat</span><span class="o">?</span>
<span class="nv">splat: </span><span class="nx">param</span>
<span class="nv">splat.index: </span><span class="nx">i</span>
<span class="nx">@body</span><span class="p">.</span><span class="nx">unshift</span><span class="p">(</span><span class="nx">splat</span><span class="p">)</span>
<span class="nv">splat.trailings: </span><span class="p">[]</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">splat</span><span class="o">?</span>
<span class="nx">splat</span><span class="p">.</span><span class="nx">trailings</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">param</span><span class="p">)</span>
<span class="k">else</span>
<span class="nx">params</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">param</span><span class="p">)</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="nv">params: </span><span class="p">(</span><span class="nx">param</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">for</span> <span class="nx">param</span> <span class="k">in</span> <span class="nx">params</span><span class="p">)</span>
<span class="nx">@body</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span>
<span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">parameter</span><span class="p">(</span><span class="nx">param</span><span class="p">))</span> <span class="k">for</span> <span class="nx">param</span> <span class="k">in</span> <span class="nx">params</span>
<span class="nv">code: </span><span class="k">if</span> <span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">length</span> <span class="k">then</span> <span class="s2">&quot;\n${ @body.compile_with_declarations(o) }\n&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">name_part: </span><span class="k">if</span> <span class="nx">@name</span> <span class="k">then</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nx">@name</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">func: </span><span class="s2">&quot;function${ if @bound then &#39;&#39; else name_part }(${ params.join(&#39;, &#39;) }) {$code${@idt(if @bound then 1 else 0)}}&quot;</span>
<span class="nv">func: </span><span class="s2">&quot;($func)&quot;</span> <span class="k">if</span> <span class="nx">top</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@bound</span>
<span class="k">return</span> <span class="nx">func</span> <span class="nx">unless</span> <span class="nx">@bound</span>
<span class="nx">utility</span> <span class="s1">&#39;slice&#39;</span>
<span class="nv">ref: </span><span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">literal</span> <span class="nx">utility</span> <span class="s1">&#39;bind&#39;</span>
<span class="p">(</span><span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">ref</span><span class="p">,</span> <span class="p">[</span><span class="nx">literal</span><span class="p">(</span><span class="nx">func</span><span class="p">),</span> <span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;this&#39;</span><span class="p">)]).</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">top_sensitive: </span><span class="o">-&gt;</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-86"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-86">#</a> </div> <p>When traversing (for printing or inspecting), return the real children of
the function -- the parameters and body of expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">real_children: </span><span class="o">-&gt;</span>
<span class="nx">flatten</span> <span class="p">[</span><span class="nx">@params</span><span class="p">,</span> <span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-87"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-87">#</a> </div> <p>Custom <code>traverse</code> implementation that uses the <code>real_children</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">traverse: </span><span class="p">(</span><span class="nx">block</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">block</span> <span class="k">this</span>
<span class="nx">child</span><span class="p">.</span><span class="nx">traverse</span> <span class="nx">block</span> <span class="k">for</span> <span class="nx">child</span> <span class="k">in</span> <span class="nx">@real_children</span><span class="p">()</span>
<span class="nv">toString: </span><span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">idt: </span><span class="o">or</span> <span class="s1">&#39;&#39;</span>
<span class="nv">children: </span><span class="p">(</span><span class="nx">child</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="nx">idt</span> <span class="o">+</span> <span class="nx">TAB</span><span class="p">)</span> <span class="k">for</span> <span class="nx">child</span> <span class="k">in</span> <span class="nx">@real_children</span><span class="p">()).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
<span class="s2">&quot;\n$idt$children&quot;</span></pre></div> </td> </tr> <tr id="section-88"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-88">#</a> </div> <h3>SplatNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-89"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-89">#</a> </div> <p>A splat, either as a parameter to a function, an argument to a call,
or as part of a destructuring assignment.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.SplatNode: </span><span class="nx">class</span> <span class="nx">SplatNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">name: </span><span class="nx">literal</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">name</span><span class="p">.</span><span class="nx">compile</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@name: </span><span class="nx">name</span><span class="p">]</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@index</span><span class="o">?</span> <span class="k">then</span> <span class="nx">@compile_param</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-90"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-90">#</a> </div> <p>Compiling a parameter splat means recovering the parameters that succeed
the splat in the parameter list, by slicing the arguments object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_param: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">name: </span><span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">find</span> <span class="nx">name</span>
<span class="nv">i: </span><span class="mi">0</span>
<span class="k">for</span> <span class="nx">trailing</span> <span class="k">in</span> <span class="nx">@trailings</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="nx">trailing</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="s2">&quot;arguments[arguments.length - $@trailings.length + $i]&quot;</span><span class="p">)</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="s2">&quot;$name = ${utility(&#39;slice&#39;)}.call(arguments, $@index, arguments.length - ${@trailings.length})&quot;</span></pre></div> </td> </tr> <tr id="section-91"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-91">#</a> </div> <p>A compiling a splat as a destructuring assignment means slicing arguments
from the right-hand-side's corresponding array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_value: </span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">,</span> <span class="nx">trailings</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">trail: </span><span class="k">if</span> <span class="nx">trailings</span> <span class="k">then</span> <span class="s2">&quot;, ${name}.length - $trailings&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="s2">&quot;${utility &#39;slice&#39;}.call($name, $index$trail)&quot;</span></pre></div> </td> </tr> <tr id="section-92"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-92">#</a> </div> <p>Utility function that converts arbitrary number of elements, mixed with
splats, to a proper array</p> </td> <td class="code"> <div class="highlight"><pre> <span class="vi">@compile_mixed_array: </span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">args: </span><span class="p">[]</span>
<span class="nv">i: </span><span class="mi">0</span>
<span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">list</span>
<span class="nv">code: </span><span class="nx">arg</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="k">if</span> <span class="o">not</span> <span class="p">(</span><span class="nx">arg</span> <span class="k">instanceof</span> <span class="nx">SplatNode</span><span class="p">)</span>
<span class="nv">prev: </span><span class="nx">args</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;[&#39;</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">prev</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;]&#39;</span>
<span class="nx">args</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="s2">&quot;${prev.substr(0, prev.length - 1)}, $code]&quot;</span>
<span class="k">continue</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;.concat([&#39;</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">prev</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;])&#39;</span>
<span class="nx">args</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="s2">&quot;${prev.substr(0, prev.length - 2)}, $code])&quot;</span>
<span class="k">continue</span>
<span class="k">else</span>
<span class="nv">code: </span><span class="s2">&quot;[$code]&quot;</span>
<span class="nx">args</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="mi">0</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">&quot;.concat($code)&quot;</span><span class="p">)</span>
<span class="nv">i: </span><span class="o">+</span> <span class="mi">1</span>
<span class="nx">args</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-93"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-93">#</a> </div> <h3>WhileNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-94"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-94">#</a> </div> <p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From
it, all other loops can be manufactured. Useful in cases where you need more
flexibility or more speed than a comprehension can provide.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.WhileNode: </span><span class="nx">class</span> <span class="nx">WhileNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">condition</span><span class="p">,</span> <span class="nx">opts</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@children</span><span class="o">:</span><span class="p">[</span><span class="vi">@condition: </span><span class="nx">condition</span><span class="p">]</span>
<span class="vi">@filter: </span><span class="nx">opts</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">filter</span>
<span class="nv">add_body: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@children</span><span class="p">.</span><span class="nx">push</span> <span class="vi">@body: </span><span class="nx">body</span>
<span class="k">this</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="vi">@returns: </span><span class="kc">true</span>
<span class="k">this</span>
<span class="nv">top_sensitive: </span><span class="o">-&gt;</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-95"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-95">#</a> </div> <p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript
<em>while</em> can be used as a part of a larger expression -- while loops may
return an array containing the computed result of each iteration.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">top: </span> <span class="nx">del</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;top&#39;</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@returns</span>
<span class="nv">o.indent: </span> <span class="nx">@idt</span> <span class="mi">1</span>
<span class="nv">o.top: </span> <span class="kc">true</span>
<span class="nv">cond: </span> <span class="nx">@condition</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">set: </span> <span class="s1">&#39;&#39;</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">top</span>
<span class="nv">rvar: </span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">set: </span> <span class="s2">&quot;$@tab$rvar = [];\n&quot;</span>
<span class="vi">@body: </span> <span class="nx">PushNode</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="nx">rvar</span><span class="p">,</span> <span class="nx">@body</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@body</span>
<span class="nv">pre: </span> <span class="s2">&quot;$set${@tab}while ($cond)&quot;</span>
<span class="k">return</span> <span class="s2">&quot;$pre null;$post&quot;</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">@body</span>
<span class="vi">@body: </span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="k">new</span> <span class="nx">IfNode</span><span class="p">(</span><span class="nx">@filter</span><span class="p">,</span> <span class="nx">@body</span><span class="p">)])</span> <span class="k">if</span> <span class="nx">@filter</span>
<span class="k">if</span> <span class="nx">@returns</span>
<span class="nv">post: </span><span class="k">new</span> <span class="nx">ReturnNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="nx">rvar</span><span class="p">)).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{</span><span class="nv">indent: </span><span class="nx">@idt</span><span class="p">()}))</span>
<span class="k">else</span>
<span class="nv">post: </span><span class="s1">&#39;&#39;</span>
<span class="s2">&quot;$pre {\n${ @body.compile(o) }\n$@tab}\n$post&quot;</span>
<span class="nx">statement</span> <span class="nx">WhileNode</span></pre></div> </td> </tr> <tr id="section-96"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-96">#</a> </div> <h3>OpNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-97"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-97">#</a> </div> <p>Simple Arithmetic and logical operations. Performs some conversion from
CoffeeScript operations into their JavaScript equivalents.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.OpNode: </span><span class="nx">class</span> <span class="nx">OpNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-98">#</a> </div> <p>The map of conversions from CoffeeScript to JavaScript symbols.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">CONVERSIONS: </span><span class="p">{</span>
<span class="s1">&#39;==&#39;</span><span class="o">:</span> <span class="s1">&#39;===&#39;</span>
<span class="s1">&#39;!=&#39;</span><span class="o">:</span> <span class="s1">&#39;!==&#39;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-99">#</a> </div> <p>The list of operators for which we perform
<a href="http://docs.python.org/reference/expressions.html#notin">Python-style comparison chaining</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">CHAINABLE: </span> <span class="p">[</span><span class="s1">&#39;&lt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&gt;=&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;=&#39;</span><span class="p">,</span> <span class="s1">&#39;===&#39;</span><span class="p">,</span> <span class="s1">&#39;!==&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-100">#</a> </div> <p>Our assignment operators that have no JavaScript equivalent.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ASSIGNMENT: </span> <span class="p">[</span><span class="s1">&#39;||=&#39;</span><span class="p">,</span> <span class="s1">&#39;&amp;&amp;=&#39;</span><span class="p">,</span> <span class="s1">&#39;?=&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-101">#</a> </div> <p>Operators must come before their operands with a space.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">PREFIX_OPERATORS: </span><span class="p">[</span><span class="s1">&#39;typeof&#39;</span><span class="p">,</span> <span class="s1">&#39;delete&#39;</span><span class="p">]</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">operator</span><span class="p">,</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">,</span> <span class="nx">flip</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@constructor.name: </span><span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nx">operator</span>
<span class="vi">@children: </span><span class="nx">compact</span> <span class="p">[</span><span class="vi">@first: </span><span class="nx">first</span><span class="p">,</span> <span class="vi">@second: </span><span class="nx">second</span><span class="p">]</span>
<span class="vi">@operator: </span><span class="nx">@CONVERSIONS</span><span class="p">[</span><span class="nx">operator</span><span class="p">]</span> <span class="o">or</span> <span class="nx">operator</span>
<span class="vi">@flip: </span><span class="o">!!</span><span class="nx">flip</span>
<span class="nv">is_unary: </span><span class="o">-&gt;</span>
<span class="o">not</span> <span class="nx">@second</span>
<span class="nv">is_chainable: </span><span class="o">-&gt;</span>
<span class="nx">@CHAINABLE</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">@operator</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o.operation: </span><span class="kc">true</span>
<span class="k">return</span> <span class="nx">@compile_chain</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@is_chainable</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span> <span class="k">instanceof</span> <span class="nx">OpNode</span> <span class="o">and</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">().</span><span class="nx">is_chainable</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">@compile_assignment</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@ASSIGNMENT</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">@operator</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span>
<span class="k">return</span> <span class="nx">@compile_unary</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@is_unary</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">@compile_existence</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@operator</span> <span class="o">is</span> <span class="s1">&#39;?&#39;</span>
<span class="p">[</span><span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">@operator</span><span class="p">,</span> <span class="nx">@second</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)].</span><span class="nx">join</span> <span class="s1">&#39; &#39;</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-102">#</a> </div> <p>Mimic Python's chained comparisons when multiple comparison operators are
used sequentially. For example:</p>
<pre><code>bin/coffee -e "puts 50 &lt; 65 &gt; 10"
true
</code></pre> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_chain: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">shared: </span><span class="nx">@first</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">().</span><span class="nx">second</span>
<span class="p">[</span><span class="nx">@first</span><span class="p">.</span><span class="nx">second</span><span class="p">,</span> <span class="nx">shared</span><span class="p">]</span><span class="o">:</span> <span class="nx">shared</span><span class="p">.</span><span class="nx">compile_reference</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">shared</span><span class="p">.</span><span class="nx">contains_type</span> <span class="nx">CallNode</span>
<span class="p">[</span><span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">,</span> <span class="nx">shared</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">@second</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">shared</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)]</span>
<span class="s2">&quot;($first) &amp;&amp; ($shared $@operator $second)&quot;</span></pre></div> </td> </tr> <tr id="section-103"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-103">#</a> </div> <p>When compiling a conditional assignment, take care to ensure that the
operands are only evaluated once, even though we have to reference them
more than once.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_assignment: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">[</span><span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">@second</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)]</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="nx">first</span><span class="p">)</span> <span class="k">if</span> <span class="nx">first</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">IDENTIFIER</span><span class="p">)</span>
<span class="k">return</span> <span class="s2">&quot;$first = ${ ExistenceNode.compile_test(o, @first) } ? $first : $second&quot;</span> <span class="k">if</span> <span class="nx">@operator</span> <span class="o">is</span> <span class="s1">&#39;?=&#39;</span>
<span class="s2">&quot;$first = $first ${ @operator.substr(0, 2) } $second&quot;</span></pre></div> </td> </tr> <tr id="section-104"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-104">#</a> </div> <p>If this is an existence operator, we delegate to <code>ExistenceNode.compile_test</code>
to give us the safe references for the variables.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_existence: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">[</span><span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">@second</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)]</span>
<span class="nv">test: </span><span class="nx">ExistenceNode</span><span class="p">.</span><span class="nx">compile_test</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">@first</span><span class="p">)</span>
<span class="s2">&quot;$test ? $first : $second&quot;</span></pre></div> </td> </tr> <tr id="section-105"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-105">#</a> </div> <p>Compile a unary <strong>OpNode</strong>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_unary: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">space: </span><span class="k">if</span> <span class="nx">@PREFIX_OPERATORS</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">@operator</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="k">then</span> <span class="s1">&#39; &#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">parts: </span><span class="p">[</span><span class="nx">@operator</span><span class="p">,</span> <span class="nx">space</span><span class="p">,</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)]</span>
<span class="nv">parts: </span><span class="nx">parts</span><span class="p">.</span><span class="nx">reverse</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@flip</span>
<span class="nx">parts</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-106"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-106">#</a> </div> <h3>TryNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-107"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-107">#</a> </div> <p>A classic <em>try/catch/finally</em> block.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.TryNode: </span><span class="nx">class</span> <span class="nx">TryNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">attempt</span><span class="p">,</span> <span class="nx">error</span><span class="p">,</span> <span class="nx">recovery</span><span class="p">,</span> <span class="nx">ensure</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="nx">compact</span> <span class="p">[</span><span class="vi">@attempt: </span><span class="nx">attempt</span><span class="p">,</span> <span class="vi">@recovery: </span><span class="nx">recovery</span><span class="p">,</span> <span class="vi">@ensure: </span><span class="nx">ensure</span><span class="p">]</span>
<span class="vi">@error: </span><span class="nx">error</span>
<span class="k">this</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="vi">@attempt: </span><span class="nx">@attempt</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@attempt</span>
<span class="vi">@recovery: </span><span class="nx">@recovery</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@recovery</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-108"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-108">#</a> </div> <p>Compilation is more or less as you would expect -- the <em>finally</em> clause
is optional, the <em>catch</em> is not.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o.indent: </span> <span class="nx">@idt</span> <span class="mi">1</span>
<span class="nv">o.top: </span> <span class="kc">true</span>
<span class="nv">attempt_part: </span><span class="nx">@attempt</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">error_part: </span> <span class="k">if</span> <span class="nx">@error</span> <span class="k">then</span> <span class="s2">&quot; (${ @error.compile(o) }) &quot;</span> <span class="k">else</span> <span class="s1">&#39; &#39;</span>
<span class="nv">catch_part: </span> <span class="k">if</span> <span class="nx">@recovery</span> <span class="k">then</span> <span class="s2">&quot; catch$error_part{\n${ @recovery.compile(o) }\n$@tab}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">finally_part: </span><span class="p">(</span><span class="nx">@ensure</span> <span class="o">or</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="o">and</span> <span class="s1">&#39; finally {\n&#39;</span> <span class="o">+</span> <span class="nx">@ensure</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">))</span> <span class="o">+</span> <span class="s2">&quot;\n$@tab}&quot;</span>
<span class="s2">&quot;${@tab}try {\n$attempt_part\n$@tab}$catch_part$finally_part&quot;</span>
<span class="nx">statement</span> <span class="nx">TryNode</span></pre></div> </td> </tr> <tr id="section-109"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-109">#</a> </div> <h3>ThrowNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-110"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-110">#</a> </div> <p>Simple node to throw an exception.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ThrowNode: </span><span class="nx">class</span> <span class="nx">ThrowNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">expression</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@expression: </span><span class="nx">expression</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-111"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-111">#</a> </div> <p>A <strong>ThrowNode</strong> is already a return, of sorts...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="k">return</span> <span class="k">this</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="s2">&quot;${@tab}throw ${@expression.compile(o)};&quot;</span>
<span class="nx">statement</span> <span class="nx">ThrowNode</span></pre></div> </td> </tr> <tr id="section-112"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-112">#</a> </div> <h3>ExistenceNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-113"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-113">#</a> </div> <p>Checks a variable for existence -- not <em>null</em> and not <em>undefined</em>. This is
similar to <code>.nil?</code> in Ruby, and avoids having to consult a JavaScript truth
table.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ExistenceNode: </span><span class="nx">class</span> <span class="nx">ExistenceNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">expression</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@expression: </span><span class="nx">expression</span><span class="p">]</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">ExistenceNode</span><span class="p">.</span><span class="nx">compile_test</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">@expression</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-114"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-114">#</a> </div> <p>The meat of the <strong>ExistenceNode</strong> is in this static <code>compile_test</code> method
because other nodes like to check the existence of their variables as well.
Be careful not to double-evaluate anything.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="vi">@compile_test: </span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">variable</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">[</span><span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">variable</span><span class="p">,</span> <span class="nx">variable</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">variable</span> <span class="k">instanceof</span> <span class="nx">CallNode</span> <span class="o">or</span> <span class="p">(</span><span class="nx">variable</span> <span class="k">instanceof</span> <span class="nx">ValueNode</span> <span class="o">and</span> <span class="nx">variable</span><span class="p">.</span><span class="nx">has_properties</span><span class="p">())</span>
<span class="p">[</span><span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">]</span><span class="o">:</span> <span class="nx">variable</span><span class="p">.</span><span class="nx">compile_reference</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="p">[</span><span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">),</span> <span class="nx">second</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)]</span>
<span class="s2">&quot;(typeof $first !== \&quot;undefined\&quot; &amp;&amp; $second !== null)&quot;</span></pre></div> </td> </tr> <tr id="section-115"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-115">#</a> </div> <h3>ParentheticalNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-116"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-116">#</a> </div> <p>An extra set of parentheses, specified explicitly in the source. At one time
we tried to clean up the results by detecting and removing redundant
parentheses, but no longer -- you can put in as many as you please.</p>
<p>Parentheses are a good way to force any statement to become an expression.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ParentheticalNode: </span><span class="nx">class</span> <span class="nx">ParentheticalNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">expression</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@children: </span><span class="p">[</span><span class="vi">@expression: </span><span class="nx">expression</span><span class="p">]</span>
<span class="nv">is_statement: </span><span class="o">-&gt;</span>
<span class="nx">@expression</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="nx">@expression</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">code: </span><span class="nx">@expression</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="k">return</span> <span class="nx">code</span> <span class="k">if</span> <span class="nx">@is_statement</span><span class="p">()</span>
<span class="nv">l: </span> <span class="nx">code</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">code: </span><span class="nx">code</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">l</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="nx">code</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">l</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;;&#39;</span>
<span class="k">if</span> <span class="nx">@expression</span> <span class="k">instanceof</span> <span class="nx">AssignNode</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">&quot;($code)&quot;</span></pre></div> </td> </tr> <tr id="section-117"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-117">#</a> </div> <h3>ForNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-118"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-118">#</a> </div> <p>CoffeeScript's replacement for the <em>for</em> loop is our array and object
comprehensions, that compile into <em>for</em> loops here. They also act as an
expression, able to return the result of each filtered iteration.</p>
<p>Unlike Python array comprehensions, they can be multi-line, and you can pass
the current index of the loop as a second parameter. Unlike Ruby blocks,
you can map and filter in a single pass.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ForNode: </span><span class="nx">class</span> <span class="nx">ForNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">body</span><span class="p">,</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@body: </span> <span class="nx">body</span>
<span class="vi">@name: </span> <span class="nx">name</span>
<span class="vi">@index: </span> <span class="nx">index</span> <span class="o">or</span> <span class="kc">null</span>
<span class="vi">@source: </span> <span class="nx">source</span><span class="p">.</span><span class="nx">source</span>
<span class="vi">@filter: </span> <span class="nx">source</span><span class="p">.</span><span class="nx">filter</span>
<span class="vi">@step: </span> <span class="nx">source</span><span class="p">.</span><span class="nx">step</span>
<span class="vi">@object: </span> <span class="o">!!</span><span class="nx">source</span><span class="p">.</span><span class="nx">object</span>
<span class="p">[</span><span class="nx">@name</span><span class="p">,</span> <span class="nx">@index</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@index</span><span class="p">,</span> <span class="nx">@name</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@object</span>
<span class="vi">@children: </span><span class="nx">compact</span> <span class="p">[</span><span class="nx">@body</span><span class="p">,</span> <span class="nx">@source</span><span class="p">,</span> <span class="nx">@filter</span><span class="p">]</span>
<span class="vi">@returns: </span><span class="kc">false</span>
<span class="nv">top_sensitive: </span><span class="o">-&gt;</span>
<span class="kc">true</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="vi">@returns: </span><span class="kc">true</span>
<span class="k">this</span>
<span class="nv">compile_return_value: </span><span class="p">(</span><span class="nx">val</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">ReturnNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="nx">val</span><span class="p">)).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@returns</span>
<span class="nx">val</span> <span class="o">or</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-119"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-119">#</a> </div> <p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner
loop, filtering, stepping, and result saving for array, object, and range
comprehensions. Some of the generated code can be shared in common, and
some cannot.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">top_level: </span> <span class="nx">del</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;top&#39;</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@returns</span>
<span class="nv">range: </span> <span class="nx">@source</span> <span class="k">instanceof</span> <span class="nx">ValueNode</span> <span class="o">and</span> <span class="nx">@source</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">RangeNode</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@source</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">source: </span> <span class="k">if</span> <span class="nx">range</span> <span class="k">then</span> <span class="nx">@source</span><span class="p">.</span><span class="nx">base</span> <span class="k">else</span> <span class="nx">@source</span>
<span class="nv">scope: </span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span>
<span class="nv">name: </span> <span class="nx">@name</span> <span class="o">and</span> <span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">index: </span> <span class="nx">@index</span> <span class="o">and</span> <span class="nx">@index</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nx">scope</span><span class="p">.</span><span class="nx">find</span> <span class="nx">name</span> <span class="k">if</span> <span class="nx">name</span>
<span class="nx">scope</span><span class="p">.</span><span class="nx">find</span> <span class="nx">index</span> <span class="k">if</span> <span class="nx">index</span>
<span class="nv">body_dent: </span> <span class="nx">@idt</span> <span class="mi">1</span>
<span class="nv">rvar: </span> <span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">top_level</span>
<span class="nv">ivar: </span> <span class="k">if</span> <span class="nx">range</span> <span class="k">then</span> <span class="nx">name</span> <span class="k">else</span> <span class="nx">index</span> <span class="o">or</span> <span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">var_part: </span> <span class="s1">&#39;&#39;</span>
<span class="nv">body: </span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">@body</span><span class="p">])</span>
<span class="k">if</span> <span class="nx">range</span>
<span class="nv">index_var: </span> <span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">source_part: </span> <span class="nx">source</span><span class="p">.</span><span class="nx">compile_variables</span> <span class="nx">o</span>
<span class="nv">for_part: </span> <span class="nx">source</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">merge</span> <span class="nx">o</span><span class="p">,</span> <span class="p">{</span><span class="nv">index: </span><span class="nx">ivar</span><span class="p">,</span> <span class="nv">step: </span><span class="nx">@step</span><span class="p">}</span>
<span class="nv">for_part: </span> <span class="s2">&quot;$index_var = 0, $for_part, $index_var++&quot;</span>
<span class="k">else</span>
<span class="nv">svar: </span> <span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">index_var: </span> <span class="kc">null</span>
<span class="nv">source_part: </span> <span class="s2">&quot;$svar = ${ @source.compile(o) };\n$@tab&quot;</span>
<span class="nv">var_part: </span> <span class="s2">&quot;$body_dent$name = $svar[$ivar];\n&quot;</span> <span class="k">if</span> <span class="nx">name</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">@object</span>
<span class="nv">lvar: </span> <span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">()</span>
<span class="nv">step_part: </span> <span class="k">if</span> <span class="nx">@step</span> <span class="k">then</span> <span class="s2">&quot;$ivar += ${ @step.compile(o) }&quot;</span> <span class="k">else</span> <span class="s2">&quot;$ivar++&quot;</span>
<span class="nv">for_part: </span> <span class="s2">&quot;$ivar = 0, $lvar = ${svar}.length; $ivar &lt; $lvar; $step_part&quot;</span>
<span class="nv">set_result: </span> <span class="k">if</span> <span class="nx">rvar</span> <span class="k">then</span> <span class="nx">@idt</span><span class="p">()</span> <span class="o">+</span> <span class="nx">rvar</span> <span class="o">+</span> <span class="s1">&#39; = []; &#39;</span> <span class="k">else</span> <span class="nx">@idt</span><span class="p">()</span>
<span class="nv">return_result: </span> <span class="nx">@compile_return_value</span><span class="p">(</span><span class="nx">rvar</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span>
<span class="nv">body: </span> <span class="nx">ClosureNode</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="nx">body</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span> <span class="k">if</span> <span class="nx">top_level</span> <span class="o">and</span> <span class="nx">body</span><span class="p">.</span><span class="nx">contains</span> <span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">n</span> <span class="k">instanceof</span> <span class="nx">CodeNode</span>
<span class="nv">body: </span> <span class="nx">PushNode</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="nx">rvar</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">top_level</span>
<span class="k">if</span> <span class="nx">@filter</span>
<span class="nv">body: </span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="k">new</span> <span class="nx">IfNode</span><span class="p">(</span><span class="nx">@filter</span><span class="p">,</span> <span class="nx">body</span><span class="p">)])</span>
<span class="k">if</span> <span class="nx">@object</span>
<span class="nv">for_part: </span><span class="s2">&quot;$ivar in $svar) { if (${utility(&#39;hasProp&#39;)}.call($svar, $ivar)&quot;</span>
<span class="nv">body: </span> <span class="nx">body</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{</span><span class="nv">indent: </span><span class="nx">body_dent</span><span class="p">,</span> <span class="nv">top: </span><span class="kc">true</span><span class="p">}))</span>
<span class="nv">vars: </span> <span class="k">if</span> <span class="nx">range</span> <span class="k">then</span> <span class="nx">name</span> <span class="k">else</span> <span class="s2">&quot;$name, $ivar&quot;</span>
<span class="nv">close: </span> <span class="k">if</span> <span class="nx">@object</span> <span class="k">then</span> <span class="s1">&#39;}}\n&#39;</span> <span class="k">else</span> <span class="s1">&#39;}\n&#39;</span>
<span class="s2">&quot;$set_result${source_part}for ($for_part) {\n$var_part$body\n$@tab$close$return_result&quot;</span>
<span class="nx">statement</span> <span class="nx">ForNode</span></pre></div> </td> </tr> <tr id="section-120"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-120">#</a> </div> <h3>IfNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-121"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-121">#</a> </div> <p><em>If/else</em> statements. Our <em>switch/when</em> will be compiled into this. Acts as an
expression by pushing down requested returns to the last line of each clause.</p>
<p>Single-expression <strong>IfNodes</strong> are compiled into ternary operators if possible,
because ternaries are already proper expressions, and don't need conversion.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.IfNode: </span><span class="nx">class</span> <span class="nx">IfNode</span> <span class="k">extends</span> <span class="nx">BaseNode</span>
<span class="nv">constructor: </span><span class="p">(</span><span class="nx">condition</span><span class="p">,</span> <span class="nx">body</span><span class="p">,</span> <span class="nx">else_body</span><span class="p">,</span> <span class="nx">tags</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@condition: </span><span class="nx">condition</span>
<span class="vi">@body: </span> <span class="nx">body</span> <span class="o">and</span> <span class="nx">body</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span>
<span class="vi">@else_body: </span><span class="nx">else_body</span> <span class="o">and</span> <span class="nx">else_body</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span>
<span class="vi">@children: </span> <span class="nx">compact</span> <span class="nx">flatten</span> <span class="p">[</span><span class="nx">@condition</span><span class="p">,</span> <span class="nx">@body</span><span class="p">,</span> <span class="nx">@else_body</span><span class="p">]</span>
<span class="vi">@tags: </span> <span class="nx">tags</span> <span class="o">or</span> <span class="p">{}</span>
<span class="vi">@multiple: </span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@condition</span> <span class="k">instanceof</span> <span class="nb">Array</span>
<span class="vi">@condition: </span><span class="k">new</span> <span class="nx">OpNode</span><span class="p">(</span><span class="s1">&#39;!&#39;</span><span class="p">,</span> <span class="k">new</span> <span class="nx">ParentheticalNode</span><span class="p">(</span><span class="nx">@condition</span><span class="p">))</span> <span class="k">if</span> <span class="nx">@tags</span><span class="p">.</span><span class="nx">invert</span></pre></div> </td> </tr> <tr id="section-122"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-122">#</a> </div> <p>Add a new <em>else</em> clause to this <strong>IfNode</strong>, or push it down to the bottom
of the chain recursively.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">push: </span><span class="p">(</span><span class="nx">else_body</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">eb: </span><span class="nx">else_body</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">@else_body</span> <span class="k">then</span> <span class="nx">@else_body</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">eb</span><span class="p">)</span> <span class="k">else</span> <span class="vi">@else_body: </span><span class="nx">eb</span>
<span class="k">this</span>
<span class="nv">force_statement: </span><span class="o">-&gt;</span>
<span class="vi">@tags.statement: </span><span class="kc">true</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-123"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-123">#</a> </div> <p>Tag a chain of <strong>IfNodes</strong> with their object(s) to switch on for equality
tests. <code>rewrite_switch</code> will perform the actual change at compile time.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite_condition: </span><span class="p">(</span><span class="nx">expression</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@switcher: </span><span class="nx">expression</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-124"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-124">#</a> </div> <p>Rewrite a chain of <strong>IfNodes</strong> with their switch condition for equality.
Ensure that the switch expression isn't evaluated more than once.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite_switch: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">assigner: </span><span class="nx">@switcher</span>
<span class="k">if</span> <span class="o">not</span> <span class="p">(</span><span class="nx">@switcher</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span> <span class="k">instanceof</span> <span class="nx">LiteralNode</span><span class="p">)</span>
<span class="nv">variable: </span><span class="nx">literal</span><span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">free_variable</span><span class="p">())</span>
<span class="nv">assigner: </span><span class="k">new</span> <span class="nx">AssignNode</span><span class="p">(</span><span class="nx">variable</span><span class="p">,</span> <span class="nx">@switcher</span><span class="p">)</span>
<span class="vi">@switcher: </span><span class="nx">variable</span>
<span class="vi">@condition: </span><span class="k">if</span> <span class="nx">@multiple</span>
<span class="k">for</span> <span class="nx">cond</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@condition</span>
<span class="k">new</span> <span class="nx">OpNode</span><span class="p">(</span><span class="s1">&#39;==&#39;</span><span class="p">,</span> <span class="p">(</span><span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="mi">0</span> <span class="k">then</span> <span class="nx">assigner</span> <span class="k">else</span> <span class="nx">@switcher</span><span class="p">),</span> <span class="nx">cond</span><span class="p">)</span>
<span class="k">else</span>
<span class="k">new</span> <span class="nx">OpNode</span><span class="p">(</span><span class="s1">&#39;==&#39;</span><span class="p">,</span> <span class="nx">assigner</span><span class="p">,</span> <span class="nx">@condition</span><span class="p">)</span>
<span class="nx">@else_body</span><span class="p">.</span><span class="nx">rewrite_condition</span><span class="p">(</span><span class="nx">@switcher</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@is_chain</span><span class="p">()</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-125"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-125">#</a> </div> <p>Rewrite a chain of <strong>IfNodes</strong> to add a default case as the final <em>else</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add_else: </span><span class="p">(</span><span class="nx">exprs</span><span class="p">,</span> <span class="nx">statement</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@is_chain</span><span class="p">()</span>
<span class="nx">@else_body</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">exprs</span><span class="p">,</span> <span class="nx">statement</span>
<span class="k">else</span>
<span class="nv">exprs: </span><span class="nx">exprs</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">statement</span>
<span class="nx">@children</span><span class="p">.</span><span class="nx">push</span> <span class="vi">@else_body: </span><span class="nx">exprs</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-126"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-126">#</a> </div> <p>If the <code>else_body</code> is an <strong>IfNode</strong> itself, then we've got an <em>if-else</em> chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">is_chain: </span><span class="o">-&gt;</span>
<span class="vi">@chain: </span><span class="o">or</span> <span class="nx">@else_body</span> <span class="o">and</span> <span class="nx">@else_body</span> <span class="k">instanceof</span> <span class="nx">IfNode</span></pre></div> </td> </tr> <tr id="section-127"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-127">#</a> </div> <p>The <strong>IfNode</strong> only compiles into a statement if either of its bodies needs
to be a statement. Otherwise a ternary is safe.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">is_statement: </span><span class="o">-&gt;</span>
<span class="vi">@statement: </span><span class="o">or</span> <span class="o">!!</span><span class="p">(</span><span class="nx">@comment</span> <span class="o">or</span> <span class="nx">@tags</span><span class="p">.</span><span class="nx">statement</span> <span class="o">or</span> <span class="nx">@body</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()</span> <span class="o">or</span> <span class="p">(</span><span class="nx">@else_body</span> <span class="o">and</span> <span class="nx">@else_body</span><span class="p">.</span><span class="nx">is_statement</span><span class="p">()))</span>
<span class="nv">compile_condition: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">cond</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">for</span> <span class="nx">cond</span> <span class="k">in</span> <span class="nx">flatten</span><span class="p">([</span><span class="nx">@condition</span><span class="p">])).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; || &#39;</span><span class="p">)</span>
<span class="nv">compile_node: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@is_statement</span><span class="p">()</span> <span class="k">then</span> <span class="nx">@compile_statement</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="nx">@compile_ternary</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">make_return: </span><span class="o">-&gt;</span>
<span class="vi">@body: </span> <span class="o">and</span> <span class="nx">@body</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span>
<span class="vi">@else_body: </span><span class="o">and</span> <span class="nx">@else_body</span><span class="p">.</span><span class="nx">make_return</span><span class="p">()</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-128"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-128">#</a> </div> <p>Compile the <strong>IfNode</strong> as a regular <em>if-else</em> statement. Flattened chains
force inner <em>else</em> bodies into statement form.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_statement: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@rewrite_switch</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@switcher</span>
<span class="nv">child: </span> <span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;chain_child&#39;</span>
<span class="nv">cond_o: </span> <span class="nx">merge</span> <span class="nx">o</span>
<span class="nv">o.indent: </span> <span class="nx">@idt</span> <span class="mi">1</span>
<span class="nv">o.top: </span> <span class="kc">true</span>
<span class="nv">if_dent: </span> <span class="k">if</span> <span class="nx">child</span> <span class="k">then</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="nx">@idt</span><span class="p">()</span>
<span class="nv">com_dent: </span> <span class="k">if</span> <span class="nx">child</span> <span class="k">then</span> <span class="nx">@idt</span><span class="p">()</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">prefix: </span> <span class="k">if</span> <span class="nx">@comment</span> <span class="k">then</span> <span class="s2">&quot;${ @comment.compile(cond_o) }\n$com_dent&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">body: </span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">@body</span><span class="p">]).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">if_part: </span> <span class="s2">&quot;$prefix${if_dent}if (${ @compile_condition(cond_o) }) {\n$body\n$@tab}&quot;</span>
<span class="k">return</span> <span class="nx">if_part</span> <span class="nx">unless</span> <span class="nx">@else_body</span>
<span class="nv">else_part: </span><span class="k">if</span> <span class="nx">@is_chain</span><span class="p">()</span>
<span class="s1">&#39; else &#39;</span> <span class="o">+</span> <span class="nx">@else_body</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="p">{</span><span class="nv">indent: </span><span class="nx">@idt</span><span class="p">(),</span> <span class="nv">chain_child: </span><span class="kc">true</span><span class="p">}))</span>
<span class="k">else</span>
<span class="s2">&quot; else {\n${ Expressions.wrap([@else_body]).compile(o) }\n$@tab}&quot;</span>
<span class="s2">&quot;$if_part$else_part&quot;</span></pre></div> </td> </tr> <tr id="section-129"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-129">#</a> </div> <p>Compile the IfNode as a ternary operator.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compile_ternary: </span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">if_part: </span> <span class="nx">@condition</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39; ? &#39;</span> <span class="o">+</span> <span class="nx">@body</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
<span class="nv">else_part: </span> <span class="k">if</span> <span class="nx">@else_body</span> <span class="k">then</span> <span class="nx">@else_body</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;null&#39;</span>
<span class="s2">&quot;$if_part : $else_part&quot;</span></pre></div> </td> </tr> <tr id="section-130"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-130">#</a> </div> <h2>Faux-Nodes</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-131"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-131">#</a> </div> <h3>PushNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-132"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-132">#</a> </div> <p>Faux-nodes are never created by the grammar, but are used during code
generation to generate other combinations of nodes. The <strong>PushNode</strong> creates
the tree for <code>array.push(value)</code>, which is helpful for recording the result
arrays from comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">PushNode: exports.PushNode: </span><span class="p">{</span>
<span class="nv">wrap: </span><span class="p">(</span><span class="nx">array</span><span class="p">,</span> <span class="nx">expressions</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">expr: </span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">expressions</span> <span class="k">if</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">is_pure_statement</span><span class="p">()</span> <span class="o">or</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">contains_pure_statement</span><span class="p">()</span>
<span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="k">new</span> <span class="nx">CallNode</span><span class="p">(</span>
<span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="nx">array</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">AccessorNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;push&#39;</span><span class="p">))]),</span> <span class="p">[</span><span class="nx">expr</span><span class="p">]</span>
<span class="p">)])</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-133"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-133">#</a> </div> <h3>ClosureNode</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-134"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-134">#</a> </div> <p>A faux-node used to wrap an expressions body in a closure.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ClosureNode: exports.ClosureNode: </span><span class="p">{</span></pre></div> </td> </tr> <tr id="section-135"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-135">#</a> </div> <p>Wrap the expressions body, unless it contains a pure statement,
in which case, no dice.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">wrap: </span><span class="p">(</span><span class="nx">expressions</span><span class="p">,</span> <span class="nx">statement</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="nx">expressions</span> <span class="k">if</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">contains_pure_statement</span><span class="p">()</span>
<span class="nv">func: </span><span class="k">new</span> <span class="nx">ParentheticalNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">CodeNode</span><span class="p">([],</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">expressions</span><span class="p">])))</span>
<span class="nv">call: </span><span class="k">new</span> <span class="nx">CallNode</span><span class="p">(</span><span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">func</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">AccessorNode</span><span class="p">(</span><span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;call&#39;</span><span class="p">))]),</span> <span class="p">[</span><span class="nx">literal</span><span class="p">(</span><span class="s1">&#39;this&#39;</span><span class="p">)])</span>
<span class="k">if</span> <span class="nx">statement</span> <span class="k">then</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">call</span><span class="p">])</span> <span class="k">else</span> <span class="nx">call</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-136"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-136">#</a> </div> <h2>Utility Functions</h2> </td> <td class="code"> <div class="highlight"><pre><span class="nv">UTILITIES: </span><span class="p">{</span></pre></div> </td> </tr> <tr id="section-137"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-137">#</a> </div> <p>Correctly set up a prototype chain for inheritance, including a reference
to the superclass for <code>super()</code> calls. See:
<a href="http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.source.html#line1206">goog.inherits</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">__extends: </span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> function(child, parent) {</span>
<span class="s2"> var ctor = function(){ };</span>
<span class="s2"> ctor.prototype = parent.prototype;</span>
<span class="s2"> child.__superClass__ = parent.prototype;</span>
<span class="s2"> child.prototype = new ctor();</span>
<span class="s2"> child.prototype.constructor = child;</span>
<span class="s2"> }</span>
<span class="s2"> &quot;&quot;&quot;</span></pre></div> </td> </tr> <tr id="section-138"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-138">#</a> </div> <p>Bind a function to a calling context, optionally including curried arguments.
See <a href="http://jashkenas.github.com/coffee-script/documentation/docs/underscore.html#section-47">Underscore's implementation</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">__bind: </span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> function(func, obj, args) {</span>
<span class="s2"> return function() {</span>
<span class="s2"> return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);</span>
<span class="s2"> };</span>
<span class="s2"> }</span>
<span class="s2"> &quot;&quot;&quot;</span></pre></div> </td> </tr> <tr id="section-139"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-139">#</a> </div> <p>Shortcuts to speed up the lookup time for native functions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">__hasProp: </span><span class="s1">&#39;Object.prototype.hasOwnProperty&#39;</span>
<span class="nv">__slice: </span><span class="s1">&#39;Array.prototype.slice&#39;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-140"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-140">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-141"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-141">#</a> </div> <p>Tabs are two spaces for pretty printing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">TAB: </span><span class="s1">&#39; &#39;</span></pre></div> </td> </tr> <tr id="section-142"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-142">#</a> </div> <p>Trim out all trailing whitespace, so that the generated code plays nice
with Git.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">TRAILING_WHITESPACE: </span><span class="sr">/\s+$/gm</span></pre></div> </td> </tr> <tr id="section-143"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-143">#</a> </div> <p>Keep this identifier regex in sync with the Lexer.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER: </span><span class="sr">/^[a-zA-Z\$_](\w|\$)*$/</span></pre></div> </td> </tr> <tr id="section-144"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-144">#</a> </div> <h2>Utility Functions</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-145"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-145">#</a> </div> <p>Handy helper for a generating LiteralNode.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">literal: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">new</span> <span class="nx">LiteralNode</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-146"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-146">#</a> </div> <p>Helper for ensuring that utility functions are assigned at the top level.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">utility: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">ref: </span><span class="s2">&quot;__$name&quot;</span>
<span class="nx">Scope</span><span class="p">.</span><span class="nx">root</span><span class="p">.</span><span class="nx">assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">UTILITIES</span><span class="p">[</span><span class="nx">ref</span><span class="p">]</span>
<span class="nx">ref</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,67 @@
<!DOCTYPE html> <html> <head> <title>optparse.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> optparse.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
Use it like so:</p>
<pre><code>parser: new OptionParser switches, help_banner
options: parser.parse process.argv
</code></pre> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.OptionParser: </span><span class="nx">class</span> <span class="nx">OptionParser</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Initialize with a list of valid options, in the form:</p>
<pre><code>[short-flag, long-flag, description]
</code></pre>
<p>Along with an an optional banner for the usage help.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">constructor: </span><span class="p">(</span><span class="nx">rules</span><span class="p">,</span> <span class="nx">banner</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@banner: </span> <span class="nx">banner</span>
<span class="vi">@rules: </span> <span class="nx">build_rules</span><span class="p">(</span><span class="nx">rules</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Parse the list of arguments, populating an <code>options</code> object with all of the
specified options, and returning it. <code>options.arguments</code> will be an array
containing the remaning non-option arguments. This is a simpler API than
many option parsers that allow you to attach callback actions for every
flag. Instead, you're responsible for interpreting the options object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">parse: </span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">options: </span><span class="p">{</span><span class="nv">arguments: </span><span class="p">[]}</span>
<span class="nv">args: </span><span class="nx">normalize_arguments</span> <span class="nx">args</span>
<span class="k">while</span> <span class="p">(</span><span class="nv">arg: </span><span class="nx">args</span><span class="p">.</span><span class="nx">shift</span><span class="p">())</span>
<span class="nv">is_option: </span><span class="o">!!</span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)</span> <span class="o">or</span> <span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SHORT_FLAG</span><span class="p">))</span>
<span class="nv">matched_rule: </span><span class="kc">no</span>
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
<span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">short_flag</span> <span class="o">is</span> <span class="nx">arg</span> <span class="o">or</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">long_flag</span> <span class="o">is</span> <span class="nx">arg</span>
<span class="nx">options</span><span class="p">[</span><span class="nx">rule</span><span class="p">.</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">has_argument</span> <span class="k">then</span> <span class="nx">args</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span> <span class="k">else</span> <span class="kc">true</span>
<span class="nv">matched_rule: </span><span class="kc">yes</span>
<span class="k">break</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;unrecognized option: $arg&quot;</span> <span class="k">if</span> <span class="nx">is_option</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">matched_rule</span>
<span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span><span class="p">.</span><span class="nx">push</span> <span class="nx">arg</span> <span class="nx">unless</span> <span class="nx">is_option</span>
<span class="nx">options</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
of the valid options, for <code>--help</code> and such.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">help: </span><span class="o">-&gt;</span>
<span class="nv">lines: </span><span class="p">[</span><span class="s1">&#39;Available options:&#39;</span><span class="p">]</span>
<span class="nx">lines</span><span class="p">.</span><span class="nx">unshift</span> <span class="s2">&quot;$@banner\n&quot;</span> <span class="k">if</span> <span class="nx">@banner</span>
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
<span class="nv">spaces: </span> <span class="mi">15</span> <span class="o">-</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">long_flag</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">spaces: </span> <span class="k">if</span> <span class="nx">spaces</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">then</span> <span class="p">(</span><span class="s1">&#39; &#39;</span> <span class="k">for</span> <span class="nx">i</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">..</span><span class="nx">spaces</span><span class="p">]).</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">let_part: </span><span class="k">if</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">short_flag</span> <span class="k">then</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">short_flag</span> <span class="o">+</span> <span class="s1">&#39;, &#39;</span> <span class="k">else</span> <span class="s1">&#39; &#39;</span>
<span class="nx">lines</span><span class="p">.</span><span class="nx">push</span> <span class="s2">&quot; $let_part${rule.long_flag}$spaces${rule.description}&quot;</span>
<span class="s2">&quot;\n${ lines.join(&#39;\n&#39;) }\n&quot;</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <h2>Helpers</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Regex matchers for option flags.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LONG_FLAG: </span> <span class="sr">/^(--\w[\w\-]+)/</span>
<span class="nv">SHORT_FLAG: </span><span class="sr">/^(-\w)/</span>
<span class="nv">MULTI_FLAG: </span><span class="sr">/^-(\w{2,})/</span>
<span class="nv">OPTIONAL: </span> <span class="sr">/\[(.+)\]/</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Build and return the list of option rules. If the optional <em>short-flag</em> is
unspecified, leave it out by padding with <code>null</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">build_rules: </span><span class="p">(</span><span class="nx">rules</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">tuple</span> <span class="k">in</span> <span class="nx">rules</span>
<span class="nx">tuple</span><span class="p">.</span><span class="nx">unshift</span> <span class="kc">null</span> <span class="k">if</span> <span class="nx">tuple</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="mi">3</span>
<span class="nx">build_rule</span> <span class="nx">tuple</span><span class="p">...</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
description of what the option does.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">build_rule: </span><span class="p">(</span><span class="nx">short_flag</span><span class="p">,</span> <span class="nx">long_flag</span><span class="p">,</span> <span class="nx">description</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">match: </span> <span class="nx">long_flag</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">OPTIONAL</span><span class="p">)</span>
<span class="nv">long_flag: </span> <span class="nx">long_flag</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
<span class="p">{</span>
<span class="nv">name: </span> <span class="nx">long_flag</span><span class="p">.</span><span class="nx">substr</span> <span class="mi">2</span>
<span class="nv">short_flag: </span> <span class="nx">short_flag</span>
<span class="nv">long_flag: </span> <span class="nx">long_flag</span>
<span class="nv">description: </span> <span class="nx">description</span>
<span class="nv">has_argument: </span><span class="o">!!</span><span class="p">(</span><span class="nx">match</span> <span class="o">and</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Normalize arguments by expanding merged flags into multiple flags. This allows
you to have <code>-wl</code> be the same as <code>--watch --lint</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">normalize_arguments: </span><span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">args: </span><span class="nx">args</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span>
<span class="nv">result: </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">args</span>
<span class="k">if</span> <span class="nv">match: </span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span> <span class="nx">MULTI_FLAG</span>
<span class="nx">result</span><span class="p">.</span><span class="nx">push</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="nx">l</span> <span class="k">for</span> <span class="nx">l</span> <span class="k">in</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">split</span> <span class="s1">&#39;&#39;</span>
<span class="k">else</span>
<span class="nx">result</span><span class="p">.</span><span class="nx">push</span> <span class="nx">arg</span>
<span class="nx">result</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html> <html> <head> <title>repl.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> repl.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
and evaluates it. Good for simple tests, or poking around the <strong>Node.js</strong> API.
Using it looks like this:</p>
<pre><code>coffee&gt; puts "$num bottles of beer" for num in [99..1]
</code></pre> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Require the <strong>coffee-script</strong> module to get access to the compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript: </span><span class="nx">require</span> <span class="s1">&#39;./coffee-script&#39;</span>
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./helpers&#39;</span><span class="p">).</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Our prompt.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">prompt: </span><span class="s1">&#39;coffee&gt; &#39;</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="p">{</span>
<span class="nv">quit: </span><span class="o">-&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
Attempt to evaluate the command. If there's an exception, print it out instead
of exiting.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">run: </span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">try</span>
<span class="nv">val: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">code</span><span class="p">,</span> <span class="p">{</span><span class="nv">no_wrap: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">globals: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">source: </span><span class="s1">&#39;repl&#39;</span><span class="p">}</span>
<span class="nx">p</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
<span class="k">catch</span> <span class="nx">err</span>
<span class="nx">puts</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
<span class="nx">print</span> <span class="nx">prompt</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Start up the REPL by opening <strong>stdio</strong> and listening for input.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">run</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdio</span><span class="p">.</span><span class="nx">open</span><span class="p">()</span>
<span class="nx">print</span> <span class="nx">prompt</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,214 @@
<!DOCTYPE html> <html> <head> <title>rewriter.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> rewriter.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript language has a good deal of optional syntax, implicit syntax,
and shorthand syntax. This can greatly complicate a grammar and bloat
the resulting parse table. Instead of making the parser handle it all, we take
a series of passes over the token stream, using this <strong>Rewriter</strong> to convert
shorthand into the unambiguous long form, add implicit indentation and
parentheses, balance incorrect nestings, and generally clean things up.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both Node.js and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
<span class="nv">helpers: </span><span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./helpers&#39;</span><span class="p">).</span><span class="nx">helpers</span>
<span class="k">else</span>
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">include: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">include</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
its internal array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Rewriter: </span><span class="nx">class</span> <span class="nx">Rewriter</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Rewrite the token stream in multiple passes, one logical filter at
a time. This could certainly be changed into a single pass through the
stream, with a big ol' efficient switch, but it's much nicer to work with
like this. The order of these passes matters -- indentation must be
corrected before implicit parentheses can be wrapped around blocks of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite: </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@tokens: </span><span class="nx">tokens</span>
<span class="nx">@adjust_comments</span><span class="p">()</span>
<span class="nx">@remove_leading_newlines</span><span class="p">()</span>
<span class="nx">@remove_mid_expression_newlines</span><span class="p">()</span>
<span class="nx">@close_open_calls_and_indexes</span><span class="p">()</span>
<span class="nx">@add_implicit_indentation</span><span class="p">()</span>
<span class="nx">@add_implicit_parentheses</span><span class="p">()</span>
<span class="nx">@ensure_balance</span> <span class="nx">BALANCED_PAIRS</span>
<span class="nx">@rewrite_closing_parens</span><span class="p">()</span>
<span class="nx">@tokens</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Rewrite the token stream, looking one token ahead and behind.
Allow the return value of the block to tell us how many tokens to move
forwards (or backwards) in the stream, to make sure we don't miss anything
as tokens are inserted and removed, and the stream changes length under
our feet.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">scan_tokens: </span><span class="p">(</span><span class="nx">block</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">i: </span><span class="mi">0</span>
<span class="k">while</span> <span class="kc">true</span>
<span class="k">break</span> <span class="nx">unless</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
<span class="nv">move: </span><span class="nx">block</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">],</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">],</span> <span class="nx">i</span>
<span class="nv">i: </span><span class="o">+</span> <span class="nx">move</span>
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Massage newlines and indentations so that comments don't have to be
correctly indented, or appear on a line of their own.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">adjust_comments: </span><span class="o">-&gt;</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;COMMENT&#39;</span>
<span class="nv">after: </span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">after</span> <span class="o">and</span> <span class="nx">after</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;INDENT&#39;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">after</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;TERMINATOR&#39;</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;INDENT&#39;</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;OUTDENT&#39;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s2">&quot;\n&quot;</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="k">return</span> <span class="mi">2</span>
<span class="k">else</span>
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Leading newlines would introduce an ambiguity in the grammar, so we
dispatch them here.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">remove_leading_newlines: </span><span class="o">-&gt;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span> <span class="k">while</span> <span class="nx">@tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">and</span> <span class="nx">@tokens</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;TERMINATOR&#39;</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Some blocks occur in the middle of expressions -- when we're expecting
this, remove their trailing newlines.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">remove_mid_expression_newlines: </span><span class="o">-&gt;</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">post</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">EXPRESSION_CLOSE</span><span class="p">,</span> <span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;TERMINATOR&#39;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">1</span>
<span class="k">return</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>The lexer has tagged the opening parenthesis of a method call, and the
opening bracket of an indexing operation. Match them with their paired
close.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">close_open_calls_and_indexes: </span><span class="o">-&gt;</span>
<span class="nv">parens: </span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">brackets: </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="k">switch</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">when</span> <span class="s1">&#39;CALL_START&#39;</span> <span class="k">then</span> <span class="nx">parens</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
<span class="k">when</span> <span class="s1">&#39;INDEX_START&#39;</span> <span class="k">then</span> <span class="nx">brackets</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
<span class="k">when</span> <span class="s1">&#39;(&#39;</span> <span class="k">then</span> <span class="nx">parens</span><span class="p">[</span><span class="nx">parens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;[&#39;</span> <span class="k">then</span> <span class="nx">brackets</span><span class="p">[</span><span class="nx">brackets</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;)&#39;</span>
<span class="k">if</span> <span class="nx">parens</span><span class="p">[</span><span class="nx">parens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="mi">0</span>
<span class="nx">parens</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;CALL_END&#39;</span>
<span class="k">else</span>
<span class="nx">parens</span><span class="p">[</span><span class="nx">parens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;]&#39;</span>
<span class="k">if</span> <span class="nx">brackets</span><span class="p">[</span><span class="nx">brackets</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
<span class="nx">brackets</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;INDEX_END&#39;</span>
<span class="k">else</span>
<span class="nx">brackets</span><span class="p">[</span><span class="nx">brackets</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">-</span> <span class="mi">1</span>
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Methods may be optionally called without parentheses, for simple cases.
Insert the implicit parentheses here, so that the parser doesn't have to
deal with them.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add_implicit_parentheses: </span><span class="o">-&gt;</span>
<span class="nv">stack: </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">calls: </span> <span class="mi">0</span>
<span class="nv">parens: </span><span class="mi">0</span>
<span class="nv">start_parens: </span><span class="mi">0</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="nv">tag: </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">switch</span> <span class="nx">tag</span>
<span class="k">when</span> <span class="s1">&#39;CALL_START&#39;</span> <span class="k">then</span> <span class="nv">calls: </span><span class="o">+</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;CALL_END&#39;</span> <span class="k">then</span> <span class="nv">calls: </span><span class="o">-</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;(&#39;</span> <span class="k">then</span> <span class="nv">parens: </span><span class="o">+</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;)&#39;</span> <span class="k">then</span> <span class="nv">parens: </span><span class="o">-</span> <span class="mi">1</span>
<span class="k">when</span> <span class="s1">&#39;INDENT&#39;</span> <span class="k">then</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
<span class="k">when</span> <span class="s1">&#39;OUTDENT&#39;</span>
<span class="nv">last: </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">last</span>
<span class="nv">open: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="k">if</span> <span class="o">!</span><span class="nx">post</span><span class="o">?</span> <span class="o">or</span> <span class="p">(</span><span class="nx">start_parens</span> <span class="o">&gt;</span> <span class="nx">parens</span><span class="p">)</span> <span class="o">or</span> <span class="p">(</span><span class="nx">parens</span> <span class="o">is</span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;INDENT&#39;</span> <span class="o">and</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">IMPLICIT_BLOCK</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;OUTDENT&#39;</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">generated</span>
<span class="k">if</span> <span class="nx">open</span> <span class="o">or</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;INDENT&#39;</span>
<span class="nv">idx: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;OUTDENT&#39;</span> <span class="k">then</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">i</span>
<span class="nv">stack_pointer: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;INDENT&#39;</span> <span class="k">then</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">1</span>
<span class="k">for</span> <span class="nx">tmp</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]]</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">idx</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;CALL_END&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]])</span>
<span class="nv">size: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]</span><span class="o">:</span> <span class="mi">0</span>
<span class="k">return</span> <span class="nx">size</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_FUNC</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_CALL</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
<span class="nv">calls: </span><span class="mi">0</span>
<span class="nv">start_parens: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;(&#39;</span> <span class="k">then</span> <span class="nx">parens</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">parens</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;CALL_START&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">return</span> <span class="mi">2</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Because our grammar is LALR(1), it can't handle some single-line
expressions that lack ending delimiters. The <strong>Rewriter</strong> adds the implicit
blocks, so it doesn't need to. ')' can close a single-line block,
but we need to make sure it's balanced.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add_implicit_indentation: </span><span class="o">-&gt;</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">include</span><span class="p">(</span><span class="nx">SINGLE_LINERS</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span>
<span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;INDENT&#39;</span> <span class="o">and</span>
<span class="o">not</span> <span class="p">(</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;ELSE&#39;</span> <span class="o">and</span> <span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;IF&#39;</span><span class="p">)</span>
<span class="nv">starter: </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="nv">idx: </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nv">parens: </span><span class="mi">0</span>
<span class="k">while</span> <span class="kc">true</span>
<span class="nv">idx: </span><span class="o">+</span> <span class="mi">1</span>
<span class="nv">tok: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">idx</span><span class="p">]</span>
<span class="nv">pre: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">idx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="p">(</span><span class="o">not</span> <span class="nx">tok</span> <span class="o">or</span>
<span class="p">(</span><span class="nx">include</span><span class="p">(</span><span class="nx">SINGLE_CLOSERS</span><span class="p">,</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;;&#39;</span><span class="p">)</span> <span class="o">or</span>
<span class="p">(</span><span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;)&#39;</span> <span class="o">and</span> <span class="nx">parens</span> <span class="o">is</span> <span class="mi">0</span><span class="p">))</span> <span class="o">and</span>
<span class="o">not</span> <span class="p">(</span><span class="nx">starter</span> <span class="o">is</span> <span class="s1">&#39;ELSE&#39;</span> <span class="o">and</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">)</span>
<span class="nv">insertion: </span><span class="k">if</span> <span class="nx">pre</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s2">&quot;,&quot;</span> <span class="k">then</span> <span class="nx">idx</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">idx</span>
<span class="nv">outdent: </span><span class="p">[</span><span class="s1">&#39;OUTDENT&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="nv">outdent.generated: </span><span class="kc">true</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">insertion</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">outdent</span>
<span class="k">break</span>
<span class="nv">parens: </span><span class="o">+</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;(&#39;</span>
<span class="nv">parens: </span><span class="o">-</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;)&#39;</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;THEN&#39;</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">1</span>
<span class="k">return</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Ensure that all listed pairs of tokens are correctly balanced throughout
the course of the token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ensure_balance: </span><span class="p">(</span><span class="nx">pairs</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">levels: </span><span class="p">{}</span>
<span class="nv">open_line: </span><span class="p">{}</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">pairs</span>
<span class="p">[</span><span class="nx">open</span><span class="p">,</span> <span class="nx">close</span><span class="p">]</span><span class="o">:</span> <span class="nx">pair</span>
<span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span><span class="o">:</span> <span class="o">or</span> <span class="mi">0</span>
<span class="k">if</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="nx">open</span>
<span class="nx">open_line</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span><span class="o">:</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
<span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span><span class="o">:</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="nx">close</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&quot;too many ${token[1]} on line ${token[2] + 1}&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="nv">unclosed: </span><span class="nx">key</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span> <span class="k">of</span> <span class="nx">levels</span> <span class="k">when</span> <span class="nx">value</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="k">if</span> <span class="nx">unclosed</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">open: </span><span class="nx">unclosed</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">line: </span><span class="nx">open_line</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;unclosed $open on line $line&quot;</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>We'd like to support syntax like this:</p>
<pre><code>el.click((event) -&gt;
el.hide())
</code></pre>
<p>In order to accomplish this, move outdents that follow closing parens
inwards, safely. The steps to accomplish this are:</p>
<ol>
<li>Check that all paired tokens are balanced and in order.</li>
<li>Rewrite the stream with a stack: if you see an <code>EXPRESSION_START</code>, add it
to the stack. If you see an <code>EXPRESSION_END</code>, pop the stack and replace
it with the inverse of what we've just popped.</li>
<li>Keep track of "debt" for tokens that we manufacture, to make sure we end
up balanced in the end.</li>
</ol> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite_closing_parens: </span><span class="o">-&gt;</span>
<span class="nv">stack: </span><span class="p">[]</span>
<span class="nv">debt: </span> <span class="p">{}</span>
<span class="p">(</span><span class="nx">debt</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">INVERSES</span>
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="nv">tag: </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">inv: </span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span>
<span class="k">if</span> <span class="nx">include</span> <span class="nx">EXPRESSION_START</span><span class="p">,</span> <span class="nx">tag</span>
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">EXPRESSION_END</span><span class="p">,</span> <span class="nx">tag</span>
<span class="k">if</span> <span class="nx">debt</span><span class="p">[</span><span class="nx">inv</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="nx">debt</span><span class="p">[</span><span class="nx">inv</span><span class="p">]</span><span class="o">:</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">1</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="k">else</span>
<span class="nv">match: </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nv">mtag: </span> <span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
<span class="nx">debt</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nv">val: </span><span class="k">if</span> <span class="nx">mtag</span> <span class="o">is</span> <span class="s1">&#39;INDENT&#39;</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">],</span> <span class="nx">val</span><span class="p">]</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span>
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>List of the token pairs that must be balanced.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BALANCED_PAIRS: </span><span class="p">[[</span><span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;}&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">],</span>
<span class="p">[</span><span class="s1">&#39;PARAM_START&#39;</span><span class="p">,</span> <span class="s1">&#39;PARAM_END&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;CALL_START&#39;</span><span class="p">,</span> <span class="s1">&#39;CALL_END&#39;</span><span class="p">],</span>
<span class="p">[</span><span class="s1">&#39;INDEX_START&#39;</span><span class="p">,</span> <span class="s1">&#39;INDEX_END&#39;</span><span class="p">],</span> <span class="p">[</span><span class="s1">&#39;SOAKED_INDEX_START&#39;</span><span class="p">,</span> <span class="s1">&#39;SOAKED_INDEX_END&#39;</span><span class="p">]]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>The inverse mappings of <code>BALANCED_PAIRS</code> we're trying to fix up, so we can
look things up from either end.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">INVERSES: </span><span class="p">{}</span>
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span>
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>The tokens that signal the start of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START: </span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>The tokens that signal the end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_END: </span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Tokens that indicate the close of a clause of an expression.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_CLOSE: </span><span class="p">[</span><span class="s1">&#39;CATCH&#39;</span><span class="p">,</span> <span class="s1">&#39;WHEN&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;FINALLY&#39;</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_FUNC: </span> <span class="p">[</span><span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;SUPER&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;CALL_END&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="s1">&#39;INDEX_END&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;-&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_CALL: </span> <span class="p">[</span><span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;NUMBER&#39;</span><span class="p">,</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s1">&#39;JS&#39;</span><span class="p">,</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="s1">&#39;NEW&#39;</span><span class="p">,</span> <span class="s1">&#39;PARAM_START&#39;</span><span class="p">,</span>
<span class="s1">&#39;TRY&#39;</span><span class="p">,</span> <span class="s1">&#39;DELETE&#39;</span><span class="p">,</span> <span class="s1">&#39;TYPEOF&#39;</span><span class="p">,</span> <span class="s1">&#39;SWITCH&#39;</span><span class="p">,</span> <span class="s1">&#39;EXTENSION&#39;</span><span class="p">,</span>
<span class="s1">&#39;TRUE&#39;</span><span class="p">,</span> <span class="s1">&#39;FALSE&#39;</span><span class="p">,</span> <span class="s1">&#39;YES&#39;</span><span class="p">,</span> <span class="s1">&#39;NO&#39;</span><span class="p">,</span> <span class="s1">&#39;ON&#39;</span><span class="p">,</span> <span class="s1">&#39;OFF&#39;</span><span class="p">,</span> <span class="s1">&#39;!&#39;</span><span class="p">,</span> <span class="s1">&#39;!!&#39;</span><span class="p">,</span> <span class="s1">&#39;NOT&#39;</span><span class="p">,</span>
<span class="s1">&#39;THIS&#39;</span><span class="p">,</span> <span class="s1">&#39;NULL&#39;</span><span class="p">,</span>
<span class="s1">&#39;@&#39;</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="s1">&#39;{&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK: </span><span class="p">[</span><span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;,&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END: </span> <span class="p">[</span><span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#39;</span><span class="p">,</span> <span class="s1">&#39;FOR&#39;</span><span class="p">,</span> <span class="s1">&#39;WHILE&#39;</span><span class="p">,</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
The grammar can't disambiguate them, so we insert the implicit indentation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SINGLE_LINERS: </span><span class="p">[</span><span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s2">&quot;-&gt;&quot;</span><span class="p">,</span> <span class="s2">&quot;=&gt;&quot;</span><span class="p">,</span> <span class="s1">&#39;TRY&#39;</span><span class="p">,</span> <span class="s1">&#39;FINALLY&#39;</span><span class="p">,</span> <span class="s1">&#39;THEN&#39;</span><span class="p">]</span>
<span class="nv">SINGLE_CLOSERS: </span><span class="p">[</span><span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;CATCH&#39;</span><span class="p">,</span> <span class="s1">&#39;FINALLY&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;LEADING_WHEN&#39;</span><span class="p">]</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@@ -0,0 +1,48 @@
<!DOCTYPE html> <html> <head> <title>scope.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To &hellip; <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> scope.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <strong>Scope</strong> class regulates lexical scoping within CoffeeScript. As you
generate code, you create a tree of scopes in the same shape as the nested
function bodies. Each scope knows about the variables declared within it,
and has a reference to its parent enclosing scope. In this way, we know which
variables are new and need to be declared with <code>var</code>, and which are shared
with the outside.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both <strong>Node.js</strong> and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">process</span><span class="o">?</span>
<span class="nv">exports.Scope: </span><span class="nx">class</span> <span class="nx">Scope</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The top-level <strong>Scope</strong> object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="vi">@root: </span><span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Initialize a scope with its parent, for lookups up the chain,
as well as a reference to the <strong>Expressions</strong> node is belongs to, which is
where it should declare its variables, and a reference to the function that
it wraps.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">constructor: </span><span class="p">(</span><span class="nx">parent</span><span class="p">,</span> <span class="nx">expressions</span><span class="p">,</span> <span class="nx">method</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">[</span><span class="nx">@parent</span><span class="p">,</span> <span class="nx">@expressions</span><span class="p">,</span> <span class="nx">@method</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">parent</span><span class="p">,</span> <span class="nx">expressions</span><span class="p">,</span> <span class="nx">method</span><span class="p">]</span>
<span class="vi">@variables: </span><span class="p">{}</span>
<span class="k">if</span> <span class="nx">@parent</span>
<span class="vi">@temp_var: </span><span class="nx">@parent</span><span class="p">.</span><span class="nx">temp_var</span>
<span class="k">else</span>
<span class="nv">Scope.root: </span><span class="k">this</span>
<span class="vi">@temp_var: </span><span class="s1">&#39;_a&#39;</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Look up a variable name in lexical scope, and declare it if it does not
already exist.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">find: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@check</span> <span class="nx">name</span>
<span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;var&#39;</span>
<span class="kc">false</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Test variables and return true the first time fn(v, k) returns true</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">any: </span><span class="p">(</span><span class="nx">fn</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">v</span><span class="p">,</span> <span class="nx">k</span> <span class="k">of</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">fn</span><span class="p">(</span><span class="nx">v</span><span class="p">,</span> <span class="nx">k</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">true</span>
<span class="k">return</span> <span class="kc">false</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Reserve a variable name as originating from a function parameter for this
scope. No <code>var</code> required for internal references.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">parameter: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;param&#39;</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Just check to see if a variable has already been declared, without reserving.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">check: </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span>
<span class="o">!!</span><span class="p">(</span><span class="nx">@parent</span> <span class="o">and</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">check</span><span class="p">(</span><span class="nx">name</span><span class="p">))</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>If we need to store an intermediate result, find an available name for a
compiler-generated variable. <code>_a</code>, <code>_b</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">free_variable: </span><span class="o">-&gt;</span>
<span class="k">while</span> <span class="nx">@check</span> <span class="nx">@temp_var</span>
<span class="nv">ordinal: </span><span class="mi">1</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">@temp_var</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="mi">36</span>
<span class="vi">@temp_var: </span><span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="nx">ordinal</span><span class="p">.</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">&#39;a&#39;</span><span class="p">)</span>
<span class="nx">@variables</span><span class="p">[</span><span class="nx">@temp_var</span><span class="p">]</span><span class="o">:</span> <span class="s1">&#39;var&#39;</span>
<span class="nx">@temp_var</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Ensure that an assignment is made at the top of this scope
(or at the top-level scope, if requested).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assign: </span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@variables</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="p">{</span><span class="nv">value: </span><span class="nx">value</span><span class="p">,</span> <span class="nv">assigned: </span><span class="kc">true</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Does this scope reference any variables that need to be declared in the
given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">has_declarations: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">k</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">val</span> <span class="o">is</span> <span class="s1">&#39;var&#39;</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Does this scope reference any assignments that need to be declared at the
top of the given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">has_assignments: </span><span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">k</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">val</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-13">#</a> </div> <p>Return the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">declared_variables: </span><span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">key</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">val</span> <span class="o">is</span> <span class="s1">&#39;var&#39;</span><span class="p">).</span><span class="nx">sort</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Return the list of assignments that are supposed to be made at the top
of this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">assigned_variables: </span><span class="o">-&gt;</span>
<span class="s2">&quot;$key = ${val.value}&quot;</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">val</span><span class="p">.</span><span class="nx">assigned</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Compile the JavaScript for all of the variable declarations in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compiled_declarations: </span><span class="o">-&gt;</span>
<span class="nx">@declared_variables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Compile the JavaScript for all of the variable assignments in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">compiled_assignments: </span><span class="o">-&gt;</span>
<span class="nx">@assigned_variables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -22,14 +22,15 @@
<title>CoffeeScript</title>
<link rel="stylesheet" type="text/css" href="documentation/css/docs.css" />
<link rel="stylesheet" type="text/css" href="documentation/css/idle.css" />
<link rel="shortcut icon" href="documentation/images/favicon.ico" />
</head>
<body>
<body class="minimized">
<div id="fadeout"></div>
<div id="flybar">
<a id="logo" href="#top"> </a>
<div class="navigation">
<div class="navigation toc">
<div class="button">
Table of Contents
</div>
@@ -45,19 +46,19 @@
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a>
<a href="#aliases">Aliases</a>
<a href="#splats">Splats...</a>
<a href="#arguments">Arguments are Arrays</a>
<a href="#while">While Loops</a>
<a href="#comprehensions">Comprehensions (Arrays, Objects, and Ranges)</a>
<a href="#slice_splice">Array Slicing and Splicing with Ranges</a>
<a href="#expressions">Everything is an Expression</a>
<a href="#existence">The Existential Operator</a>
<a href="#inheritance">Inheritance, and Calling Super from a Subclass</a>
<a href="#classes">Classes, Inheritance, and Super</a>
<a href="#pattern_matching">Pattern Matching</a>
<a href="#fat_arrow">Function Binding</a>
<a href="#embedded">Embedded JavaScript</a>
<a href="#switch">Switch/When/Else</a>
<a href="#try">Try/Catch/Finally</a>
<a href="#comparisons">Chained Comparisons</a>
<a href="#interpolation">String and RegExp Interpolation</a>
<a href="#strings">Multiline Strings and Heredocs</a>
<a href="#cake">Cake, and Cakefiles</a>
<a href="#scripts">"text/coffeescript" Script Tags</a>
@@ -71,17 +72,37 @@
</div>
<div class="contents repl_wrapper">
<div class="code">
<textarea id="repl_source">reverse: (string) ->
<div id="repl_source_wrap"><textarea id="repl_source">reverse: (string) ->
string.split('').reverse().join ''
alert reverse '!tpircseeffoC'</textarea>
alert reverse '.eeffoC yrT'</textarea></div>
<pre id="repl_results"></pre>
<button class="compile" onclick="javascript: repl_compile();">compile</button>
<button class="run" onclick="javascript: repl_run();">run</button>
<button class="full_screen">go full screen</button>
<button class="minimize">minimize</button>
<button class="run">run</button>
<br class="clear" />
</div>
</div>
</div>
<div class="navigation annotated">
<div class="button">
Annotated Source
</div>
<div class="contents">
<a href="documentation/docs/grammar.html">Grammar Rules &mdash; src/grammar</a>
<a href="documentation/docs/lexer.html">Lexing Tokens &mdash; src/lexer</a>
<a href="documentation/docs/rewriter.html">The Rewriter &mdash; src/rewriter</a>
<a href="documentation/docs/nodes.html">The Syntax Tree &mdash; src/nodes</a>
<a href="documentation/docs/scope.html">Lexical Scope &mdash; src/scope</a>
<a href="documentation/docs/helpers.html">Helpers &amp; Utility Functions &mdash; src/helpers</a>
<a href="documentation/docs/coffee-script.html">The CoffeeScript Module &mdash; src/coffee-script</a>
<a href="documentation/docs/cake.html">Cake &amp; Cakefiles &mdash; src/cake</a>
<a href="documentation/docs/command.html">"coffee" Command-Line Utility &mdash; src/command</a>
<a href="documentation/docs/optparse.html">Option Parsing &mdash; src/optparse</a>
<a href="documentation/docs/repl.html">Interactive REPL &mdash; src/repl</a>
</div>
</div>
<div id="error" style="display:none;"></div>
</div>
<div class="container">
@@ -108,7 +129,7 @@ alert reverse '!tpircseeffoC'</textarea>
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffee-script/tarball/0.5.2">0.5.2</a>
<a href="http://github.com/jashkenas/coffee-script/tarball/0.6.0">0.6.0</a>
</p>
<h2>
@@ -122,7 +143,7 @@ alert reverse '!tpircseeffoC'</textarea>
<p>
For a longer CoffeeScript example, check out
<a href="documentation/underscore.html">Underscore.coffee</a>, a port
<a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
library of helper functions. Underscore.coffee can pass the entire Underscore.js
test suite. The CoffeeScript version is faster than the original for a number
@@ -140,7 +161,7 @@ alert reverse '!tpircseeffoC'</textarea>
<p>
The CoffeeScript compiler is written in pure CoffeeScript, using a
<a href="http://github.com/jashkenas/coffee-script/blob/master/src/grammar.coffee">small DSL</a>
<a href="documentation/docs/grammar.html">small DSL</a>
on top of the <a href="http://github.com/zaach/jison">Jison parser generator</a>, and is available
as a <a href="http://nodejs.org/">Node.js</a> utility. The core compiler however,
does not depend on Node, and can be run in other server-side-JavaScript environments,
@@ -149,11 +170,12 @@ alert reverse '!tpircseeffoC'</textarea>
</p>
<p>
To install, first make sure you have a working version of
<a href="http://nodejs.org/">Node.js</a>, 0.1.30 or higher. Then clone the CoffeeScript
To install, first make sure you have a working copy of the latest tagged version of
<a href="http://nodejs.org/">Node.js</a>, currently <b>0.1.33</b> or higher.
Then clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download the latest
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.5.2">0.5.2</a>.
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.6.0">0.6.0</a>.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
@@ -162,10 +184,9 @@ alert reverse '!tpircseeffoC'</textarea>
sudo bin/cake install</pre>
<p>
This provides the <tt>coffee</tt> command, which can
be used to compile CoffeeScript <tt>.coffee</tt> files into JavaScript, as
well as debug them. The <tt>coffee</tt>
command also provides direct evaluation and an interactive REPL.
This provides the <tt>coffee</tt> command, which will execute CoffeeScripts
under Node.js by default, but is also used to compile CoffeeScript
<tt>.coffee</tt> files into JavaScript, or to run an an interactive REPL.
When compiling to JavaScript, <tt>coffee</tt> writes the output
as <tt>.js</tt> files in the same directory by default, but output
can be customized with the following options:
@@ -173,22 +194,25 @@ sudo bin/cake install</pre>
<table>
<tr>
<td width="25%"><code>-i, --interactive</code></td>
<td><code>-c, --compile</code></td>
<td>
Launch an interactive CoffeeScript session to try short snippets.
Compile a <tt>.coffee</tt> script into a <tt>.js</tt> JavaScript file
of the same name.
</td>
</tr>
<tr>
<td><code>-r, --run</code></td>
<td width="25%"><code>-i, --interactive</code></td>
<td>
Compile and execute a given CoffeeScript without saving the intermediate
JavaScript.
Launch an interactive CoffeeScript session to try short snippets.
More pleasant if wrapped with
<a href="http://utopia.knoware.nl/~hlub/uck/rlwrap/rlwrap.html">rlwrap</a>.
</td>
</tr>
<tr>
<td><code>-o, --output [DIR]</code></td>
<td>
Write out all compiled JavaScript files into the specified directory.
Use in conjunction with <tt>--compile</tt> or <tt>--watch</tt>.
</td>
</tr>
<tr>
@@ -220,18 +244,18 @@ sudo bin/cake install</pre>
<td>
Pipe in CoffeeScript to STDIN and get back JavaScript over STDOUT.
Good for use with processes written in other languages. An example:<br />
<tt>cat src/cake.coffee | coffee -s</tt>
<tt>cat src/cake.coffee | coffee -sc</tt>
</td>
</tr>
<tr>
<td><code>-e, --eval</code></td>
<td>
Compile and print a little snippet of CoffeeScript directly from the
command line. For example:<br /><tt>coffee -e "square: (x) -> x * x"</tt>
command line. For example:<br /><tt>coffee -e "puts num for num in [10..1]"</tt>
</td>
</tr>
<tr>
<td><code>-n, --no-wrap</code></td>
<td><code>--no-wrap</code></td>
<td>
Compile the JavaScript without the top-level function safety wrapper.
(Used for CoffeeScript as a Node.js module.)
@@ -245,7 +269,7 @@ sudo bin/cake install</pre>
</td>
</tr>
<tr>
<td><code>-tr, --tree</code></td>
<td><code>-n, --nodes</code></td>
<td>
Instead of compiling the CoffeeScript, just lex and parse it, and print
out the parse tree:
@@ -266,7 +290,7 @@ Expressions
</p>
<pre>
coffee path/to/script.coffee
coffee -c path/to/script.coffee
coffee --interactive
coffee --watch --lint experimental.coffee
coffee --print app/scripts/*.coffee > concatenation.js</pre>
@@ -371,6 +395,13 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
should not be able to change the value of the external variable of the same name, and
therefore has a declaration of its own.
</p>
<p>
This behavior is effectively identical to Ruby's scope for local variables.
Because you don't have direct access to the <tt>var</tt> keyword,
it's impossible to shadow an outer variable on purpose, you may only refer
to it. So be careful that you're not reusing the name of an external
variable accidentally, if you're writing a deeply nested function.
</p>
<p>
Although suppressed within this documentation for clarity, all
CoffeeScript output is wrapped in an anonymous function:
@@ -400,10 +431,9 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('conditionals') %>
<p>
The conditional assignment operators are included: <tt>||=</tt>,
which only assigns a value to a variable if the variable's current value
is falsy, and <tt>&amp;&amp;=</tt>, which only replaces the value of
truthy variables.
You can assign a variable to a half-expression to perform an operation
like Ruby's <tt>||=</tt>, which only assigns a value to a variable
if the variable's current value is falsy.
</p>
<p>
@@ -450,16 +480,6 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('splats', true) %>
<p>
<span id="arguments" class="bookmark"></span>
<b class="header">Arguments are Arrays</b>
If you reference the <b>arguments object</b> directly, it will be converted
into a real Array, making all of the
<a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array">Array methods</a>
available.
</p>
<%= code_for('arguments', true) %>
<p>
<span id="while" class="bookmark"></span>
<b class="header">While Loops</b>
@@ -589,8 +609,8 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<p>
<span id="inheritance" class="bookmark"></span>
<b class="header">Inheritance, and Calling Super from a Subclass</b>
<span id="classes" class="bookmark"></span>
<b class="header">Classes, Inheritance, and Super</b>
JavaScript's prototypal inheritance has always been a bit of a
brain-bender, with a whole family tree of libraries that provide a cleaner
syntax for classical inheritance on top of JavaScript's prototypes:
@@ -604,12 +624,24 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
set the prototype chain.
</p>
<p>
CoffeeScript provides <tt>extends</tt>
to help with prototype setup, <tt>::</tt> for quick access to an
object's prototype, and converts <tt>super()</tt> into a call against
the immediate ancestor's method of the same name.
Instead of repetitively attaching functions to a prototype, CoffeeScript
provides a basic <tt>class</tt> structure that allows you to name your class,
set the superclass, assign prototypal properties, and define the constructor,
in a single assignable expression.
</p>
<%= code_for('classes', true) %>
<p>
If structuring your prototypes classically isn't your cup of tea, CoffeeScript
provides a couple of lower-level conveniences. The <tt>extends</tt> operator
helps with proper prototype setup, <tt>::</tt> gives you
quick access to an object's prototype, and <tt>super()</tt>
is converted into a call against the immediate ancestor's method of the same name.
</p>
<%= code_for('prototypes', '"one_two".dasherize()') %>
<p>
Finally, you may assign Class-level (static) properties within a class
definition by using<br /><tt>@property: value</tt>
</p>
<%= code_for('super', true) %>
<p>
<span id="pattern_matching" class="bookmark"></span>
@@ -633,11 +665,23 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
to help pull out deeply nested properties.
</p>
<%= code_for('object_extraction', 'poet + " — " + street') %>
<p>
Pattern matching can even be combined with splats.
</p>
<%= code_for('patterns_and_splats', 'contents.join("")') %>
<p>
<span id="fat_arrow" class="bookmark"></span>
<b class="header">Function binding</b>
The fat arrow <tt>=></tt> can be used to both define a function, and to bind
In JavaScript, the <tt>this</tt> keyword is dynamically scoped to mean the
object that the current function is attached to. If you pass a function as
as callback, or attach it to a different object, the original value of <tt>this</tt>
will be lost. If you're not familiar with this behavior,
<a href="http://www.digital-web.com/articles/scope_in_javascript/">this Digital Web article</a>
gives a good overview of the quirks.
</p>
<p>
The fat arrow <tt>=&gt;</tt> can be used to both define a function, and to bind
it to the current value of <tt>this</tt>, right on the spot. This is helpful
when using callback-based libraries like Prototype or jQuery, for creating
iterator functions to pass to <tt>each</tt>, or event-handler functions
@@ -645,6 +689,20 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
properties of the <tt>this</tt> where they're defined.
</p>
<%= code_for('fat_arrow') %>
<p>
If we had used <tt>-></tt> in the callback above, <tt>@customer</tt> would
have referred to the undefined "customer" property of the DOM element,
and trying to call <tt>purchase()</tt> on it would have raised an exception.
</p>
<p>
If you have more custom needs for function binding, CoffeeScript includes
the <tt>&lt;-</tt> bind operator, which works the same as ECMAScript 5
and Prototype.js's <tt>Function#bind</tt>. The first argument is the <tt>this</tt>
value, and the remainder are curried arguments. In the example below,
we curry a jQuery request for a URL, and then execute the bound function
with the missing callback argument.
</p>
<%= code_for('binding', true) %>
<p>
<span id="embedded" class="bookmark"></span>
@@ -691,6 +749,20 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</p>
<%= code_for('comparisons', 'healthy') %>
<p>
<span id="interpolation" class="bookmark"></span>
<b class="header">String and RegExp Interpolation</b>
A version of <a href="http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation">ECMAScript Harmony's proposed string interpolation</a>
is included in CoffeeScript. Simple variables can be included by marking
them with a dollar sign.
</p>
<%= code_for('interpolation', 'quote') %>
<p>
And arbitrary expressions can be interpolated by using brackets <tt>${ ... }</tt><br />
Interpolation works the same way within regular expressions.
</p>
<%= code_for('interpolation_expression', 'sentence') %>
<p>
<span id="strings" class="bookmark"></span>
<b class="header">Multiline Strings and Heredocs</b>
@@ -704,6 +776,9 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
you can keep it all aligned with the body of your code.
</p>
<%= code_for('heredocs') %>
<p>
Double-quoted heredocs, like double-quoted strings, allow interpolation.
</p>
<h2>
<span id="cake" class="bookmark"></span>
@@ -734,20 +809,20 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<p>
While it's not recommended for serious use, CoffeeScripts may be included
directly within the browser using <tt>&lt;script type="text/coffeescript"&gt;</tt>
tags. The codebase includes a compressed and minified version of the compiler
(<a href="extras/coffee-script.js">Download current version here, 43k when gzipped</a>).
Include <tt>coffee-script.js</tt> on the page <b>after</b> any <tt>text/coffeescript</tt> tags
with inline CoffeeScript, and it will compile and evaluate them in order.
tags. The source includes a compressed and minified version of the compiler
(<a href="extras/coffee-script.js">Download current version here, 43k when gzipped</a>)
as <tt>extras/coffee-script.js</tt>. Include this file on a page with
inline CoffeeScript tags, and it will compile and evaluate them in order.
</p>
<p>
In fact, the little bit of glue script that runs "Try CoffeeScript" above,
as well as jQuery for the menu, is implemented in just this way.
as well as jQuery for the menu, is implemented in just this way.
View source and look at the bottom of the page to see the example.
Including the script also gives you access to <tt>CoffeeScript.compile()</tt>
so you can pop open Firebug and try compiling some strings.
</p>
<p>
The usual caveats about CoffeeScript apply &mdash; your inline scripts will
run within a closure wrapper, so if you want to expose global variables or
@@ -766,14 +841,45 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<tt>bin/cake test</tt> to run the test suite,<br />
<tt>bin/cake build</tt> to rebuild the CoffeeScript compiler, and <br />
<tt>bin/cake build:parser</tt> to regenerate the Jison parser if you're
working on the grammar.
working on the grammar. <br /><br />
<tt>git checkout lib &amp;&amp; bin/cake build:full</tt> is a good command to run when you're working
on the core language. It'll refresh the lib directory
(in case you broke something), build your altered compiler, use that to
rebuild itself (a good sanity test) and then run all of the tests. If
they pass, there's a good chance you've made a successful change.
</li>
<li>
<a href="http://github.com/jashkenas/coffee-script/issues">CoffeeScript Issues</a><br />
Bugs reports, feature requests, and general discussion all belong here.
</li>
<li>
If you'd like to chat, stop by <tt>#coffeescript</tt> on Freenode.
If you'd like to chat, stop by <tt>#coffeescript</tt> on Freenode in the
IRC client of your choice, or on
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
</li>
<li>
<b>defunkt</b>'s <a href="http://github.com/defunkt/coffee-mode">CoffeeScript Major Mode</a>
&mdash; a Emacs major mode that provides syntax highlighting, indentation
support, and some bonus commands.
</li>
<li>
<b>jashkenas</b>'s <a href="http://github.com/jashkenas/coffee-script-tmbundle">CoffeeScript TextMate Bundle</a>
&mdash; which provides syntax highlighting, snippet expansion, and the
ability to run bits of CoffeeScript from within TextMate itself.
</li>
<li>
<b>kchmck</b>'s <a href="http://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a>
&mdash; which adds Vim syntax highlighting and indentation support.
</li>
<li>
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
&mdash; a small Rack middleware for serving CoffeeScript files as
compiled JavaScript on the fly.
</li>
<li>
<b>jnicklas</b>'s <a href="http://github.com/jnicklas/bistro_car">BistroCar</a>
&mdash; a plugin that serves and bundles CoffeeScript from within your
Rails application.
</li>
</ul>
@@ -782,6 +888,50 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
Change Log
</h2>
<p>
<b class="header" style="margin-top: 20px;">0.6.0</b>
Trailing commas are now allowed, a-la Python. Static
properties may be assigned directly within class definitions,
using <tt>@property</tt> notation.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.6</b>
Interpolation can now be used within regular expressions and heredocs, as well as
strings. Added the <tt>&lt;-</tt> bind operator.
Allowing assignment to half-expressions instead of special <tt>||=</tt>-style
operators. The arguments object is no longer automatically converted into
an array. After requiring <tt>coffee-script</tt>, Node.js can now directly
load <tt>.coffee</tt> files, thanks to <b>registerExtension</b>. Multiple
splats can now be used in function calls, arrays, and pattern matching.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.5</b>
String interpolation, contributed by
<a href="http://github.com/StanAngeloff">Stan Angeloff</a>.
Since <tt>--run</tt> has been the default since <b>0.5.3</b>, updating
<tt>--stdio</tt> and <tt>--eval</tt> to run by default, pass <tt>--compile</tt>
as well if you'd like to print the result.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.4</b>
Bugfix that corrects the Node.js global constants <tt>__filename</tt> and
<tt>__dirname</tt>. Tweaks for more flexible parsing of nested function
literals and improperly-indented comments. Updates for the latest Node.js API.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.3</b>
CoffeeScript now has a syntax for defining classes. Many of the core
components (Nodes, Lexer, Rewriter, Scope, Optparse) are using them.
Cakefiles can use <tt>optparse.coffee</tt> to define options for tasks.
<tt>--run</tt> is now the default flag for the <tt>coffee</tt> command,
use <tt>--compile</tt> to save JavaScripts. Bugfix for an ambiguity between
RegExp literals and chained divisions.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.2</b>
Added a compressed version of the compiler for inclusion in web pages as
@@ -789,7 +939,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
with type <tt>text/coffeescript</tt> for you. Added a <tt>--stdio</tt> option
to the <tt>coffee</tt> command, for piped-in compiles.
</p>
<p>
<b class="header" style="margin-top: 20px;">0.5.1</b>
@@ -963,27 +1113,37 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
<script type="text/coffeescript">
window.repl_compile: ->
# Set up the compilation function, to run when you stop typing.
compile_source: ->
source: $('#repl_source').val()
window.compiled_js: ''
try
window.compiled_js: CoffeeScript.compile source, {no_wrap: true}
catch error then alert error
$('#repl_results').html window.compiled_js
$('#repl_results').text window.compiled_js
$('#error').hide();
catch error
$('#error').text(error.message).show();
window.repl_run: ->
# Listen for keypresses and recompile.
$('#repl_source').keyup -> compile_source()
# Eval the compiled js.
$('button.run').click ->
try
eval window.compiled_js
catch error then alert error
nav: $('.navigation')
current_nav: null
# Helper to hide the menus.
close_menus: ->
current_nav.removeClass 'active' if current_nav
if current_nav
current_nav.removeClass 'active'
document.body.className: 'minimized'
current_nav: null
nav.click (e) ->
# Bind navigation buttons to open the menus.
$('.navigation').click (e) ->
return if e.target.tagName.toLowerCase() is 'a'
if this isnt (current_nav and current_nav[0])
close_menus();
@@ -993,6 +1153,14 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
$(document.body).click -> close_menus()
$('.navigation .full_screen').click ->
document.body.className: 'full_screen'
$('.navigation .minimize').click ->
document.body.className: 'minimized'
compile_source()
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

View File

@@ -1,8 +0,0 @@
(function(){
var backwards;
backwards = function backwards() {
arguments = Array.prototype.slice.call(arguments, 0);
return alert(arguments.reverse());
};
backwards("stairway", "to", "heaven");
})();

View File

@@ -1,21 +1,21 @@
(function(){
var _a, _b, _c, _d, _e, _f, _g, food, lunch, roid, roid2;
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, food, lunch, roid, roid2;
// Eat lunch.
lunch = (function() {
_a = []; _b = ['toast', 'cheese', 'wine'];
for (_c = 0; _c < _b.length; _c++) {
food = _b[_c];
_a = []; _c = ['toast', 'cheese', 'wine'];
for (_b = 0, _d = _c.length; _b < _d; _b++) {
food = _c[_b];
_a.push(eat(food));
}
return _a;
}).call(this);
// Naive collision detection.
_d = asteroids;
for (_e = 0; _e < _d.length; _e++) {
roid = _d[_e];
_f = asteroids;
for (_g = 0; _g < _f.length; _g++) {
roid2 = _f[_g];
_f = asteroids;
for (_e = 0, _g = _f.length; _e < _g; _e++) {
roid = _f[_e];
_i = asteroids;
for (_h = 0, _j = _i.length; _h < _j; _h++) {
roid2 = _i[_h];
if (roid !== roid2) {
if (roid.overlaps(roid2)) {
roid.explode();

View File

@@ -0,0 +1,13 @@
(function(){
var get_source, url;
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
return function() {
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
};
};
url = "documentation/coffee/binding.coffee";
get_source = __bind(jQuery.get, jQuery, [url]);
get_source(function(response) {
return alert(response);
});
})();

View File

@@ -1,10 +1,9 @@
(function(){
process.mixin(require('assert'));
task('test', 'run each of the unit tests', function() {
var _a, _b, _c, test;
_a = []; _b = test_files;
for (_c = 0; _c < _b.length; _c++) {
test = _b[_c];
var _a, _b, _c, _d, test;
_a = []; _c = test_files;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
test = _c[_b];
_a.push(fs.readFile(test, function(err, code) {
return eval(coffee.compile(code));
}));

View File

@@ -1,5 +1,12 @@
(function(){
var Animal, Horse, Snake, _a, _b, sam, tom;
var Animal, Horse, Snake, sam, tom;
var __extends = function(child, parent) {
var ctor = function(){ };
ctor.prototype = parent.prototype;
child.__superClass__ = parent.prototype;
child.prototype = new ctor();
child.prototype.constructor = child;
};
Animal = function Animal() { };
Animal.prototype.move = function move(meters) {
return alert(this.name + " moved " + meters + "m.");
@@ -8,11 +15,7 @@
this.name = name;
return this;
};
_a = function(){};
_a.prototype = Animal.prototype;
Snake.__superClass__ = Animal.prototype;
Snake.prototype = new _a();
Snake.prototype.constructor = Snake;
__extends(Snake, Animal);
Snake.prototype.move = function move() {
alert("Slithering...");
return Snake.__superClass__.move.call(this, 5);
@@ -21,11 +24,7 @@
this.name = name;
return this;
};
_b = function(){};
_b.prototype = Animal.prototype;
Horse.__superClass__ = Animal.prototype;
Horse.prototype = new _b();
Horse.prototype.constructor = Horse;
__extends(Horse, Animal);
Horse.prototype.move = function move() {
alert("Galloping...");
return Horse.__superClass__.move.call(this, 45);

View File

@@ -4,7 +4,11 @@
if (student.excellent_work) {
return "A+";
} else if (student.okay_stuff) {
return student.tried_hard ? "B" : "B-";
if (student.tried_hard) {
return "B";
} else {
return "B-";
}
} else {
return "C";
}

View File

@@ -1,4 +1,4 @@
(function(){
var one, six, three, two;
six = ((one = 1)) + ((two = 2)) + ((three = 3));
six = (one = 1) + (two = 2) + (three = 3);
})();

View File

@@ -1,15 +1,15 @@
(function(){
var Account;
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
return function() {
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
};
};
Account = function Account(customer, cart) {
this.customer = customer;
this.cart = cart;
return $('.shopping_cart').bind('click', (function(__this) {
var __func = function(event) {
return $('.shopping_cart').bind('click', __bind(function(event) {
return this.customer.purchase(this.cart);
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
}, this));
};
})();

View File

@@ -1,4 +1,4 @@
(function(){
var html;
html = "<strong>\n cup of coffeescript\n</strong>";
html = '<strong>\n cup of coffeescript\n</strong>';
})();

View File

@@ -0,0 +1,5 @@
(function(){
var author, quote;
author = "Wittgenstein";
quote = "A picture is a fact. -- " + author;
})();

View File

@@ -0,0 +1,6 @@
(function(){
var dates, sentence, sep;
sentence = "" + (22 / 7) + " is a decent approximation of π";
sep = "[.\\/\\- ]";
dates = (new RegExp("\\d+" + sep + "\\d+" + sep + "\\d+", "g"));
})();

View File

@@ -1,5 +1,6 @@
(function(){
var _a, _b, _c, cubed_list, list, math, num, number, opposite_day, race, square;
var _a, _b, _c, _d, cubed_list, list, math, num, number, opposite_day, race, square;
var __slice = Array.prototype.slice;
// Assignment:
number = 42;
opposite_day = true;
@@ -24,7 +25,7 @@
// Splats:
race = function race(winner) {
var runners;
runners = Array.prototype.slice.call(arguments, 1);
runners = __slice.call(arguments, 1, arguments.length - 0);
return print(winner, runners);
};
// Existence:
@@ -33,9 +34,9 @@
}
// Array comprehensions:
cubed_list = (function() {
_a = []; _b = list;
for (_c = 0; _c < _b.length; _c++) {
num = _b[_c];
_a = []; _c = list;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
num = _c[_b];
_a.push(math.cube(num));
}
return _a;

View File

@@ -0,0 +1,9 @@
(function(){
var _a, close, contents, open, tag;
var __slice = Array.prototype.slice;
tag = "<impossible>";
_a = tag.split("");
open = _a[0];
contents = __slice.call(_a, 1, _a.length - 1);
close = _a[_a.length - 1];
})();

5
documentation/js/prototypes.js vendored Normal file
View File

@@ -0,0 +1,5 @@
(function(){
String.prototype.dasherize = function dasherize() {
return this.replace(/_/g, "-");
};
})();

View File

@@ -1,21 +1,21 @@
(function(){
var _a, _b, _c, _d, _e, countdown, egg_delivery, num;
var _a, _b, _c, _d, countdown, egg_delivery, num;
countdown = (function() {
_a = []; _d = 10; _e = 1;
for (_c = 0, num=_d; (_d <= _e ? num <= _e : num >= _e); (_d <= _e ? num += 1 : num -= 1), _c++) {
_a = []; _c = 10; _d = 1;
for (_b = 0, num = _c; (_c <= _d ? num <= _d : num >= _d); (_c <= _d ? num += 1 : num -= 1), _b++) {
_a.push(num);
}
return _a;
}).call(this);
egg_delivery = function egg_delivery() {
var _f, _g, _h, _i, _j, dozen_eggs, i;
_f = []; _i = 0; _j = eggs.length;
for (_h = 0, i=_i; (_i <= _j ? i < _j : i > _j); (_i <= _j ? i += 12 : i -= 12), _h++) {
_f.push((function() {
var _e, _f, _g, _h, dozen_eggs, i;
_e = []; _g = 0; _h = eggs.length;
for (_f = 0, i = _g; (_g <= _h ? i < _h : i > _h); (_g <= _h ? i += 12 : i -= 12), _f++) {
_e.push((function() {
dozen_eggs = eggs.slice(i, i + 12);
return deliver(new egg_carton(dozen));
}).call(this));
}
return _f;
return _e;
};
})();

View File

@@ -4,7 +4,8 @@
change_numbers = function change_numbers() {
var new_num;
new_num = -1;
return num = 10;
num = 10;
return num;
};
new_num = change_numbers();
})();

View File

@@ -1,12 +1,14 @@
(function(){
var award_medals, contenders, gold, silver, the_field;
var __slice = Array.prototype.slice;
gold = (silver = (the_field = "unknown"));
award_medals = function award_medals(first, second) {
var rest;
rest = Array.prototype.slice.call(arguments, 2);
rest = __slice.call(arguments, 2, arguments.length - 0);
gold = first;
silver = second;
return the_field = rest;
the_field = rest;
return the_field;
};
contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
award_medals.apply(this, contenders);

View File

@@ -1,627 +0,0 @@
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" media="screen,projection,print" href="css/idle.css" />
<title>Underscore.coffee</title>
</head>
<body>
<pre class="idle"><span class="line-numbers"> 1 </span>
<span class="line-numbers"> 2 </span> <span class="Comment"><span class="Comment">#</span> Underscore.coffee</span>
<span class="line-numbers"> 3 </span> <span class="Comment"><span class="Comment">#</span> (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.</span>
<span class="line-numbers"> 4 </span> <span class="Comment"><span class="Comment">#</span> Underscore is freely distributable under the terms of the MIT license.</span>
<span class="line-numbers"> 5 </span> <span class="Comment"><span class="Comment">#</span> Portions of Underscore are inspired by or borrowed from Prototype.js,</span>
<span class="line-numbers"> 6 </span> <span class="Comment"><span class="Comment">#</span> Oliver Steele's Functional, and John Resig's Micro-Templating.</span>
<span class="line-numbers"> 7 </span> <span class="Comment"><span class="Comment">#</span> For all details and documentation:</span>
<span class="line-numbers"> 8 </span> <span class="Comment"><span class="Comment">#</span> http://documentcloud.github.com/underscore/</span>
<span class="line-numbers"> 9 </span>
<span class="line-numbers"> 10 </span>
<span class="line-numbers"> 11 </span> <span class="Comment"><span class="Comment">#</span> ------------------------- Baseline setup ---------------------------------</span>
<span class="line-numbers"> 12 </span>
<span class="line-numbers"> 13 </span> <span class="Comment"><span class="Comment">#</span> Establish the root object, &quot;window&quot; in the browser, or &quot;global&quot; on the server.</span>
<span class="line-numbers"> 14 </span> <span class="FunctionName">root</span><span class="Keyword">:</span> <span class="Variable">this</span>
<span class="line-numbers"> 15 </span>
<span class="line-numbers"> 16 </span>
<span class="line-numbers"> 17 </span> <span class="Comment"><span class="Comment">#</span> Save the previous value of the &quot;_&quot; variable.</span>
<span class="line-numbers"> 18 </span> <span class="FunctionName">previousUnderscore</span><span class="Keyword">:</span> root._
<span class="line-numbers"> 19 </span>
<span class="line-numbers"> 20 </span>
<span class="line-numbers"> 21 </span> <span class="Comment"><span class="Comment">#</span> If Underscore is called as a function, it returns a wrapped object that</span>
<span class="line-numbers"> 22 </span> <span class="Comment"><span class="Comment">#</span> can be used OO-style. This wrapper holds altered versions of all the</span>
<span class="line-numbers"> 23 </span> <span class="Comment"><span class="Comment">#</span> underscore functions. Wrapped objects may be chained.</span>
<span class="line-numbers"> 24 </span> <span class="FunctionName">wrapper</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 25 </span> <span class="FunctionName">this._wrapped</span><span class="Keyword">:</span> obj
<span class="line-numbers"> 26 </span> <span class="Variable">this</span>
<span class="line-numbers"> 27 </span>
<span class="line-numbers"> 28 </span>
<span class="line-numbers"> 29 </span> <span class="Comment"><span class="Comment">#</span> Establish the object that gets thrown to break out of a loop iteration.</span>
<span class="line-numbers"> 30 </span> <span class="FunctionName">breaker</span><span class="Keyword">:</span> <span class="Keyword">if</span> <span class="Keyword">typeof</span>(StopIteration) <span class="Keyword">is</span> <span class="String"><span class="String">'</span>undefined<span class="String">'</span></span> <span class="Keyword">then</span> <span class="String"><span class="String">'</span>__break__<span class="String">'</span></span> <span class="Keyword">else</span> StopIteration
<span class="line-numbers"> 31 </span>
<span class="line-numbers"> 32 </span>
<span class="line-numbers"> 33 </span> <span class="Comment"><span class="Comment">#</span> Create a safe reference to the Underscore object forreference below.</span>
<span class="line-numbers"> 34 </span> <span class="FunctionName">_</span><span class="Keyword">:</span> <span class="FunctionName">root._</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">new</span> <span class="TypeName">wrapper</span>(obj)
<span class="line-numbers"> 35 </span>
<span class="line-numbers"> 36 </span>
<span class="line-numbers"> 37 </span> <span class="Comment"><span class="Comment">#</span> Export the Underscore object for CommonJS.</span>
<span class="line-numbers"> 38 </span> <span class="Keyword">if</span> <span class="Keyword">typeof</span>(exports) <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">'</span>undefined<span class="String">'</span></span> <span class="Keyword">then</span> <span class="FunctionName">exports._</span><span class="Keyword">:</span> _
<span class="line-numbers"> 39 </span>
<span class="line-numbers"> 40 </span>
<span class="line-numbers"> 41 </span> <span class="Comment"><span class="Comment">#</span> Create quick reference variables for speed access to core prototypes.</span>
<span class="line-numbers"> 42 </span> <span class="FunctionName">slice</span><span class="Keyword">:</span> <span class="FunctionName">Array:</span><span class="Keyword">:</span>slice
<span class="line-numbers"> 43 </span> <span class="FunctionName">unshift</span><span class="Keyword">:</span> <span class="FunctionName">Array:</span><span class="Keyword">:</span>unshift
<span class="line-numbers"> 44 </span> <span class="FunctionName">toString</span><span class="Keyword">:</span> <span class="FunctionName">Object:</span><span class="Keyword">:</span>toString
<span class="line-numbers"> 45 </span> <span class="FunctionName">hasOwnProperty</span><span class="Keyword">:</span> <span class="FunctionName">Object:</span><span class="Keyword">:</span>hasOwnProperty
<span class="line-numbers"> 46 </span> <span class="FunctionName">propertyIsEnumerable</span><span class="Keyword">:</span> <span class="FunctionName">Object:</span><span class="Keyword">:</span>propertyIsEnumerable
<span class="line-numbers"> 47 </span>
<span class="line-numbers"> 48 </span>
<span class="line-numbers"> 49 </span> <span class="Comment"><span class="Comment">#</span> Current version.</span>
<span class="line-numbers"> 50 </span> <span class="FunctionName">_.VERSION</span><span class="Keyword">:</span> <span class="String"><span class="String">'</span>0.5.8<span class="String">'</span></span>
<span class="line-numbers"> 51 </span>
<span class="line-numbers"> 52 </span>
<span class="line-numbers"> 53 </span> <span class="Comment"><span class="Comment">#</span> ------------------------ Collection Functions: ---------------------------</span>
<span class="line-numbers"> 54 </span>
<span class="line-numbers"> 55 </span> <span class="Comment"><span class="Comment">#</span> The cornerstone, an each implementation.</span>
<span class="line-numbers"> 56 </span> <span class="Comment"><span class="Comment">#</span> Handles objects implementing forEach, arrays, and raw objects.</span>
<span class="line-numbers"> 57 </span> <span class="FunctionName">_.each</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 58 </span> <span class="FunctionName">index</span><span class="Keyword">:</span> <span class="Number">0</span>
<span class="line-numbers"> 59 </span> <span class="Keyword">try</span>
<span class="line-numbers"> 60 </span> <span class="Keyword">return</span> obj.forEach(iterator, context) <span class="Keyword">if</span> obj.forEach
<span class="line-numbers"> 61 </span> <span class="Keyword">if</span> _.isNumber(obj.length)
<span class="line-numbers"> 62 </span> <span class="Keyword">return</span> iterator.call(context, obj[i], i, obj) <span class="Keyword">for</span> i <span class="Keyword">in</span> [<span class="Number">0</span>...obj.length]
<span class="line-numbers"> 63 </span> iterator.call(context, val, key, obj) <span class="Keyword">for</span> key, val <span class="Keyword">of</span> obj
<span class="line-numbers"> 64 </span> <span class="Keyword">catch</span> e
<span class="line-numbers"> 65 </span> <span class="Keyword">throw</span> e <span class="Keyword">if</span> e <span class="Keyword">isnt</span> breaker
<span class="line-numbers"> 66 </span> obj
<span class="line-numbers"> 67 </span>
<span class="line-numbers"> 68 </span>
<span class="line-numbers"> 69 </span> <span class="Comment"><span class="Comment">#</span> Return the results of applying the iterator to each element. Use JavaScript</span>
<span class="line-numbers"> 70 </span> <span class="Comment"><span class="Comment">#</span> 1.6's version of map, if possible.</span>
<span class="line-numbers"> 71 </span> <span class="FunctionName">_.map</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 72 </span> <span class="Keyword">return</span> obj.map(iterator, context) <span class="Keyword">if</span> (obj <span class="Keyword">and</span> _.isFunction(obj.map))
<span class="line-numbers"> 73 </span> <span class="FunctionName">results</span><span class="Keyword">:</span> []
<span class="line-numbers"> 74 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 75 </span> results.push(iterator.call(context, value, index, list))
<span class="line-numbers"> 76 </span> results
<span class="line-numbers"> 77 </span>
<span class="line-numbers"> 78 </span>
<span class="line-numbers"> 79 </span> <span class="Comment"><span class="Comment">#</span> Reduce builds up a single result from a list of values. Also known as</span>
<span class="line-numbers"> 80 </span> <span class="Comment"><span class="Comment">#</span> inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.</span>
<span class="line-numbers"> 81 </span> <span class="FunctionName">_.reduce</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, memo, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 82 </span> <span class="Keyword">return</span> obj.reduce(_.bind(iterator, context), memo) <span class="Keyword">if</span> (obj <span class="Keyword">and</span> _.isFunction(obj.reduce))
<span class="line-numbers"> 83 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 84 </span> <span class="FunctionName">memo</span><span class="Keyword">:</span> iterator.call(context, memo, value, index, list)
<span class="line-numbers"> 85 </span> memo
<span class="line-numbers"> 86 </span>
<span class="line-numbers"> 87 </span>
<span class="line-numbers"> 88 </span> <span class="Comment"><span class="Comment">#</span> The right-associative version of reduce, also known as foldr. Uses</span>
<span class="line-numbers"> 89 </span> <span class="Comment"><span class="Comment">#</span> JavaScript 1.8's version of reduceRight, if available.</span>
<span class="line-numbers"> 90 </span> <span class="FunctionName">_.reduceRight</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, memo, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 91 </span> <span class="Keyword">return</span> obj.reduceRight(_.bind(iterator, context), memo) <span class="Keyword">if</span> (obj <span class="Keyword">and</span> _.isFunction(obj.reduceRight))
<span class="line-numbers"> 92 </span> _.each _.clone(_.toArray(obj)).reverse(), <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 93 </span> <span class="FunctionName">memo</span><span class="Keyword">:</span> iterator.call(context, memo, value, index, obj)
<span class="line-numbers"> 94 </span> memo
<span class="line-numbers"> 95 </span>
<span class="line-numbers"> 96 </span>
<span class="line-numbers"> 97 </span> <span class="Comment"><span class="Comment">#</span> Return the first value which passes a truth test.</span>
<span class="line-numbers"> 98 </span> <span class="FunctionName">_.detect</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 99 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> <span class="BuiltInConstant">null</span>
<span class="line-numbers"> 100 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 101 </span> <span class="Keyword">if</span> iterator.call(context, value, index, list)
<span class="line-numbers"> 102 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> value
<span class="line-numbers"> 103 </span> _.breakLoop()
<span class="line-numbers"> 104 </span> result
<span class="line-numbers"> 105 </span>
<span class="line-numbers"> 106 </span>
<span class="line-numbers"> 107 </span> <span class="Comment"><span class="Comment">#</span> Return all the elements that pass a truth test. Use JavaScript 1.6's</span>
<span class="line-numbers"> 108 </span> <span class="Comment"><span class="Comment">#</span> filter(), if it exists.</span>
<span class="line-numbers"> 109 </span> <span class="FunctionName">_.select</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 110 </span> <span class="Keyword">if</span> obj <span class="Keyword">and</span> _.isFunction(obj.filter) <span class="Keyword">then</span> <span class="Keyword">return</span> obj.filter(iterator, context)
<span class="line-numbers"> 111 </span> <span class="FunctionName">results</span><span class="Keyword">:</span> []
<span class="line-numbers"> 112 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 113 </span> results.push(value) <span class="Keyword">if</span> iterator.call(context, value, index, list)
<span class="line-numbers"> 114 </span> results
<span class="line-numbers"> 115 </span>
<span class="line-numbers"> 116 </span>
<span class="line-numbers"> 117 </span> <span class="Comment"><span class="Comment">#</span> Return all the elements for which a truth test fails.</span>
<span class="line-numbers"> 118 </span> <span class="FunctionName">_.reject</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 119 </span> <span class="FunctionName">results</span><span class="Keyword">:</span> []
<span class="line-numbers"> 120 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 121 </span> results.push(value) <span class="Keyword">if</span> <span class="Keyword">not</span> iterator.call(context, value, index, list)
<span class="line-numbers"> 122 </span> results
<span class="line-numbers"> 123 </span>
<span class="line-numbers"> 124 </span>
<span class="line-numbers"> 125 </span> <span class="Comment"><span class="Comment">#</span> Determine whether all of the elements match a truth test. Delegate to</span>
<span class="line-numbers"> 126 </span> <span class="Comment"><span class="Comment">#</span> JavaScript 1.6's every(), if it is present.</span>
<span class="line-numbers"> 127 </span> <span class="FunctionName">_.all</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 128 </span> iterator <span class="Keyword">||</span><span class="Keyword">=</span> _.identity
<span class="line-numbers"> 129 </span> <span class="Keyword">return</span> obj.every(iterator, context) <span class="Keyword">if</span> obj <span class="Keyword">and</span> _.isFunction(obj.every)
<span class="line-numbers"> 130 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> <span class="BuiltInConstant">true</span>
<span class="line-numbers"> 131 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 132 </span> _.breakLoop() <span class="Keyword">unless</span> (<span class="FunctionName">result</span><span class="Keyword">:</span> result <span class="Keyword">and</span> iterator.call(context, value, index, list))
<span class="line-numbers"> 133 </span> result
<span class="line-numbers"> 134 </span>
<span class="line-numbers"> 135 </span>
<span class="line-numbers"> 136 </span> <span class="Comment"><span class="Comment">#</span> Determine if at least one element in the object matches a truth test. Use</span>
<span class="line-numbers"> 137 </span> <span class="Comment"><span class="Comment">#</span> JavaScript 1.6's some(), if it exists.</span>
<span class="line-numbers"> 138 </span> <span class="FunctionName">_.any</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 139 </span> iterator <span class="Keyword">||</span><span class="Keyword">=</span> _.identity
<span class="line-numbers"> 140 </span> <span class="Keyword">return</span> obj.some(iterator, context) <span class="Keyword">if</span> obj <span class="Keyword">and</span> _.isFunction(obj.some)
<span class="line-numbers"> 141 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> <span class="BuiltInConstant">false</span>
<span class="line-numbers"> 142 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 143 </span> _.breakLoop() <span class="Keyword">if</span> (<span class="FunctionName">result</span><span class="Keyword">:</span> iterator.call(context, value, index, list))
<span class="line-numbers"> 144 </span> result
<span class="line-numbers"> 145 </span>
<span class="line-numbers"> 146 </span>
<span class="line-numbers"> 147 </span> <span class="Comment"><span class="Comment">#</span> Determine if a given value is included in the array or object,</span>
<span class="line-numbers"> 148 </span> <span class="Comment"><span class="Comment">#</span> based on '==='.</span>
<span class="line-numbers"> 149 </span> <span class="FunctionName">_.include</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, target</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 150 </span> <span class="Keyword">return</span> _.indexOf(obj, target) <span class="Keyword">isnt</span> <span class="Keyword">-</span><span class="Number">1</span> <span class="Keyword">if</span> obj <span class="Keyword">and</span> _.isFunction(obj.indexOf)
<span class="line-numbers"> 151 </span> <span class="Keyword">for</span> key, val <span class="Keyword">of</span> obj
<span class="line-numbers"> 152 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">true</span> <span class="Keyword">if</span> val <span class="Keyword">is</span> target
<span class="line-numbers"> 153 </span> <span class="BuiltInConstant">false</span>
<span class="line-numbers"> 154 </span>
<span class="line-numbers"> 155 </span>
<span class="line-numbers"> 156 </span> <span class="Comment"><span class="Comment">#</span> Invoke a method with arguments on every item in a collection.</span>
<span class="line-numbers"> 157 </span> <span class="FunctionName">_.invoke</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, method</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 158 </span> <span class="FunctionName">args</span><span class="Keyword">:</span> _.rest(arguments, <span class="Number">2</span>)
<span class="line-numbers"> 159 </span> (<span class="Keyword">if</span> method <span class="Keyword">then</span> val[method] <span class="Keyword">else</span> val).apply(val, args) <span class="Keyword">for</span> val <span class="Keyword">in</span> obj
<span class="line-numbers"> 160 </span>
<span class="line-numbers"> 161 </span>
<span class="line-numbers"> 162 </span> <span class="Comment"><span class="Comment">#</span> Convenience version of a common use case of map: fetching a property.</span>
<span class="line-numbers"> 163 </span> <span class="FunctionName">_.pluck</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, key</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 164 </span> _.map(obj, (<span class="FunctionArgument">(</span><span class="FunctionArgument">val</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> val[key]))
<span class="line-numbers"> 165 </span>
<span class="line-numbers"> 166 </span>
<span class="line-numbers"> 167 </span> <span class="Comment"><span class="Comment">#</span> Return the maximum item or (item-based computation).</span>
<span class="line-numbers"> 168 </span> <span class="FunctionName">_.max</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 169 </span> <span class="Keyword">return</span> Math.max.apply(Math, obj) <span class="Keyword">if</span> <span class="Keyword">not</span> iterator <span class="Keyword">and</span> _.isArray(obj)
<span class="line-numbers"> 170 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> {<span class="FunctionName">computed</span><span class="Keyword">:</span> <span class="Keyword">-</span><span class="BuiltInConstant">Infinity</span>}
<span class="line-numbers"> 171 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 172 </span> <span class="FunctionName">computed</span><span class="Keyword">:</span> <span class="Keyword">if</span> iterator <span class="Keyword">then</span> iterator.call(context, value, index, list) <span class="Keyword">else</span> value
<span class="line-numbers"> 173 </span> computed <span class="Keyword">&gt;=</span> result.computed <span class="Keyword">and</span> (<span class="FunctionName">result</span><span class="Keyword">:</span> {<span class="FunctionName">value</span><span class="Keyword">:</span> value, <span class="FunctionName">computed</span><span class="Keyword">:</span> computed})
<span class="line-numbers"> 174 </span> result.value
<span class="line-numbers"> 175 </span>
<span class="line-numbers"> 176 </span>
<span class="line-numbers"> 177 </span> <span class="Comment"><span class="Comment">#</span> Return the minimum element (or element-based computation).</span>
<span class="line-numbers"> 178 </span> <span class="FunctionName">_.min</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 179 </span> <span class="Keyword">return</span> Math.min.apply(Math, obj) <span class="Keyword">if</span> <span class="Keyword">not</span> iterator <span class="Keyword">and</span> _.isArray(obj)
<span class="line-numbers"> 180 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> {<span class="FunctionName">computed</span><span class="Keyword">:</span> <span class="BuiltInConstant">Infinity</span>}
<span class="line-numbers"> 181 </span> _.each obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 182 </span> <span class="FunctionName">computed</span><span class="Keyword">:</span> <span class="Keyword">if</span> iterator <span class="Keyword">then</span> iterator.call(context, value, index, list) <span class="Keyword">else</span> value
<span class="line-numbers"> 183 </span> computed <span class="Keyword">&lt;</span> result.computed <span class="Keyword">and</span> (<span class="FunctionName">result</span><span class="Keyword">:</span> {<span class="FunctionName">value</span><span class="Keyword">:</span> value, <span class="FunctionName">computed</span><span class="Keyword">:</span> computed})
<span class="line-numbers"> 184 </span> result.value
<span class="line-numbers"> 185 </span>
<span class="line-numbers"> 186 </span>
<span class="line-numbers"> 187 </span> <span class="Comment"><span class="Comment">#</span> Sort the object's values by a criteria produced by an iterator.</span>
<span class="line-numbers"> 188 </span> <span class="FunctionName">_.sortBy</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, iterator, context</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 189 </span> _.pluck(((_.map obj, <span class="FunctionArgument">(</span><span class="FunctionArgument">value, index, list</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 190 </span> {<span class="FunctionName">value</span><span class="Keyword">:</span> value, <span class="FunctionName">criteria</span><span class="Keyword">:</span> iterator.call(context, value, index, list)}
<span class="line-numbers"> 191 </span> ).sort(<span class="FunctionArgument">(</span><span class="FunctionArgument">left, right</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 192 </span> <span class="FunctionName">a</span><span class="Keyword">:</span> left.criteria; <span class="FunctionName">b</span><span class="Keyword">:</span> right.criteria
<span class="line-numbers"> 193 </span> <span class="Keyword">if</span> a <span class="Keyword">&lt;</span> b <span class="Keyword">then</span> <span class="Keyword">-</span><span class="Number">1</span> <span class="Keyword">else</span> <span class="Keyword">if</span> a <span class="Keyword">&gt;</span> b <span class="Keyword">then</span> <span class="Number">1</span> <span class="Keyword">else</span> <span class="Number">0</span>
<span class="line-numbers"> 194 </span> )), <span class="String"><span class="String">'</span>value<span class="String">'</span></span>)
<span class="line-numbers"> 195 </span>
<span class="line-numbers"> 196 </span>
<span class="line-numbers"> 197 </span> <span class="Comment"><span class="Comment">#</span> Use a comparator function to figure out at what index an object should</span>
<span class="line-numbers"> 198 </span> <span class="Comment"><span class="Comment">#</span> be inserted so as to maintain order. Uses binary search.</span>
<span class="line-numbers"> 199 </span> <span class="FunctionName">_.sortedIndex</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array, obj, iterator</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 200 </span> iterator <span class="Keyword">||</span><span class="Keyword">=</span> _.identity
<span class="line-numbers"> 201 </span> <span class="FunctionName">low</span><span class="Keyword">:</span> <span class="Number">0</span>; <span class="FunctionName">high</span><span class="Keyword">:</span> array.length
<span class="line-numbers"> 202 </span> <span class="Keyword">while</span> low <span class="Keyword">&lt;</span> high
<span class="line-numbers"> 203 </span> <span class="FunctionName">mid</span><span class="Keyword">:</span> (low <span class="Keyword">+</span> high) <span class="Keyword">&gt;</span><span class="Keyword">&gt;</span> <span class="Number">1</span>
<span class="line-numbers"> 204 </span> <span class="Keyword">if</span> iterator(array[mid]) <span class="Keyword">&lt;</span> iterator(obj) <span class="Keyword">then</span> <span class="FunctionName">low</span><span class="Keyword">:</span> mid <span class="Keyword">+</span> <span class="Number">1</span> <span class="Keyword">else</span> <span class="FunctionName">high</span><span class="Keyword">:</span> mid
<span class="line-numbers"> 205 </span> low
<span class="line-numbers"> 206 </span>
<span class="line-numbers"> 207 </span>
<span class="line-numbers"> 208 </span> <span class="Comment"><span class="Comment">#</span> Convert anything iterable into a real, live array.</span>
<span class="line-numbers"> 209 </span> <span class="FunctionName">_.toArray</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">iterable</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 210 </span> <span class="Keyword">return</span> [] <span class="Keyword">if</span> (<span class="Keyword">!</span>iterable)
<span class="line-numbers"> 211 </span> <span class="Keyword">return</span> iterable.toArray() <span class="Keyword">if</span> (iterable.toArray)
<span class="line-numbers"> 212 </span> <span class="Keyword">return</span> iterable <span class="Keyword">if</span> (_.isArray(iterable))
<span class="line-numbers"> 213 </span> <span class="Keyword">return</span> slice.call(iterable) <span class="Keyword">if</span> (_.isArguments(iterable))
<span class="line-numbers"> 214 </span> _.values(iterable)
<span class="line-numbers"> 215 </span>
<span class="line-numbers"> 216 </span>
<span class="line-numbers"> 217 </span> <span class="Comment"><span class="Comment">#</span> Return the number of elements in an object.</span>
<span class="line-numbers"> 218 </span> <span class="FunctionName">_.size</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> _.toArray(obj).length
<span class="line-numbers"> 219 </span>
<span class="line-numbers"> 220 </span>
<span class="line-numbers"> 221 </span> <span class="Comment"><span class="Comment">#</span> -------------------------- Array Functions: ------------------------------</span>
<span class="line-numbers"> 222 </span>
<span class="line-numbers"> 223 </span> <span class="Comment"><span class="Comment">#</span> Get the first element of an array. Passing &quot;n&quot; will return the first N</span>
<span class="line-numbers"> 224 </span> <span class="Comment"><span class="Comment">#</span> values in the array. Aliased as &quot;head&quot;. The &quot;guard&quot; check allows it to work</span>
<span class="line-numbers"> 225 </span> <span class="Comment"><span class="Comment">#</span> with _.map.</span>
<span class="line-numbers"> 226 </span> <span class="FunctionName">_.first</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array, n, guard</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 227 </span> <span class="Keyword">if</span> n <span class="Keyword">and</span> <span class="Keyword">not</span> guard <span class="Keyword">then</span> slice.call(array, <span class="Number">0</span>, n) <span class="Keyword">else</span> array[<span class="Number">0</span>]
<span class="line-numbers"> 228 </span>
<span class="line-numbers"> 229 </span>
<span class="line-numbers"> 230 </span> <span class="Comment"><span class="Comment">#</span> Returns everything but the first entry of the array. Aliased as &quot;tail&quot;.</span>
<span class="line-numbers"> 231 </span> <span class="Comment"><span class="Comment">#</span> Especially useful on the arguments object. Passing an &quot;index&quot; will return</span>
<span class="line-numbers"> 232 </span> <span class="Comment"><span class="Comment">#</span> the rest of the values in the array from that index onward. The &quot;guard&quot;</span>
<span class="line-numbers"> 233 </span> <span class="Comment"><span class="Comment">#</span> check allows it to work with _.map.</span>
<span class="line-numbers"> 234 </span> <span class="FunctionName">_.rest</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array, index, guard</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 235 </span> slice.call(array, <span class="Keyword">if</span> _.isUndefined(index) <span class="Keyword">or</span> guard <span class="Keyword">then</span> <span class="Number">1</span> <span class="Keyword">else</span> index)
<span class="line-numbers"> 236 </span>
<span class="line-numbers"> 237 </span>
<span class="line-numbers"> 238 </span> <span class="Comment"><span class="Comment">#</span> Get the last element of an array.</span>
<span class="line-numbers"> 239 </span> <span class="FunctionName">_.last</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> array[array.length <span class="Keyword">-</span> <span class="Number">1</span>]
<span class="line-numbers"> 240 </span>
<span class="line-numbers"> 241 </span>
<span class="line-numbers"> 242 </span> <span class="Comment"><span class="Comment">#</span> Trim out all falsy values from an array.</span>
<span class="line-numbers"> 243 </span> <span class="FunctionName">_.compact</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> item <span class="Keyword">for</span> item <span class="Keyword">in</span> array <span class="Keyword">when</span> item
<span class="line-numbers"> 244 </span>
<span class="line-numbers"> 245 </span>
<span class="line-numbers"> 246 </span> <span class="Comment"><span class="Comment">#</span> Return a completely flattened version of an array.</span>
<span class="line-numbers"> 247 </span> <span class="FunctionName">_.flatten</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 248 </span> _.reduce array, [], <span class="FunctionArgument">(</span><span class="FunctionArgument">memo, value</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 249 </span> <span class="Keyword">return</span> memo.concat(_.flatten(value)) <span class="Keyword">if</span> _.isArray(value)
<span class="line-numbers"> 250 </span> memo.push(value)
<span class="line-numbers"> 251 </span> memo
<span class="line-numbers"> 252 </span>
<span class="line-numbers"> 253 </span>
<span class="line-numbers"> 254 </span> <span class="Comment"><span class="Comment">#</span> Return a version of the array that does not contain the specified value(s).</span>
<span class="line-numbers"> 255 </span> <span class="FunctionName">_.without</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 256 </span> <span class="FunctionName">values</span><span class="Keyword">:</span> _.rest(arguments)
<span class="line-numbers"> 257 </span> val <span class="Keyword">for</span> val <span class="Keyword">in</span> _.toArray(array) <span class="Keyword">when</span> <span class="Keyword">not</span> _.include(values, val)
<span class="line-numbers"> 258 </span>
<span class="line-numbers"> 259 </span>
<span class="line-numbers"> 260 </span> <span class="Comment"><span class="Comment">#</span> Produce a duplicate-free version of the array. If the array has already</span>
<span class="line-numbers"> 261 </span> <span class="Comment"><span class="Comment">#</span> been sorted, you have the option of using a faster algorithm.</span>
<span class="line-numbers"> 262 </span> <span class="FunctionName">_.uniq</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array, isSorted</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 263 </span> <span class="FunctionName">memo</span><span class="Keyword">:</span> []
<span class="line-numbers"> 264 </span> <span class="Keyword">for</span> el, i <span class="Keyword">in</span> _.toArray(array)
<span class="line-numbers"> 265 </span> memo.push(el) <span class="Keyword">if</span> i <span class="Keyword">is</span> <span class="Number">0</span> <span class="Keyword">||</span> (<span class="Keyword">if</span> isSorted <span class="Keyword">is</span> <span class="BuiltInConstant">true</span> <span class="Keyword">then</span> _.last(memo) <span class="Keyword">isnt</span> el <span class="Keyword">else</span> <span class="Keyword">not</span> _.include(memo, el))
<span class="line-numbers"> 266 </span> memo
<span class="line-numbers"> 267 </span>
<span class="line-numbers"> 268 </span>
<span class="line-numbers"> 269 </span> <span class="Comment"><span class="Comment">#</span> Produce an array that contains every item shared between all the</span>
<span class="line-numbers"> 270 </span> <span class="Comment"><span class="Comment">#</span> passed-in arrays.</span>
<span class="line-numbers"> 271 </span> <span class="FunctionName">_.intersect</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 272 </span> <span class="FunctionName">rest</span><span class="Keyword">:</span> _.rest(arguments)
<span class="line-numbers"> 273 </span> _.select _.uniq(array), <span class="FunctionArgument">(</span><span class="FunctionArgument">item</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 274 </span> _.all rest, <span class="FunctionArgument">(</span><span class="FunctionArgument">other</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 275 </span> _.indexOf(other, item) <span class="Keyword">&gt;=</span> <span class="Number">0</span>
<span class="line-numbers"> 276 </span>
<span class="line-numbers"> 277 </span>
<span class="line-numbers"> 278 </span> <span class="Comment"><span class="Comment">#</span> Zip together multiple lists into a single array -- elements that share</span>
<span class="line-numbers"> 279 </span> <span class="Comment"><span class="Comment">#</span> an index go together.</span>
<span class="line-numbers"> 280 </span> <span class="FunctionName">_.zip</span><span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 281 </span> <span class="FunctionName">length</span><span class="Keyword">:</span> _.max(_.pluck(arguments, <span class="String"><span class="String">'</span>length<span class="String">'</span></span>))
<span class="line-numbers"> 282 </span> <span class="FunctionName">results</span><span class="Keyword">:</span> <span class="Keyword">new</span> <span class="TypeName">Array</span>(length)
<span class="line-numbers"> 283 </span> <span class="Keyword">for</span> i <span class="Keyword">in</span> [<span class="Number">0</span>...length]
<span class="line-numbers"> 284 </span> results[i]<span class="Keyword">:</span> _.pluck(arguments, String(i))
<span class="line-numbers"> 285 </span> results
<span class="line-numbers"> 286 </span>
<span class="line-numbers"> 287 </span>
<span class="line-numbers"> 288 </span> <span class="Comment"><span class="Comment">#</span> If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),</span>
<span class="line-numbers"> 289 </span> <span class="Comment"><span class="Comment">#</span> we need this function. Return the position of the first occurence of an</span>
<span class="line-numbers"> 290 </span> <span class="Comment"><span class="Comment">#</span> item in an array, or -1 if the item is not included in the array.</span>
<span class="line-numbers"> 291 </span> <span class="FunctionName">_.indexOf</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array, item</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 292 </span> <span class="Keyword">return</span> array.indexOf(item) <span class="Keyword">if</span> array.indexOf
<span class="line-numbers"> 293 </span> <span class="FunctionName">i</span><span class="Keyword">:</span> <span class="Number">0</span>; <span class="FunctionName">l</span><span class="Keyword">:</span> array.length
<span class="line-numbers"> 294 </span> <span class="Keyword">while</span> l <span class="Keyword">-</span> i
<span class="line-numbers"> 295 </span> <span class="Keyword">if</span> array[i] <span class="Keyword">is</span> item <span class="Keyword">then</span> <span class="Keyword">return</span> i <span class="Keyword">else</span> i<span class="Keyword">++</span>
<span class="line-numbers"> 296 </span> <span class="Keyword">-</span><span class="Number">1</span>
<span class="line-numbers"> 297 </span>
<span class="line-numbers"> 298 </span>
<span class="line-numbers"> 299 </span> <span class="Comment"><span class="Comment">#</span> Provide JavaScript 1.6's lastIndexOf, delegating to the native function,</span>
<span class="line-numbers"> 300 </span> <span class="Comment"><span class="Comment">#</span> if possible.</span>
<span class="line-numbers"> 301 </span> <span class="FunctionName">_.lastIndexOf</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">array, item</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 302 </span> <span class="Keyword">return</span> array.lastIndexOf(item) <span class="Keyword">if</span> array.lastIndexOf
<span class="line-numbers"> 303 </span> <span class="FunctionName">i</span><span class="Keyword">:</span> array.length
<span class="line-numbers"> 304 </span> <span class="Keyword">while</span> i
<span class="line-numbers"> 305 </span> <span class="Keyword">if</span> array[i] <span class="Keyword">is</span> item <span class="Keyword">then</span> <span class="Keyword">return</span> i <span class="Keyword">else</span> i<span class="Keyword">--</span>
<span class="line-numbers"> 306 </span> <span class="Keyword">-</span><span class="Number">1</span>
<span class="line-numbers"> 307 </span>
<span class="line-numbers"> 308 </span>
<span class="line-numbers"> 309 </span> <span class="Comment"><span class="Comment">#</span> Generate an integer Array containing an arithmetic progression. A port of</span>
<span class="line-numbers"> 310 </span> <span class="Comment"><span class="Comment">#</span> the native Python range() function. See:</span>
<span class="line-numbers"> 311 </span> <span class="Comment"><span class="Comment">#</span> http://docs.python.org/library/functions.html#range</span>
<span class="line-numbers"> 312 </span> <span class="FunctionName">_.range</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">start, stop, step</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 313 </span> <span class="FunctionName">a</span><span class="Keyword">:</span> arguments
<span class="line-numbers"> 314 </span> <span class="FunctionName">solo</span><span class="Keyword">:</span> a.length <span class="Keyword">&lt;=</span> <span class="Number">1</span>
<span class="line-numbers"> 315 </span> <span class="FunctionName">i</span><span class="Keyword">:</span> <span class="FunctionName">start</span><span class="Keyword">:</span> <span class="Keyword">if</span> solo <span class="Keyword">then</span> <span class="Number">0</span> <span class="Keyword">else</span> a[<span class="Number">0</span>]
<span class="line-numbers"> 316 </span> <span class="FunctionName">stop</span><span class="Keyword">:</span> <span class="Keyword">if</span> solo <span class="Keyword">then</span> a[<span class="Number">0</span>] <span class="Keyword">else</span> a[<span class="Number">1</span>]
<span class="line-numbers"> 317 </span> <span class="FunctionName">step</span><span class="Keyword">:</span> a[<span class="Number">2</span>] <span class="Keyword">or</span> <span class="Number">1</span>
<span class="line-numbers"> 318 </span> <span class="FunctionName">len</span><span class="Keyword">:</span> Math.ceil((stop <span class="Keyword">-</span> start) <span class="Keyword">/</span> step)
<span class="line-numbers"> 319 </span> <span class="Keyword">return</span> [] <span class="Keyword">if</span> len <span class="Keyword">&lt;=</span> <span class="Number">0</span>
<span class="line-numbers"> 320 </span> <span class="FunctionName">range</span><span class="Keyword">:</span> <span class="Keyword">new</span> <span class="TypeName">Array</span>(len)
<span class="line-numbers"> 321 </span> <span class="FunctionName">idx</span><span class="Keyword">:</span> <span class="Number">0</span>
<span class="line-numbers"> 322 </span> <span class="Keyword">while</span> <span class="BuiltInConstant">true</span>
<span class="line-numbers"> 323 </span> <span class="Keyword">return</span> range <span class="Keyword">if</span> (<span class="Keyword">if</span> step <span class="Keyword">&gt;</span> <span class="Number">0</span> <span class="Keyword">then</span> i <span class="Keyword">-</span> stop <span class="Keyword">else</span> stop <span class="Keyword">-</span> i) <span class="Keyword">&gt;=</span> <span class="Number">0</span>
<span class="line-numbers"> 324 </span> range[idx]<span class="Keyword">:</span> i
<span class="line-numbers"> 325 </span> idx<span class="Keyword">++</span>
<span class="line-numbers"> 326 </span> i<span class="Keyword">+</span><span class="Keyword">=</span> step
<span class="line-numbers"> 327 </span>
<span class="line-numbers"> 328 </span>
<span class="line-numbers"> 329 </span> <span class="Comment"><span class="Comment">#</span> ----------------------- Function Functions: -----------------------------</span>
<span class="line-numbers"> 330 </span>
<span class="line-numbers"> 331 </span> <span class="Comment"><span class="Comment">#</span> Create a function bound to a given object (assigning 'this', and arguments,</span>
<span class="line-numbers"> 332 </span> <span class="Comment"><span class="Comment">#</span> optionally). Binding with arguments is also known as 'curry'.</span>
<span class="line-numbers"> 333 </span> <span class="FunctionName">_.bind</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">func, obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 334 </span> <span class="FunctionName">args</span><span class="Keyword">:</span> _.rest(arguments, <span class="Number">2</span>)
<span class="line-numbers"> 335 </span> <span class="Storage">-&gt;</span> func.apply(obj <span class="Keyword">or</span> root, args.concat(arguments))
<span class="line-numbers"> 336 </span>
<span class="line-numbers"> 337 </span>
<span class="line-numbers"> 338 </span> <span class="Comment"><span class="Comment">#</span> Bind all of an object's methods to that object. Useful for ensuring that</span>
<span class="line-numbers"> 339 </span> <span class="Comment"><span class="Comment">#</span> all callbacks defined on an object belong to it.</span>
<span class="line-numbers"> 340 </span> <span class="FunctionName">_.bindAll</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 341 </span> <span class="FunctionName">funcs</span><span class="Keyword">:</span> <span class="Keyword">if</span> arguments.length <span class="Keyword">&gt;</span> <span class="Number">1</span> <span class="Keyword">then</span> _.rest(arguments) <span class="Keyword">else</span> _.functions(obj)
<span class="line-numbers"> 342 </span> _.each(funcs, <span class="FunctionArgument">(</span><span class="FunctionArgument">f</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> obj[f]<span class="Keyword">:</span> _.bind(obj[f], obj))
<span class="line-numbers"> 343 </span> obj
<span class="line-numbers"> 344 </span>
<span class="line-numbers"> 345 </span>
<span class="line-numbers"> 346 </span> <span class="Comment"><span class="Comment">#</span> Delays a function for the given number of milliseconds, and then calls</span>
<span class="line-numbers"> 347 </span> <span class="Comment"><span class="Comment">#</span> it with the arguments supplied.</span>
<span class="line-numbers"> 348 </span> <span class="FunctionName">_.delay</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">func, wait</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 349 </span> <span class="FunctionName">args</span><span class="Keyword">:</span> _.rest(arguments, <span class="Number">2</span>)
<span class="line-numbers"> 350 </span> setTimeout((<span class="Storage">-&gt;</span> func.apply(func, args)), wait)
<span class="line-numbers"> 351 </span>
<span class="line-numbers"> 352 </span>
<span class="line-numbers"> 353 </span> <span class="Comment"><span class="Comment">#</span> Defers a function, scheduling it to run after the current call stack has</span>
<span class="line-numbers"> 354 </span> <span class="Comment"><span class="Comment">#</span> cleared.</span>
<span class="line-numbers"> 355 </span> <span class="FunctionName">_.defer</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">func</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 356 </span> _.delay.apply(_, [func, <span class="Number">1</span>].concat(_.rest(arguments)))
<span class="line-numbers"> 357 </span>
<span class="line-numbers"> 358 </span>
<span class="line-numbers"> 359 </span> <span class="Comment"><span class="Comment">#</span> Returns the first function passed as an argument to the second,</span>
<span class="line-numbers"> 360 </span> <span class="Comment"><span class="Comment">#</span> allowing you to adjust arguments, run code before and after, and</span>
<span class="line-numbers"> 361 </span> <span class="Comment"><span class="Comment">#</span> conditionally execute the original function.</span>
<span class="line-numbers"> 362 </span> <span class="FunctionName">_.wrap</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">func, wrapper</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 363 </span> <span class="Storage">-&gt;</span> wrapper.apply(wrapper, [func].concat(arguments))
<span class="line-numbers"> 364 </span>
<span class="line-numbers"> 365 </span>
<span class="line-numbers"> 366 </span> <span class="Comment"><span class="Comment">#</span> Returns a function that is the composition of a list of functions, each</span>
<span class="line-numbers"> 367 </span> <span class="Comment"><span class="Comment">#</span> consuming the return value of the function that follows.</span>
<span class="line-numbers"> 368 </span> <span class="FunctionName">_.compose</span><span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 369 </span> <span class="FunctionName">funcs</span><span class="Keyword">:</span> arguments
<span class="line-numbers"> 370 </span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 371 </span> <span class="FunctionName">args</span><span class="Keyword">:</span> arguments
<span class="line-numbers"> 372 </span> <span class="Keyword">for</span> i <span class="Keyword">in</span> [(funcs.length <span class="Keyword">-</span> <span class="Number">1</span>)..<span class="Number">0</span>]
<span class="line-numbers"> 373 </span> <span class="FunctionName">args</span><span class="Keyword">:</span> [funcs[i].apply(<span class="Variable">this</span>, args)]
<span class="line-numbers"> 374 </span> args[<span class="Number">0</span>]
<span class="line-numbers"> 375 </span>
<span class="line-numbers"> 376 </span>
<span class="line-numbers"> 377 </span> <span class="Comment"><span class="Comment">#</span> ------------------------- Object Functions: ----------------------------</span>
<span class="line-numbers"> 378 </span>
<span class="line-numbers"> 379 </span> <span class="Comment"><span class="Comment">#</span> Retrieve the names of an object's properties.</span>
<span class="line-numbers"> 380 </span> <span class="FunctionName">_.keys</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 381 </span> <span class="Keyword">return</span> _.range(<span class="Number">0</span>, obj.length) <span class="Keyword">if</span> _.isArray(obj)
<span class="line-numbers"> 382 </span> key <span class="Keyword">for</span> key, val <span class="Keyword">of</span> obj
<span class="line-numbers"> 383 </span>
<span class="line-numbers"> 384 </span>
<span class="line-numbers"> 385 </span> <span class="Comment"><span class="Comment">#</span> Retrieve the values of an object's properties.</span>
<span class="line-numbers"> 386 </span> <span class="FunctionName">_.values</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 387 </span> _.map(obj, _.identity)
<span class="line-numbers"> 388 </span>
<span class="line-numbers"> 389 </span>
<span class="line-numbers"> 390 </span> <span class="Comment"><span class="Comment">#</span> Return a sorted list of the function names available in Underscore.</span>
<span class="line-numbers"> 391 </span> <span class="FunctionName">_.functions</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 392 </span> _.select(_.keys(obj), <span class="FunctionArgument">(</span><span class="FunctionArgument">key</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> _.isFunction(obj[key])).sort()
<span class="line-numbers"> 393 </span>
<span class="line-numbers"> 394 </span>
<span class="line-numbers"> 395 </span> <span class="Comment"><span class="Comment">#</span> Extend a given object with all of the properties in a source object.</span>
<span class="line-numbers"> 396 </span> <span class="FunctionName">_.extend</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">destination, source</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 397 </span> <span class="Keyword">for</span> key, val <span class="Keyword">of</span> source
<span class="line-numbers"> 398 </span> destination[key]<span class="Keyword">:</span> val
<span class="line-numbers"> 399 </span> destination
<span class="line-numbers"> 400 </span>
<span class="line-numbers"> 401 </span>
<span class="line-numbers"> 402 </span> <span class="Comment"><span class="Comment">#</span> Create a (shallow-cloned) duplicate of an object.</span>
<span class="line-numbers"> 403 </span> <span class="FunctionName">_.clone</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 404 </span> <span class="Keyword">return</span> obj.slice(<span class="Number">0</span>) <span class="Keyword">if</span> _.isArray(obj)
<span class="line-numbers"> 405 </span> _.extend({}, obj)
<span class="line-numbers"> 406 </span>
<span class="line-numbers"> 407 </span>
<span class="line-numbers"> 408 </span> <span class="Comment"><span class="Comment">#</span> Invokes interceptor with the obj, and then returns obj.</span>
<span class="line-numbers"> 409 </span> <span class="Comment"><span class="Comment">#</span> The primary purpose of this method is to &quot;tap into&quot; a method chain, in order to perform operations on intermediate results within the chain.</span>
<span class="line-numbers"> 410 </span> <span class="FunctionName">_.tap</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, interceptor</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 411 </span> interceptor(obj)
<span class="line-numbers"> 412 </span> obj
<span class="line-numbers"> 413 </span>
<span class="line-numbers"> 414 </span>
<span class="line-numbers"> 415 </span> <span class="Comment"><span class="Comment">#</span> Perform a deep comparison to check if two objects are equal.</span>
<span class="line-numbers"> 416 </span> <span class="FunctionName">_.isEqual</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">a, b</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 417 </span> <span class="Comment"><span class="Comment">#</span> Check object identity.</span>
<span class="line-numbers"> 418 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">true</span> <span class="Keyword">if</span> a <span class="Keyword">is</span> b
<span class="line-numbers"> 419 </span> <span class="Comment"><span class="Comment">#</span> Different types?</span>
<span class="line-numbers"> 420 </span> <span class="FunctionName">atype</span><span class="Keyword">:</span> <span class="Keyword">typeof</span>(a); <span class="FunctionName">btype</span><span class="Keyword">:</span> <span class="Keyword">typeof</span>(b)
<span class="line-numbers"> 421 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">false</span> <span class="Keyword">if</span> atype <span class="Keyword">isnt</span> btype
<span class="line-numbers"> 422 </span> <span class="Comment"><span class="Comment">#</span> Basic equality test (watch out for coercions).</span>
<span class="line-numbers"> 423 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">true</span> <span class="Keyword">if</span> <span class="String"><span class="String">`</span>a == b<span class="String">`</span></span>
<span class="line-numbers"> 424 </span> <span class="Comment"><span class="Comment">#</span> One is falsy and the other truthy.</span>
<span class="line-numbers"> 425 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">false</span> <span class="Keyword">if</span> (<span class="Keyword">!</span>a <span class="Keyword">and</span> b) <span class="Keyword">or</span> (a <span class="Keyword">and</span> <span class="Keyword">!</span>b)
<span class="line-numbers"> 426 </span> <span class="Comment"><span class="Comment">#</span> One of them implements an isEqual()?</span>
<span class="line-numbers"> 427 </span> <span class="Keyword">return</span> a.isEqual(b) <span class="Keyword">if</span> a.isEqual
<span class="line-numbers"> 428 </span> <span class="Comment"><span class="Comment">#</span> Check dates' integer values.</span>
<span class="line-numbers"> 429 </span> <span class="Keyword">return</span> a.getTime() <span class="Keyword">is</span> b.getTime() <span class="Keyword">if</span> _.isDate(a) <span class="Keyword">and</span> _.isDate(b)
<span class="line-numbers"> 430 </span> <span class="Comment"><span class="Comment">#</span> Both are NaN?</span>
<span class="line-numbers"> 431 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">true</span> <span class="Keyword">if</span> _.isNaN(a) <span class="Keyword">and</span> _.isNaN(b)
<span class="line-numbers"> 432 </span> <span class="Comment"><span class="Comment">#</span> Compare regular expressions.</span>
<span class="line-numbers"> 433 </span> <span class="Keyword">if</span> _.isRegExp(a) <span class="Keyword">and</span> _.isRegExp(b)
<span class="line-numbers"> 434 </span> <span class="Keyword">return</span> a.source <span class="Keyword">is</span> b.source <span class="Keyword">and</span>
<span class="line-numbers"> 435 </span> a.global <span class="Keyword">is</span> b.global <span class="Keyword">and</span>
<span class="line-numbers"> 436 </span> a.ignoreCase <span class="Keyword">is</span> b.ignoreCase <span class="Keyword">and</span>
<span class="line-numbers"> 437 </span> a.multiline <span class="Keyword">is</span> b.multiline
<span class="line-numbers"> 438 </span> <span class="Comment"><span class="Comment">#</span> If a is not an object by this point, we can't handle it.</span>
<span class="line-numbers"> 439 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">false</span> <span class="Keyword">if</span> atype <span class="Keyword">isnt</span> <span class="String"><span class="String">'</span>object<span class="String">'</span></span>
<span class="line-numbers"> 440 </span> <span class="Comment"><span class="Comment">#</span> Check for different array lengths before comparing contents.</span>
<span class="line-numbers"> 441 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">false</span> <span class="Keyword">if</span> a.length <span class="Keyword">and</span> (a.length <span class="Keyword">isnt</span> b.length)
<span class="line-numbers"> 442 </span> <span class="Comment"><span class="Comment">#</span> Nothing else worked, deep compare the contents.</span>
<span class="line-numbers"> 443 </span> <span class="FunctionName">aKeys</span><span class="Keyword">:</span> _.keys(a); <span class="FunctionName">bKeys</span><span class="Keyword">:</span> _.keys(b)
<span class="line-numbers"> 444 </span> <span class="Comment"><span class="Comment">#</span> Different object sizes?</span>
<span class="line-numbers"> 445 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">false</span> <span class="Keyword">if</span> aKeys.length <span class="Keyword">isnt</span> bKeys.length
<span class="line-numbers"> 446 </span> <span class="Comment"><span class="Comment">#</span> Recursive comparison of contents.</span>
<span class="line-numbers"> 447 </span> <span class="Comment"><span class="Comment">#</span> for (var key in a) if (!_.isEqual(a[key], b[key])) return false;</span>
<span class="line-numbers"> 448 </span> <span class="Keyword">return</span> <span class="BuiltInConstant">true</span>
<span class="line-numbers"> 449 </span>
<span class="line-numbers"> 450 </span>
<span class="line-numbers"> 451 </span> <span class="Comment"><span class="Comment">#</span> Is a given array or object empty?</span>
<span class="line-numbers"> 452 </span> <span class="FunctionName">_.isEmpty</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> _.keys(obj).length <span class="Keyword">is</span> <span class="Number">0</span>
<span class="line-numbers"> 453 </span>
<span class="line-numbers"> 454 </span>
<span class="line-numbers"> 455 </span> <span class="Comment"><span class="Comment">#</span> Is a given value a DOM element?</span>
<span class="line-numbers"> 456 </span> <span class="FunctionName">_.isElement</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> obj <span class="Keyword">and</span> obj.nodeType <span class="Keyword">is</span> <span class="Number">1</span>
<span class="line-numbers"> 457 </span>
<span class="line-numbers"> 458 </span>
<span class="line-numbers"> 459 </span> <span class="Comment"><span class="Comment">#</span> Is a given value an array?</span>
<span class="line-numbers"> 460 </span> <span class="FunctionName">_.isArray</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">!</span><span class="Keyword">!</span>(obj <span class="Keyword">and</span> obj.concat <span class="Keyword">and</span> obj.unshift)
<span class="line-numbers"> 461 </span>
<span class="line-numbers"> 462 </span>
<span class="line-numbers"> 463 </span> <span class="Comment"><span class="Comment">#</span> Is a given variable an arguments object?</span>
<span class="line-numbers"> 464 </span> <span class="FunctionName">_.isArguments</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> obj <span class="Keyword">and</span> _.isNumber(obj.length) <span class="Keyword">and</span> <span class="Keyword">not</span> obj.concat <span class="Keyword">and</span>
<span class="line-numbers"> 465 </span> <span class="Keyword">not</span> obj.substr <span class="Keyword">and</span> <span class="Keyword">not</span> obj.apply <span class="Keyword">and</span> <span class="Keyword">not</span> propertyIsEnumerable.call(obj, <span class="String"><span class="String">'</span>length<span class="String">'</span></span>)
<span class="line-numbers"> 466 </span>
<span class="line-numbers"> 467 </span>
<span class="line-numbers"> 468 </span> <span class="Comment"><span class="Comment">#</span> Is the given value a function?</span>
<span class="line-numbers"> 469 </span> <span class="FunctionName">_.isFunction</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">!</span><span class="Keyword">!</span>(obj <span class="Keyword">and</span> obj.constructor <span class="Keyword">and</span> obj.call <span class="Keyword">and</span> obj.apply)
<span class="line-numbers"> 470 </span>
<span class="line-numbers"> 471 </span>
<span class="line-numbers"> 472 </span> <span class="Comment"><span class="Comment">#</span> Is the given value a string?</span>
<span class="line-numbers"> 473 </span> <span class="FunctionName">_.isString</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">!</span><span class="Keyword">!</span>(obj <span class="Keyword">is</span> <span class="String"><span class="String">'</span><span class="String">'</span></span> <span class="Keyword">or</span> (obj <span class="Keyword">and</span> obj.charCodeAt <span class="Keyword">and</span> obj.substr))
<span class="line-numbers"> 474 </span>
<span class="line-numbers"> 475 </span>
<span class="line-numbers"> 476 </span> <span class="Comment"><span class="Comment">#</span> Is a given value a number?</span>
<span class="line-numbers"> 477 </span> <span class="FunctionName">_.isNumber</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> (obj <span class="Keyword">is</span> <span class="Keyword">+</span>obj) <span class="Keyword">or</span> toString.call(obj) <span class="Keyword">is</span> <span class="String"><span class="String">'</span>[object Number]<span class="String">'</span></span>
<span class="line-numbers"> 478 </span>
<span class="line-numbers"> 479 </span>
<span class="line-numbers"> 480 </span> <span class="Comment"><span class="Comment">#</span> Is a given value a Date?</span>
<span class="line-numbers"> 481 </span> <span class="FunctionName">_.isDate</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">!</span><span class="Keyword">!</span>(obj <span class="Keyword">and</span> obj.getTimezoneOffset <span class="Keyword">and</span> obj.setUTCFullYear)
<span class="line-numbers"> 482 </span>
<span class="line-numbers"> 483 </span>
<span class="line-numbers"> 484 </span> <span class="Comment"><span class="Comment">#</span> Is the given value a regular expression?</span>
<span class="line-numbers"> 485 </span> <span class="FunctionName">_.isRegExp</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">!</span><span class="Keyword">!</span>(obj <span class="Keyword">and</span> obj.exec <span class="Keyword">and</span> (obj.ignoreCase <span class="Keyword">or</span> obj.ignoreCase <span class="Keyword">is</span> <span class="BuiltInConstant">false</span>))
<span class="line-numbers"> 486 </span>
<span class="line-numbers"> 487 </span>
<span class="line-numbers"> 488 </span> <span class="Comment"><span class="Comment">#</span> Is the given value NaN -- this one is interesting. NaN != NaN, and</span>
<span class="line-numbers"> 489 </span> <span class="Comment"><span class="Comment">#</span> isNaN(undefined) == true, so we make sure it's a number first.</span>
<span class="line-numbers"> 490 </span> <span class="FunctionName">_.isNaN</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> _.isNumber(obj) <span class="Keyword">and</span> window.isNaN(obj)
<span class="line-numbers"> 491 </span>
<span class="line-numbers"> 492 </span>
<span class="line-numbers"> 493 </span> <span class="Comment"><span class="Comment">#</span> Is a given value equal to null?</span>
<span class="line-numbers"> 494 </span> <span class="FunctionName">_.isNull</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> obj <span class="Keyword">is</span> <span class="BuiltInConstant">null</span>
<span class="line-numbers"> 495 </span>
<span class="line-numbers"> 496 </span>
<span class="line-numbers"> 497 </span> <span class="Comment"><span class="Comment">#</span> Is a given variable undefined?</span>
<span class="line-numbers"> 498 </span> <span class="FunctionName">_.isUndefined</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> <span class="Keyword">typeof</span> obj <span class="Keyword">is</span> <span class="String"><span class="String">'</span>undefined<span class="String">'</span></span>
<span class="line-numbers"> 499 </span>
<span class="line-numbers"> 500 </span>
<span class="line-numbers"> 501 </span> <span class="Comment"><span class="Comment">#</span> -------------------------- Utility Functions: --------------------------</span>
<span class="line-numbers"> 502 </span>
<span class="line-numbers"> 503 </span> <span class="Comment"><span class="Comment">#</span> Run Underscore.js in noConflict mode, returning the '_' variable to its</span>
<span class="line-numbers"> 504 </span> <span class="Comment"><span class="Comment">#</span> previous owner. Returns a reference to the Underscore object.</span>
<span class="line-numbers"> 505 </span> <span class="FunctionName">_.noConflict</span><span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 506 </span> <span class="FunctionName">root._</span><span class="Keyword">:</span> previousUnderscore
<span class="line-numbers"> 507 </span> <span class="Variable">this</span>
<span class="line-numbers"> 508 </span>
<span class="line-numbers"> 509 </span>
<span class="line-numbers"> 510 </span> <span class="Comment"><span class="Comment">#</span> Keep the identity function around for default iterators.</span>
<span class="line-numbers"> 511 </span> <span class="FunctionName">_.identity</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">value</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span> value
<span class="line-numbers"> 512 </span>
<span class="line-numbers"> 513 </span>
<span class="line-numbers"> 514 </span> <span class="Comment"><span class="Comment">#</span> Break out of the middle of an iteration.</span>
<span class="line-numbers"> 515 </span> <span class="FunctionName">_.breakLoop</span><span class="Keyword">:</span> <span class="Storage">-&gt;</span> <span class="Keyword">throw</span> breaker
<span class="line-numbers"> 516 </span>
<span class="line-numbers"> 517 </span>
<span class="line-numbers"> 518 </span> <span class="Comment"><span class="Comment">#</span> Generate a unique integer id (unique within the entire client session).</span>
<span class="line-numbers"> 519 </span> <span class="Comment"><span class="Comment">#</span> Useful for temporary DOM ids.</span>
<span class="line-numbers"> 520 </span> <span class="FunctionName">idCounter</span><span class="Keyword">:</span> <span class="Number">0</span>
<span class="line-numbers"> 521 </span> <span class="FunctionName">_.uniqueId</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">prefix</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 522 </span> (prefix <span class="Keyword">or</span> <span class="String"><span class="String">'</span><span class="String">'</span></span>) <span class="Keyword">+</span> idCounter<span class="Keyword">++</span>
<span class="line-numbers"> 523 </span>
<span class="line-numbers"> 524 </span>
<span class="line-numbers"> 525 </span> <span class="Comment"><span class="Comment">#</span> By default, Underscore uses ERB-style template delimiters, change the</span>
<span class="line-numbers"> 526 </span> <span class="Comment"><span class="Comment">#</span> following template settings to use alternative delimiters.</span>
<span class="line-numbers"> 527 </span> <span class="FunctionName">_.templateSettings</span><span class="Keyword">:</span> {
<span class="line-numbers"> 528 </span> <span class="FunctionName">start</span><span class="Keyword">:</span> <span class="String"><span class="String">'</span>&lt;%<span class="String">'</span></span>
<span class="line-numbers"> 529 </span> <span class="FunctionName">end</span><span class="Keyword">:</span> <span class="String"><span class="String">'</span>%&gt;<span class="String">'</span></span>
<span class="line-numbers"> 530 </span> <span class="FunctionName">interpolate</span><span class="Keyword">:</span><span class="String"> <span class="String">/</span>&lt;%=(.+?)%&gt;<span class="String">/</span>g</span>
<span class="line-numbers"> 531 </span> }
<span class="line-numbers"> 532 </span>
<span class="line-numbers"> 533 </span>
<span class="line-numbers"> 534 </span> <span class="Comment"><span class="Comment">#</span> JavaScript templating a-la ERB, pilfered from John Resig's</span>
<span class="line-numbers"> 535 </span> <span class="Comment"><span class="Comment">#</span> &quot;Secrets of the JavaScript Ninja&quot;, page 83.</span>
<span class="line-numbers"> 536 </span> <span class="Comment"><span class="Comment">#</span> Single-quote fix from Rick Strahl's version.</span>
<span class="line-numbers"> 537 </span> <span class="FunctionName">_.template</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">str, data</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 538 </span> <span class="FunctionName">c</span><span class="Keyword">:</span> _.templateSettings
<span class="line-numbers"> 539 </span> <span class="FunctionName">fn</span><span class="Keyword">:</span> <span class="Keyword">new</span> <span class="TypeName">Function</span> <span class="String"><span class="String">'</span>obj<span class="String">'</span></span>,
<span class="line-numbers"> 540 </span> <span class="String"><span class="String">'</span>var p=[],print=function(){p.push.apply(p,arguments);};<span class="String">'</span></span> <span class="Keyword">+</span>
<span class="line-numbers"> 541 </span> <span class="String"><span class="String">'</span>with(obj){p.push(<span class="UserDefinedConstant">\'</span><span class="String">'</span></span> <span class="Keyword">+</span>
<span class="line-numbers"> 542 </span> str.replace(<span class="String"><span class="String">/</span>[<span class="UserDefinedConstant">\r</span><span class="UserDefinedConstant">\t</span><span class="UserDefinedConstant">\n</span>]<span class="String">/</span>g</span>, <span class="String"><span class="String">&quot;</span> <span class="String">&quot;</span></span>)
<span class="line-numbers"> 543 </span> .replace(<span class="Keyword">new</span> <span class="TypeName">RegExp</span>(<span class="String"><span class="String">&quot;</span>'(?=[^<span class="String">&quot;</span></span><span class="Keyword">+</span>c.end[<span class="Number">0</span>]<span class="Keyword">+</span><span class="String"><span class="String">&quot;</span>]*<span class="String">&quot;</span></span><span class="Keyword">+</span>c.end<span class="Keyword">+</span><span class="String"><span class="String">&quot;</span>)<span class="String">&quot;</span></span>,<span class="String"><span class="String">&quot;</span>g<span class="String">&quot;</span></span>),<span class="String"><span class="String">&quot;</span><span class="UserDefinedConstant">\t</span><span class="String">&quot;</span></span>)
<span class="line-numbers"> 544 </span> .split(<span class="String"><span class="String">&quot;</span>'<span class="String">&quot;</span></span>).join(<span class="String"><span class="String">&quot;</span><span class="UserDefinedConstant">\\</span>'<span class="String">&quot;</span></span>)
<span class="line-numbers"> 545 </span> .split(<span class="String"><span class="String">&quot;</span><span class="UserDefinedConstant">\t</span><span class="String">&quot;</span></span>).join(<span class="String"><span class="String">&quot;</span>'<span class="String">&quot;</span></span>)
<span class="line-numbers"> 546 </span> .replace(c.interpolate, <span class="String"><span class="String">&quot;</span>',$1,'<span class="String">&quot;</span></span>)
<span class="line-numbers"> 547 </span> .split(c.start).join(<span class="String"><span class="String">&quot;</span>');<span class="String">&quot;</span></span>)
<span class="line-numbers"> 548 </span> .split(c.end).join(<span class="String"><span class="String">&quot;</span>p.push('<span class="String">&quot;</span></span>) <span class="Keyword">+</span>
<span class="line-numbers"> 549 </span> <span class="String"><span class="String">&quot;</span>');}return p.join('');<span class="String">&quot;</span></span>
<span class="line-numbers"> 550 </span> <span class="Keyword">if</span> data <span class="Keyword">then</span> fn(data) <span class="Keyword">else</span> fn
<span class="line-numbers"> 551 </span>
<span class="line-numbers"> 552 </span>
<span class="line-numbers"> 553 </span> <span class="Comment"><span class="Comment">#</span> ------------------------------- Aliases ----------------------------------</span>
<span class="line-numbers"> 554 </span>
<span class="line-numbers"> 555 </span> <span class="FunctionName">_.forEach</span><span class="Keyword">:</span> _.each
<span class="line-numbers"> 556 </span> <span class="FunctionName">_.foldl</span><span class="Keyword">:</span> <span class="FunctionName">_.inject</span><span class="Keyword">:</span> _.reduce
<span class="line-numbers"> 557 </span> <span class="FunctionName">_.foldr</span><span class="Keyword">:</span> _.reduceRight
<span class="line-numbers"> 558 </span> <span class="FunctionName">_.filter</span><span class="Keyword">:</span> _.select
<span class="line-numbers"> 559 </span> <span class="FunctionName">_.every</span><span class="Keyword">:</span> _.all
<span class="line-numbers"> 560 </span> <span class="FunctionName">_.some</span><span class="Keyword">:</span> _.any
<span class="line-numbers"> 561 </span> <span class="FunctionName">_.head</span><span class="Keyword">:</span> _.first
<span class="line-numbers"> 562 </span> <span class="FunctionName">_.tail</span><span class="Keyword">:</span> _.rest
<span class="line-numbers"> 563 </span> <span class="FunctionName">_.methods</span><span class="Keyword">:</span> _.functions
<span class="line-numbers"> 564 </span>
<span class="line-numbers"> 565 </span>
<span class="line-numbers"> 566 </span> <span class="Comment"><span class="Comment">#</span> ------------------------ Setup the OOP Wrapper: --------------------------</span>
<span class="line-numbers"> 567 </span>
<span class="line-numbers"> 568 </span> <span class="Comment"><span class="Comment">#</span> Helper function to continue chaining intermediate results.</span>
<span class="line-numbers"> 569 </span> <span class="FunctionName">result</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">obj, chain</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 570 </span> <span class="Keyword">if</span> chain <span class="Keyword">then</span> _(obj).chain() <span class="Keyword">else</span> obj
<span class="line-numbers"> 571 </span>
<span class="line-numbers"> 572 </span>
<span class="line-numbers"> 573 </span> <span class="Comment"><span class="Comment">#</span> Add all of the Underscore functions to the wrapper object.</span>
<span class="line-numbers"> 574 </span> _.each _.functions(_), <span class="FunctionArgument">(</span><span class="FunctionArgument">name</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 575 </span> <span class="FunctionName">method</span><span class="Keyword">:</span> _[name]
<span class="line-numbers"> 576 </span> wrapper.prototype[name]<span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 577 </span> unshift.call(arguments, <span class="Variable">this</span>._wrapped)
<span class="line-numbers"> 578 </span> result(method.apply(_, arguments), <span class="Variable">this</span>._chain)
<span class="line-numbers"> 579 </span>
<span class="line-numbers"> 580 </span>
<span class="line-numbers"> 581 </span> <span class="Comment"><span class="Comment">#</span> Add all mutator Array functions to the wrapper.</span>
<span class="line-numbers"> 582 </span> _.each [<span class="String"><span class="String">'</span>pop<span class="String">'</span></span>, <span class="String"><span class="String">'</span>push<span class="String">'</span></span>, <span class="String"><span class="String">'</span>reverse<span class="String">'</span></span>, <span class="String"><span class="String">'</span>shift<span class="String">'</span></span>, <span class="String"><span class="String">'</span>sort<span class="String">'</span></span>, <span class="String"><span class="String">'</span>splice<span class="String">'</span></span>, <span class="String"><span class="String">'</span>unshift<span class="String">'</span></span>], <span class="FunctionArgument">(</span><span class="FunctionArgument">name</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 583 </span> <span class="FunctionName">method</span><span class="Keyword">:</span> Array.prototype[name]
<span class="line-numbers"> 584 </span> wrapper.prototype[name]<span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 585 </span> method.apply(<span class="Variable">this</span>._wrapped, arguments)
<span class="line-numbers"> 586 </span> result(<span class="Variable">this</span>._wrapped, <span class="Variable">this</span>._chain)
<span class="line-numbers"> 587 </span>
<span class="line-numbers"> 588 </span>
<span class="line-numbers"> 589 </span> <span class="Comment"><span class="Comment">#</span> Add all accessor Array functions to the wrapper.</span>
<span class="line-numbers"> 590 </span> _.each [<span class="String"><span class="String">'</span>concat<span class="String">'</span></span>, <span class="String"><span class="String">'</span>join<span class="String">'</span></span>, <span class="String"><span class="String">'</span>slice<span class="String">'</span></span>], <span class="FunctionArgument">(</span><span class="FunctionArgument">name</span><span class="FunctionArgument">)</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 591 </span> <span class="FunctionName">method</span><span class="Keyword">:</span> Array.prototype[name]
<span class="line-numbers"> 592 </span> wrapper.prototype[name]<span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 593 </span> result(method.apply(<span class="Variable">this</span>._wrapped, arguments), <span class="Variable">this</span>._chain)
<span class="line-numbers"> 594 </span>
<span class="line-numbers"> 595 </span>
<span class="line-numbers"> 596 </span> <span class="Comment"><span class="Comment">#</span> Start chaining a wrapped Underscore object.</span>
<span class="line-numbers"> 597 </span> <span class="FunctionName">wrapper::chain</span><span class="Keyword">:</span> <span class="Storage">-&gt;</span>
<span class="line-numbers"> 598 </span> <span class="FunctionName">this._chain</span><span class="Keyword">:</span> <span class="BuiltInConstant">true</span>
<span class="line-numbers"> 599 </span> <span class="Variable">this</span>
<span class="line-numbers"> 600 </span>
<span class="line-numbers"> 601 </span>
<span class="line-numbers"> 602 </span> <span class="Comment"><span class="Comment">#</span> Extracts the result from a wrapped and chained object.</span>
<span class="line-numbers"> 603 </span> <span class="FunctionName">wrapper::value</span><span class="Keyword">:</span> <span class="Storage">-&gt;</span> <span class="Variable">this</span>._wrapped
</pre> <p>
<a href="http://validator.w3.org/check?uri=referer">
<img style="border:0"
src="http://www.w3.org/Icons/valid-xhtml10"
alt="Valid XHTML 1.0 Strict" height="31" width="88" />
</a>
<a href="http://jigsaw.w3.org/css-validator/check?uri=referer">
<img style="border:0;width:88px;height:31px"
src="http://jigsaw.w3.org/css-validator/images/vcss"
alt="Valid CSS!" />
</a>
</p>
</body>
</html>

View File

@@ -140,24 +140,28 @@ sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad."
# Inheritance and calling super.
Animal: ->
Animal::move: (meters) ->
alert(this.name + " moved " + meters + "m.")
class Animal
move: (meters) ->
alert this.name + " moved " + meters + "m."
Snake: (name) -> this.name: name
Snake extends Animal
Snake::move: ->
alert('Slithering...')
super(5)
class Snake extends Animal
constructor: (name) ->
@name: name
Horse: (name) -> this.name: name
Horse extends Animal
Horse::move: ->
alert('Galloping...')
super(45)
move: ->
alert 'Slithering...'
super 5
sam: new Snake("Sammy the Snake")
tom: new Horse("Tommy the Horse")
class Horse extends Animal
constructor: (name) ->
@name: name
move: ->
alert 'Galloping...'
super 45
sam: new Snake "Sammy the Snake"
tom: new Horse "Tommy the Horse"
sam.move()
tom.move()

View File

@@ -1,90 +1,92 @@
# "Classic" linked list implementation that doesn't keep track of its size.
LinkedList: ->
this._head: null # Pointer to the first item in the list.
class LinkedList
constructor: ->
this._head: null # Pointer to the first item in the list.
# Appends some data to the end of the list. This method traverses the existing
# list and places the value at the end in a new node.
LinkedList::add: (data) ->
# Appends some data to the end of the list. This method traverses the existing
# list and places the value at the end in a new node.
add: (data) ->
# Create a new node object to wrap the data.
node: {data: data, next: null}
# Create a new node object to wrap the data.
node: {data: data, next: null}
current: this._head ||= node
current: this._head ||= node
if this._head isnt node
current: current.next while current.next
current.next: node
if this._head isnt node
current: current.next while current.next
current.next: node
this
this
# Retrieves the data at the given position in the list.
LinkedList::item: (index) ->
# Retrieves the data at the given position in the list.
item: (index) ->
# Check for out-of-bounds values.
return null if index < 0
# Check for out-of-bounds values.
return null if index < 0
current: this._head or null
i: -1
current: this._head or null
i: -1
# Advance through the list.
current: current.next while current and index > (i += 1)
# Advance through the list.
current: current.next while current and index > (i += 1)
# Return null if we've reached the end.
current and current.data
# Return null if we've reached the end.
current and current.data
# Remove the item from the given location in the list.
LinkedList::remove: (index) ->
# Remove the item from the given location in the list.
remove: (index) ->
# Check for out-of-bounds values.
return null if index < 0
# Check for out-of-bounds values.
return null if index < 0
current: this._head or null
i: -1
current: this._head or null
i: -1
# Special case: removing the first item.
if index is 0
this._head: current.next
else
# Special case: removing the first item.
if index is 0
this._head: current.next
else
# Find the right location.
[previous, current]: [current, current.next] while index > (i += 1)
# Find the right location.
[previous, current]: [current, current.next] while index > (i += 1)
# Skip over the item to remove.
previous.next: current.next
# Skip over the item to remove.
previous.next: current.next
# Return the value.
current and current.data
# Return the value.
current and current.data
# Calculate the number of items in the list.
LinkedList::size: ->
current: this._head
count: 0
# Calculate the number of items in the list.
size: ->
current: this._head
count: 0
while current
count += 1
current: current.next
while current
count += 1
current: current.next
count
count
# Convert the list into an array.
LinkedList::toArray: ->
result: []
current: this._head
# Convert the list into an array.
toArray: ->
result: []
current: this._head
while current
result.push(current.data)
current: current.next
while current
result.push(current.data)
current: current.next
result
result
# The string representation of the linked list.
LinkedList::toString: -> this.toArray().toString()
# The string representation of the linked list.
toString: -> this.toArray().toString()
# Tests.

View File

@@ -53,16 +53,16 @@ for key, val of {dog: 'canine', cat: 'feline', fox: 'vulpine'}
# Person print = ():
# ('My name is ', /name, '.') join print.
Person: ->
Person::print: ->
print('My name is ' + this.name + '.')
class Person
print: ->
print 'My name is ' + this.name + '.'
# p = Person ()
# p /name string print
p: new Person()
print(p.name)
print p.name
# Policeman = Person class (rank): /rank = rank.
@@ -71,12 +71,13 @@ print(p.name)
#
# Policeman ('Constable') print
Policeman: (rank) -> this.rank: rank
Policeman extends Person
Policeman::print: ->
print('My name is ' + this.name + " and I'm a " + this.rank + '.')
class Policeman extends Person
constructor: (rank) ->
@rank: rank
print: ->
print 'My name is ' + this.name + " and I'm a " + this.rank + '.'
print(new Policeman('Constable'))
print new Policeman 'Constable'
# app = [window (width=200, height=400)

View File

@@ -1,96 +1,122 @@
# Underscore.coffee
# (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
# Underscore is freely distributable under the terms of the MIT license.
# Portions of Underscore are inspired by or borrowed from Prototype.js,
# Oliver Steele's Functional, and John Resig's Micro-Templating.
# **Underscore.coffee
# (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.**
# Underscore is freely distributable under the terms of the
# [MIT license](http://en.wikipedia.org/wiki/MIT_License).
# Portions of Underscore are inspired by or borrowed from
# [Prototype.js](http://prototypejs.org/api), Oliver Steele's
# [Functional](http://osteele.com), and John Resig's
# [Micro-Templating](http://ejohn.com).
# For all details and documentation:
# http://documentcloud.github.com/underscore/
# ------------------------- Baseline setup ---------------------------------
# Baseline setup
# --------------
# Establish the root object, "window" in the browser, or "global" on the server.
# Establish the root object, `window` in the browser, or `global` on the server.
root: this
# Save the previous value of the "_" variable.
# Save the previous value of the `_` variable.
previousUnderscore: root._
# If Underscore is called as a function, it returns a wrapped object that
# can be used OO-style. This wrapper holds altered versions of all the
# underscore functions. Wrapped objects may be chained.
wrapper: (obj) ->
this._wrapped: obj
this
# Establish the object that gets thrown to break out of a loop iteration.
# `StopIteration` is SOP on Mozilla.
breaker: if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
# Create a safe reference to the Underscore object forreference below.
_: root._: (obj) -> new wrapper(obj)
# Helper function to escape **RegExp** contents, because JS doesn't have one.
escapeRegExp: (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1')
# Export the Underscore object for CommonJS.
if typeof(exports) != 'undefined' then exports._: _
# Save bytes in the minified (but not gzipped) version:
ArrayProto: Array.prototype
ObjProto: Object.prototype
# Create quick reference variables for speed access to core prototypes.
slice: Array::slice
unshift: Array::unshift
toString: Object::toString
hasOwnProperty: Object::hasOwnProperty
propertyIsEnumerable: Object::propertyIsEnumerable
slice: ArrayProto.slice
unshift: ArrayProto.unshift
toString: ObjProto.toString
hasOwnProperty: ObjProto.hasOwnProperty
propertyIsEnumerable: ObjProto.propertyIsEnumerable
# All **ECMA5** native implementations we hope to use are declared here.
nativeForEach: ArrayProto.forEach
nativeMap: ArrayProto.map
nativeReduce: ArrayProto.reduce
nativeReduceRight: ArrayProto.reduceRight
nativeFilter: ArrayProto.filter
nativeEvery: ArrayProto.every
nativeSome: ArrayProto.some
nativeIndexOf: ArrayProto.indexOf
nativeLastIndexOf: ArrayProto.lastIndexOf
nativeIsArray: Array.isArray
nativeKeys: Object.keys
# Create a safe reference to the Underscore object for use below.
_: (obj) -> new wrapper(obj)
# Export the Underscore object for **CommonJS**.
if typeof(exports) != 'undefined' then exports._: _
# Export Underscore to global scope.
root._: _
# Current version.
_.VERSION: '0.5.8'
_.VERSION: '1.0.2'
# ------------------------ Collection Functions: ---------------------------
# Collection Functions
# --------------------
# The cornerstone, an each implementation.
# Handles objects implementing forEach, arrays, and raw objects.
# The cornerstone, an **each** implementation.
# Handles objects implementing **forEach**, arrays, and raw objects.
_.each: (obj, iterator, context) ->
index: 0
try
return obj.forEach(iterator, context) if obj.forEach
if _.isNumber(obj.length)
return iterator.call(context, obj[i], i, obj) for i in [0...obj.length]
iterator.call(context, val, key, obj) for key, val of obj
if nativeForEach and obj.forEach is nativeForEach
obj.forEach iterator, context
else if _.isNumber obj.length
iterator.call(context, obj[i], i, obj) for i in [0...obj.length]
else
iterator.call(context, val, key, obj) for key, val of obj
catch e
throw e if e isnt breaker
obj
# Return the results of applying the iterator to each element. Use JavaScript
# 1.6's version of map, if possible.
# 1.6's version of **map**, if possible.
_.map: (obj, iterator, context) ->
return obj.map(iterator, context) if (obj and _.isFunction(obj.map))
return obj.map(iterator, context) if nativeMap and obj.map is nativeMap
results: []
_.each obj, (value, index, list) ->
results.push(iterator.call(context, value, index, list))
results.push iterator.call context, value, index, list
results
# Reduce builds up a single result from a list of values. Also known as
# inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
# **Reduce** builds up a single result from a list of values. Also known as
# **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible.
_.reduce: (obj, memo, iterator, context) ->
return obj.reduce(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduce))
return obj.reduce(_.bind(iterator, context), memo) if nativeReduce and obj.reduce is nativeReduce
_.each obj, (value, index, list) ->
memo: iterator.call(context, memo, value, index, list)
memo: iterator.call context, memo, value, index, list
memo
# The right-associative version of reduce, also known as foldr. Uses
# JavaScript 1.8's version of reduceRight, if available.
# The right-associative version of **reduce**, also known as **foldr**. Uses
# JavaScript 1.8's version of **reduceRight**, if available.
_.reduceRight: (obj, memo, iterator, context) ->
return obj.reduceRight(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduceRight))
return obj.reduceRight(_.bind(iterator, context), memo) if nativeReduceRight and obj.reduceRight is nativeReduceRight
_.each _.clone(_.toArray(obj)).reverse(), (value, index) ->
memo: iterator.call(context, memo, value, index, obj)
memo: iterator.call context, memo, value, index, obj
memo
@@ -98,19 +124,19 @@
_.detect: (obj, iterator, context) ->
result: null
_.each obj, (value, index, list) ->
if iterator.call(context, value, index, list)
if iterator.call context, value, index, list
result: value
_.breakLoop()
result
# Return all the elements that pass a truth test. Use JavaScript 1.6's
# filter(), if it exists.
_.select: (obj, iterator, context) ->
if obj and _.isFunction(obj.filter) then return obj.filter(iterator, context)
# **filter**, if it exists.
_.filter: (obj, iterator, context) ->
return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter
results: []
_.each obj, (value, index, list) ->
results.push(value) if iterator.call(context, value, index, list)
results.push value if iterator.call context, value, index, list
results
@@ -118,15 +144,15 @@
_.reject: (obj, iterator, context) ->
results: []
_.each obj, (value, index, list) ->
results.push(value) if not iterator.call(context, value, index, list)
results.push value if not iterator.call context, value, index, list
results
# Determine whether all of the elements match a truth test. Delegate to
# JavaScript 1.6's every(), if it is present.
_.all: (obj, iterator, context) ->
# JavaScript 1.6's **every**, if it is present.
_.every: (obj, iterator, context) ->
iterator ||= _.identity
return obj.every(iterator, context) if obj and _.isFunction(obj.every)
return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
result: true
_.each obj, (value, index, list) ->
_.breakLoop() unless (result: result and iterator.call(context, value, index, list))
@@ -134,10 +160,10 @@
# Determine if at least one element in the object matches a truth test. Use
# JavaScript 1.6's some(), if it exists.
_.any: (obj, iterator, context) ->
# JavaScript 1.6's **some**, if it exists.
_.some: (obj, iterator, context) ->
iterator ||= _.identity
return obj.some(iterator, context) if obj and _.isFunction(obj.some)
return obj.some iterator, context if nativeSome and obj.some is nativeSome
result: false
_.each obj, (value, index, list) ->
_.breakLoop() if (result: iterator.call(context, value, index, list))
@@ -145,9 +171,9 @@
# Determine if a given value is included in the array or object,
# based on '==='.
# based on `===`.
_.include: (obj, target) ->
return _.indexOf(obj, target) isnt -1 if obj and _.isFunction(obj.indexOf)
return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
for key, val of obj
return true if val is target
false
@@ -155,13 +181,13 @@
# Invoke a method with arguments on every item in a collection.
_.invoke: (obj, method) ->
args: _.rest(arguments, 2)
args: _.rest arguments, 2
(if method then val[method] else val).apply(val, args) for val in obj
# Convenience version of a common use case of map: fetching a property.
# Convenience version of a common use case of **map**: fetching a property.
_.pluck: (obj, key) ->
_.map(obj, ((val) -> val[key]))
_.map(obj, (val) -> val[key])
# Return the maximum item or (item-based computation).
@@ -184,7 +210,7 @@
result.value
# Sort the object's values by a criteria produced by an iterator.
# Sort the object's values by a criterion produced by an iterator.
_.sortBy: (obj, iterator, context) ->
_.pluck(((_.map obj, (value, index, list) ->
{value: value, criteria: iterator.call(context, value, index, list)}
@@ -198,7 +224,8 @@
# be inserted so as to maintain order. Uses binary search.
_.sortedIndex: (array, obj, iterator) ->
iterator ||= _.identity
low: 0; high: array.length
low: 0
high: array.length
while low < high
mid: (low + high) >> 1
if iterator(array[mid]) < iterator(obj) then low: mid + 1 else high: mid
@@ -218,19 +245,20 @@
_.size: (obj) -> _.toArray(obj).length
# -------------------------- Array Functions: ------------------------------
# Array Functions
# ---------------
# Get the first element of an array. Passing "n" will return the first N
# values in the array. Aliased as "head". The "guard" check allows it to work
# with _.map.
# Get the first element of an array. Passing `n` will return the first N
# values in the array. Aliased as **head**. The `guard` check allows it to work
# with **map**.
_.first: (array, n, guard) ->
if n and not guard then slice.call(array, 0, n) else array[0]
# Returns everything but the first entry of the array. Aliased as "tail".
# Especially useful on the arguments object. Passing an "index" will return
# the rest of the values in the array from that index onward. The "guard"
# check allows it to work with _.map.
# Returns everything but the first entry of the array. Aliased as **tail**.
# Especially useful on the arguments object. Passing an `index` will return
# the rest of the values in the array from that index onward. The `guard`
# check allows it to work with **map**.
_.rest: (array, index, guard) ->
slice.call(array, if _.isUndefined(index) or guard then 1 else index)
@@ -246,30 +274,30 @@
# Return a completely flattened version of an array.
_.flatten: (array) ->
_.reduce array, [], (memo, value) ->
return memo.concat(_.flatten(value)) if _.isArray(value)
memo.push(value)
return memo.concat(_.flatten(value)) if _.isArray value
memo.push value
memo
# Return a version of the array that does not contain the specified value(s).
_.without: (array) ->
values: _.rest(arguments)
val for val in _.toArray(array) when not _.include(values, val)
values: _.rest arguments
val for val in _.toArray(array) when not _.include values, val
# Produce a duplicate-free version of the array. If the array has already
# been sorted, you have the option of using a faster algorithm.
_.uniq: (array, isSorted) ->
memo: []
for el, i in _.toArray(array)
memo.push(el) if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
for el, i in _.toArray array
memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
memo
# Produce an array that contains every item shared between all the
# passed-in arrays.
_.intersect: (array) ->
rest: _.rest(arguments)
rest: _.rest arguments
_.select _.uniq(array), (item) ->
_.all rest, (other) ->
_.indexOf(other, item) >= 0
@@ -278,28 +306,28 @@
# Zip together multiple lists into a single array -- elements that share
# an index go together.
_.zip: ->
length: _.max(_.pluck(arguments, 'length'))
results: new Array(length)
length: _.max _.pluck arguments, 'length'
results: new Array length
for i in [0...length]
results[i]: _.pluck(arguments, String(i))
results[i]: _.pluck arguments, String i
results
# If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
# If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE),
# we need this function. Return the position of the first occurence of an
# item in an array, or -1 if the item is not included in the array.
_.indexOf: (array, item) ->
return array.indexOf(item) if array.indexOf
return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf
i: 0; l: array.length
while l - i
if array[i] is item then return i else i++
-1
# Provide JavaScript 1.6's lastIndexOf, delegating to the native function,
# Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function,
# if possible.
_.lastIndexOf: (array, item) ->
return array.lastIndexOf(item) if array.lastIndexOf
return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf
i: array.length
while i
if array[i] is item then return i else i--
@@ -307,8 +335,7 @@
# Generate an integer Array containing an arithmetic progression. A port of
# the native Python range() function. See:
# http://docs.python.org/library/functions.html#range
# [the native Python **range** function](http://docs.python.org/library/functions.html#range).
_.range: (start, stop, step) ->
a: arguments
solo: a.length <= 1
@@ -317,7 +344,7 @@
step: a[2] or 1
len: Math.ceil((stop - start) / step)
return [] if len <= 0
range: new Array(len)
range: new Array len
idx: 0
while true
return range if (if step > 0 then i - stop else stop - i) >= 0
@@ -326,41 +353,42 @@
i+= step
# ----------------------- Function Functions: -----------------------------
# Function Functions
# ------------------
# Create a function bound to a given object (assigning 'this', and arguments,
# optionally). Binding with arguments is also known as 'curry'.
# Create a function bound to a given object (assigning `this`, and arguments,
# optionally). Binding with arguments is also known as **curry**.
_.bind: (func, obj) ->
args: _.rest(arguments, 2)
-> func.apply(obj or root, args.concat(arguments))
args: _.rest arguments, 2
-> func.apply obj or root, args.concat arguments
# Bind all of an object's methods to that object. Useful for ensuring that
# all callbacks defined on an object belong to it.
_.bindAll: (obj) ->
funcs: if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
_.each(funcs, (f) -> obj[f]: _.bind(obj[f], obj))
_.each funcs, (f) -> obj[f]: _.bind obj[f], obj
obj
# Delays a function for the given number of milliseconds, and then calls
# it with the arguments supplied.
_.delay: (func, wait) ->
args: _.rest(arguments, 2)
args: _.rest arguments, 2
setTimeout((-> func.apply(func, args)), wait)
# Defers a function, scheduling it to run after the current call stack has
# cleared.
_.defer: (func) ->
_.delay.apply(_, [func, 1].concat(_.rest(arguments)))
_.delay.apply _, [func, 1].concat _.rest arguments
# Returns the first function passed as an argument to the second,
# allowing you to adjust arguments, run code before and after, and
# conditionally execute the original function.
_.wrap: (func, wrapper) ->
-> wrapper.apply(wrapper, [func].concat(arguments))
-> wrapper.apply wrapper, [func].concat arguments
# Returns a function that is the composition of a list of functions, each
@@ -374,41 +402,42 @@
args[0]
# ------------------------- Object Functions: ----------------------------
# Object Functions
# ----------------
# Retrieve the names of an object's properties.
_.keys: (obj) ->
return _.range(0, obj.length) if _.isArray(obj)
_.keys: nativeKeys or (obj) ->
return _.range 0, obj.length if _.isArray(obj)
key for key, val of obj
# Retrieve the values of an object's properties.
_.values: (obj) ->
_.map(obj, _.identity)
_.map obj, _.identity
# Return a sorted list of the function names available in Underscore.
_.functions: (obj) ->
_.select(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
_.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
# Extend a given object with all of the properties in a source object.
_.extend: (destination, source) ->
for key, val of source
destination[key]: val
destination
_.extend: (obj) ->
for source in _.rest(arguments)
(obj[key]: val) for key, val of source
obj
# Create a (shallow-cloned) duplicate of an object.
_.clone: (obj) ->
return obj.slice(0) if _.isArray(obj)
_.extend({}, obj)
return obj.slice 0 if _.isArray obj
_.extend {}, obj
# Invokes interceptor with the obj, and then returns obj.
# The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
_.tap: (obj, interceptor) ->
interceptor(obj)
interceptor obj
obj
@@ -423,7 +452,7 @@
return true if `a == b`
# One is falsy and the other truthy.
return false if (!a and b) or (a and !b)
# One of them implements an isEqual()?
# One of them implements an `isEqual()`?
return a.isEqual(b) if a.isEqual
# Check dates' integer values.
return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
@@ -444,12 +473,15 @@
# Different object sizes?
return false if aKeys.length isnt bKeys.length
# Recursive comparison of contents.
# for (var key in a) if (!_.isEqual(a[key], b[key])) return false;
return true
(return false) for key, val of a when !(key in b) or !_.isEqual(val, b[key])
true
# Is a given array or object empty?
_.isEmpty: (obj) -> _.keys(obj).length is 0
_.isEmpty: (obj) ->
return obj.length is 0 if _.isArray obj
(return false) for key of obj when hasOwnProperty.call(obj, key)
true
# Is a given value a DOM element?
@@ -457,12 +489,11 @@
# Is a given value an array?
_.isArray: (obj) -> !!(obj and obj.concat and obj.unshift)
_.isArray: nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)
# Is a given variable an arguments object?
_.isArguments: (obj) -> obj and _.isNumber(obj.length) and not obj.concat and
not obj.substr and not obj.apply and not propertyIsEnumerable.call(obj, 'length')
_.isArguments: (obj) -> obj and obj.callee
# Is the given value a function?
@@ -477,6 +508,10 @@
_.isNumber: (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
# Is a given value a boolean?
_.isBoolean: (obj) -> obj is true or obj is false
# Is a given value a Date?
_.isDate: (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
@@ -485,8 +520,8 @@
_.isRegExp: (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
# Is the given value NaN -- this one is interesting. NaN != NaN, and
# isNaN(undefined) == true, so we make sure it's a number first.
# Is the given value NaN -- this one is interesting. `NaN != NaN`, and
# `isNaN(undefined) == true`, so we make sure it's a number first.
_.isNaN: (obj) -> _.isNumber(obj) and window.isNaN(obj)
@@ -498,9 +533,10 @@
_.isUndefined: (obj) -> typeof obj is 'undefined'
# -------------------------- Utility Functions: --------------------------
# Utility Functions
# -----------------
# Run Underscore.js in noConflict mode, returning the '_' variable to its
# Run Underscore.js in noConflict mode, returning the `_` variable to its
# previous owner. Returns a reference to the Underscore object.
_.noConflict: ->
root._: previousUnderscore
@@ -511,10 +547,22 @@
_.identity: (value) -> value
# Run a function `n` times.
_.times: (n, iterator, context) ->
iterator.call(context, i) for i in [0...n]
# Break out of the middle of an iteration.
_.breakLoop: -> throw breaker
# Add your own custom functions to the Underscore object, ensuring that
# they're correctly added to the OOP wrapper as well.
_.mixin: (obj) ->
for name in _.functions(obj)
addToWrapper name, _[name]: obj[name]
# Generate a unique integer id (unique within the entire client session).
# Useful for temporary DOM ids.
idCounter: 0
@@ -522,7 +570,7 @@
(prefix or '') + idCounter++
# By default, Underscore uses ERB-style template delimiters, change the
# By default, Underscore uses **ERB**-style template delimiters, change the
# following template settings to use alternative delimiters.
_.templateSettings: {
start: '<%'
@@ -531,16 +579,17 @@
}
# JavaScript templating a-la ERB, pilfered from John Resig's
# "Secrets of the JavaScript Ninja", page 83.
# Single-quote fix from Rick Strahl's version.
# JavaScript templating a-la **ERB**, pilfered from John Resig's
# *Secrets of the JavaScript Ninja*, page 83.
# Single-quote fix from Rick Strahl.
_.template: (str, data) ->
c: _.templateSettings
endMatch: new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g")
fn: new Function 'obj',
'var p=[],print=function(){p.push.apply(p,arguments);};' +
'with(obj){p.push(\'' +
str.replace(/[\r\t\n]/g, " ")
.replace(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
.replace(endMatch,"\t")
.split("'").join("\\'")
.split("\t").join("'")
.replace(c.interpolate, "',$1,'")
@@ -550,32 +599,46 @@
if data then fn(data) else fn
# ------------------------------- Aliases ----------------------------------
# Aliases
# -------
_.forEach: _.each
_.foldl: _.inject: _.reduce
_.foldr: _.reduceRight
_.filter: _.select
_.every: _.all
_.some: _.any
_.select: _.filter
_.all: _.every
_.any: _.some
_.head: _.first
_.tail: _.rest
_.methods: _.functions
# ------------------------ Setup the OOP Wrapper: --------------------------
# Setup the OOP Wrapper
# ---------------------
# If Underscore is called as a function, it returns a wrapped object that
# can be used OO-style. This wrapper holds altered versions of all the
# underscore functions. Wrapped objects may be chained.
wrapper: (obj) ->
this._wrapped: obj
this
# Helper function to continue chaining intermediate results.
result: (obj, chain) ->
if chain then _(obj).chain() else obj
# Add all of the Underscore functions to the wrapper object.
_.each _.functions(_), (name) ->
method: _[name]
# A method to easily add functions to the OOP wrapper.
addToWrapper: (name, func) ->
wrapper.prototype[name]: ->
unshift.call(arguments, this._wrapped)
result(method.apply(_, arguments), this._chain)
args: _.toArray arguments
unshift.call args, this._wrapped
result func.apply(_, args), this._chain
# Add all of the Underscore functions to the wrapper object.
_.mixin _
# Add all mutator Array functions to the wrapper.

View File

@@ -1,12 +1,13 @@
# Contributed by Jason Huggins
sys: require 'sys'
http: require 'http'
server: http.createServer (req, res) ->
res.sendHeader 200, {'Content-Type': 'text/plain'}
res.sendBody 'Hello, World!'
res.finish()
res.writeHeader 200, {'Content-Type': 'text/plain'}
res.write 'Hello, World!'
res.close()
server.listen 3000
puts "Server running at http://localhost:3000/"
sys.puts "Server running at http://localhost:3000/"

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>comments</string>
<key>scope</key>
<string>source.coffee</string>
<key>settings</key>
<dict>
<key>shellVariables</key>
<array>
<dict>
<key>name</key>
<string>TM_COMMENT_START</string>
<key>value</key>
<string># </string>
</dict>
</array>
</dict>
<key>uuid</key>
<string>0A92C6F6-4D73-4859-B38C-4CC19CBC191F</string>
</dict>
</plist>

View File

@@ -1,361 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>comment</key>
<string>CoffeeScript Syntax: version 1</string>
<key>fileTypes</key>
<array>
<string>coffee</string>
</array>
<key>name</key>
<string>CoffeeScript</string>
<key>foldingStartMarker</key>
<string>^.*[:=] \{[^\}]*$</string>
<key>foldingStopMarker</key>
<string>\s*\}</string>
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>variable.parameter.function.coffee</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>variable.parameter.function.coffee</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>variable.parameter.function.coffee</string>
</dict>
<key>5</key>
<dict>
<key>name</key>
<string>storage.type.function.coffee</string>
</dict>
</dict>
<key>comment</key>
<string>match stuff like: a -&gt; … </string>
<key>match</key>
<string>(\()([a-zA-Z0-9_?.$]*(,\s*[a-zA-Z0-9_?.$]+)*)(\))\s*((=|-)&gt;)</string>
<key>name</key>
<string>meta.inline.function.coffee</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.operator.new.coffee</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>entity.name.type.instance.coffee</string>
</dict>
</dict>
<key>match</key>
<string>(new)\s+(\w+(?:\.\w*)?)</string>
<key>name</key>
<string>meta.class.instance.constructor</string>
</dict>
<dict>
<key>match</key>
<string>\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?))\b</string>
<key>name</key>
<string>constant.numeric.coffee</string>
</dict>
<dict>
<key>match</key>
<string>(@)([a-zA-Z_$]\w*)?</string>
<key>name</key>
<string>variable.other.readwrite.instance.coffee</string>
</dict>
<dict>
<key>name</key>
<string>string.quoted.heredoc.coffee</string>
<key>begin</key>
<string>("""|''')</string>
<key>end</key>
<string>("""|''')</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
</dict>
<dict>
<key>begin</key>
<string>'</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
<string>'</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.single.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
<string>"</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>`</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
<string>`</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.script.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.coffee</string>
</dict>
</dict>
<key>match</key>
<string>(#).*$\n?</string>
<key>name</key>
<string>comment.line.coffee</string>
</dict>
<dict>
<key>begin</key>
<string>(?&lt;=[=(:]|^|return)\s*(/)(?![/*+{}?])</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.coffee</string>
</dict>
</dict>
<key>end</key>
<string>(/)[igm]*</string>
<key>endCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.coffee</string>
</dict>
</dict>
<key>name</key>
<string>string.regexp.coffee</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escape.coffee</string>
</dict>
</array>
</dict>
<dict>
<key>match</key>
<string>\b(break|by|catch|continue|else|finally|for|in|of|if|return|switch|then|throw|try|unless|when|while)\b</string>
<key>name</key>
<string>keyword.control.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b([a-zA-Z$_](\w|\$|:|\.)*\s*(?=\:))</string>
<key>name</key>
<string>variable.assignment.coffee</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.name.function.coffee</string>
</dict>
</dict>
</dict>
<dict>
<key>match</key>
<string>\b(true|on|yes)\b</string>
<key>name</key>
<string>constant.language.boolean.true.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(false|off|no)\b</string>
<key>name</key>
<string>constant.language.boolean.false.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\bnull\b</string>
<key>name</key>
<string>constant.language.null.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(super|this|extends)\b</string>
<key>name</key>
<string>variable.language.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(debugger|\\)\b</string>
<key>name</key>
<string>keyword.other.coffee</string>
</dict>
<dict>
<key>match</key>
<string>(=|-)&gt;</string>
<key>name</key>
<string>storage.type.function.coffee</string>
</dict>
<dict>
<key>match</key>
<string>!|%|&amp;|\*|\/|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(instanceof|new|delete|typeof|and|or|is|isnt|not)\b</string>
<key>name</key>
<string>keyword.operator.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\b(Infinity|NaN|undefined)\b</string>
<key>name</key>
<string>constant.language.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\;</string>
<key>name</key>
<string>punctuation.terminator.statement.coffee</string>
</dict>
<dict>
<key>match</key>
<string>,[ |\t]*</string>
<key>name</key>
<string>meta.delimiter.object.comma.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\.</string>
<key>name</key>
<string>meta.delimiter.method.period.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\{|\}</string>
<key>name</key>
<string>meta.brace.curly.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\(|\)</string>
<key>name</key>
<string>meta.brace.round.coffee</string>
</dict>
<dict>
<key>match</key>
<string>\[|\]</string>
<key>name</key>
<string>meta.brace.square.coffee</string>
</dict>
</array>
<key>scopeName</key>
<string>source.coffee</string>
<key>uuid</key>
<string>5B520980-A7D5-4E10-8582-1A4C889A8DE5</string>
</dict>
</plist>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>CoffeeScript</string>
<key>uuid</key>
<string>A46E4382-F1AC-405B-8F22-65FF470F34D7</string>
</dict>
</plist>

View File

@@ -5,24 +5,3 @@ CoffeeScript compiler. To use it in the browser, include the script after any
inline script tags of type "text/coffeescript" on the page. It will compile
and evaluate all of the scripts in order.
This folder also includes rough cuts of CoffeeScript syntax highlighters for
TextMate and Vim. Improvements to their lexing ability are always welcome.
To install the TextMate bundle, drop it into:
~/Library/Application Support/TextMate/Bundles
To install the Vim highlighter, copy "coffee.vim" into the "syntax" directory of
your vim72, and enable it in either of the following two ways:
* Manually, by running `:set syntax=coffee`
* Or automatically, by creating a "filetype.vim" file within "~/.vim", which
contains something along these lines:
if exists("did_load_filetypes")
finish
end
augroup filetypedetect
au! BufRead,BufNewFile *.coffee setfiletype coffee
augroup END

File diff suppressed because one or more lines are too long

View File

@@ -1,117 +0,0 @@
" Vim syntax file
" Language: CoffeeScript
" Maintainer: Jeff Olson <olson.jeffery@gmail.com>
" URL: http://github.com/olsonjeffery
" Changes: (jro) initial port from javascript
" Last Change: 2006 Jun 19
" Adaptation of javascript.vim syntax file (distro'd w/ vim72),
" maintained by Claudio Fleiner <claudio@fleiner.com>
" with updates from Scott Shattuck (ss) <ss@technicalpursuit.com>
if !exists("main_syntax")
if version < 600
syntax clear
elseif exists("b:current_syntax")
finish
endif
let main_syntax = 'coffee'
endif
syn case ignore
syn match coffeeLineComment "#.*" contains=@Spell,CoffeeCommentTodo
syn match coffeeSpecial "\\\d\d\d\|\\."
syn region coffeeStringD start=+"+ skip=+\\\\\|\\"+ end=+"\|$+ contains=coffeeSpecial,@htmlPreproc
syn region coffeeStringS start=+'+ skip=+\\\\\|\\'+ end=+'\|$+ contains=coffeeSpecial,@htmlPreproc
syn match coffeeSpecialCharacter "'\\.'"
syn match coffeeNumber "-\=\<\d\+L\=\>\|0[xX][0-9a-fA-F]\+\>"
syn region coffeeRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gi]\{0,2\}\s*$+ end=+/[gi]\{0,2\}\s*[;.,)\]}]+me=e-1 contains=@htmlPreproc oneline
syn match coffeeFunctionParams "([^)]*)\s*->"
syn match coffeeBindFunctionParams "([^)]*)\s*=>"
syn match coffeePrototypeAccess "::"
syn match coffeeBindFunction "=[1]>[1]"
syn match coffeeFunction "->"
syn keyword coffeeExtends extends
syn keyword coffeeConditional if else switch then not
syn keyword coffeeRepeat while for in of
syn keyword coffeeBranch break continue
syn keyword coffeeOperator delete instanceof typeof
syn keyword coffeeType Array Boolean Date Function Number Object String RegExp
syn keyword coffeeStatement return with
syn keyword coffeeBoolean true false
syn keyword coffeeNull null undefined
syn keyword coffeeIdentifier arguments this var
syn keyword coffeeLabel case default
syn keyword coffeeException try catch finally throw
syn keyword coffeeMessage alert confirm prompt status
syn keyword coffeeGlobal self window top parent
syn keyword coffeeMember document event location
syn keyword coffeeDeprecated escape unescape
syn keyword coffeeReserved abstract boolean byte char class const debugger double enum export final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile
syn sync fromstart
syn sync maxlines=100
if main_syntax == "coffee"
syn sync ccomment coffeeComment
endif
" Define the default highlighting.
" For version 5.7 and earlier: only when not done already
" For version 5.8 and later: only when an item doesn't have highlighting yet
if version >= 508 || !exists("did_coffee_syn_inits")
if version < 508
let did_coffee_syn_inits = 1
command -nargs=+ HiLink hi link <args>
else
command -nargs=+ HiLink hi def link <args>
endif
HiLink coffeePrototypeAccess Keyword
HiLink coffeeExtends Keyword
HiLink coffeeLineComment Comment
HiLink coffeeSpecial Special
HiLink coffeeStringS String
HiLink coffeeStringD String
HiLink coffeeCharacter Character
HiLink coffeeSpecialCharacter coffeeSpecial
HiLink coffeeNumber coffeeValue
HiLink coffeeConditional Conditional
HiLink coffeeRepeat Repeat
HiLink coffeeBranch Conditional
HiLink coffeeOperator Operator
HiLink coffeeType Type
HiLink coffeeStatement Statement
HiLink coffeeBindFunctionParams Function
HiLink coffeeFunctionParams Function
HiLink coffeeFunction Function
HiLink coffeeBindFunction Function
HiLink coffeeBraces Function
HiLink coffeeError Error
HiLink coffeeScrParenError coffeeError
HiLink coffeeNull Keyword
HiLink coffeeBoolean Boolean
HiLink coffeeRegexpString String
HiLink coffeeIdentifier Identifier
HiLink coffeeLabel Label
HiLink coffeeException Exception
HiLink coffeeMessage Keyword
HiLink coffeeGlobal Keyword
HiLink coffeeMember Keyword
HiLink coffeeDeprecated Exception
HiLink coffeeReserved Keyword
HiLink coffeeDebug Debug
HiLink coffeeConstant Label
delcommand HiLink
endif
let b:current_syntax = "coffee"
if main_syntax == 'coffee'
unlet main_syntax
endif
" vim: ts=8

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env node
process.mixin(require('sys'));
require.paths.unshift('/usr/local/lib/coffee-script/lib');
require('cake').run();

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env node
process.mixin(require('sys'));
require.paths.unshift('/usr/local/lib/coffee-script/lib');
require('command_line').run();

View File

@@ -1,80 +1,99 @@
(function(){
var coffee, fs, no_such_task, path, print_tasks, tasks;
var CoffeeScript, fs, helpers, no_such_task, oparse, options, optparse, path, print_tasks, switches, tasks;
var __hasProp = Object.prototype.hasOwnProperty;
// `cake` is a simplified version of Make (Rake, Jake) for CoffeeScript.
// `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
// ([Rake](http://rake.rubyforge.org/), [Jake](http://github.com/280north/jake))
// for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
// and can call them from the command line, or invoke them from other tasks.
// Running `cake` with no arguments will print out a list of all the tasks in the
// current directory's Cakefile.
// External dependencies.
fs = require('fs');
path = require('path');
coffee = require('coffee-script');
helpers = require('./helpers').helpers;
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
// Keep track of the list of defined tasks, the accepted options, and so on.
tasks = {};
no_such_task = function no_such_task(task) {
process.stdio.writeError('No such task: "' + task + '"\n');
return process.exit(1);
};
// Mixin the Cake functionality.
process.mixin({
// Define a task with a name, a description, and the action itself.
options = {};
switches = [];
oparse = null;
// Mixin the top-level Cake functions for Cakefiles to use directly.
helpers.extend(global, {
// Define a Cake task with a short name, a sentence description,
// and the function to run as the action itself.
task: function task(name, description, action) {
return tasks[name] = {
tasks[name] = {
name: name,
description: description,
action: action
};
return tasks[name];
},
// Invoke another task in the Cakefile.
// Define an option that the Cakefile accepts. The parsed options hash,
// containing all of the command-line options passed, will be made available
// as the first argument to the action.
option: function option(letter, flag, description) {
return switches.push([letter, flag, description]);
},
// Invoke another task in the current Cakefile.
invoke: function invoke(name) {
if (!(tasks[name])) {
no_such_task(name);
}
return tasks[name].action();
return tasks[name].action(options);
}
});
// Display the list of Cake tasks.
print_tasks = function print_tasks() {
var _a, _b, _c, _d, _e, _f, _g, i, name, spaces, task;
_a = []; _b = tasks;
for (name in _b) { if (__hasProp.call(_b, name)) {
task = _b[name];
_a.push((function() {
spaces = 20 - name.length;
spaces = spaces > 0 ? (function() {
_c = []; _f = 0; _g = spaces;
for (_e = 0, i=_f; (_f <= _g ? i <= _g : i >= _g); (_f <= _g ? i += 1 : i -= 1), _e++) {
_c.push(' ');
}
return _c;
}).call(this).join('') : '';
return puts("cake " + name + spaces + ' # ' + task.description);
}).call(this));
}}
return _a;
};
// Running `cake` runs the tasks you pass asynchronously (node-style), or
// prints them out, with no arguments.
// Run `cake`. Executes all of the tasks you pass, in order. Note that Node's
// asynchrony may cause tasks to execute in a different order than you'd expect.
// If no tasks are passed, print the help screen.
exports.run = function run() {
return path.exists('Cakefile', function(exists) {
var args;
var _a, _b, _c, _d, arg, args;
if (!(exists)) {
throw new Error('Cakefile not found in ' + process.cwd());
throw new Error("Cakefile not found in " + (process.cwd()));
}
args = process.ARGV.slice(2, process.ARGV.length);
return fs.readFile('Cakefile', function(err, source) {
var _a, _b, _c, arg;
eval(coffee.compile(source));
if (!(args.length)) {
return print_tasks();
}
_a = []; _b = args;
for (_c = 0; _c < _b.length; _c++) {
arg = _b[_c];
_a.push((function() {
if (!(tasks[arg])) {
no_such_task(arg);
}
return tasks[arg].action();
}).call(this));
}
return _a;
args = process.argv.slice(2, process.argv.length);
CoffeeScript.run(fs.readFileSync('Cakefile'), {
source: 'Cakefile'
});
oparse = new optparse.OptionParser(switches);
if (!(args.length)) {
return print_tasks();
}
options = oparse.parse(args);
_a = []; _c = options.arguments;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
arg = _c[_b];
_a.push(invoke(arg));
}
return _a;
});
};
// Display the list of Cake tasks in a format similar to `rake -T`
print_tasks = function print_tasks() {
var _a, _b, _c, _d, _e, i, name, spaces, task;
puts('');
_a = tasks;
for (name in _a) { if (__hasProp.call(_a, name)) {
task = _a[name];
spaces = 20 - name.length;
spaces = spaces > 0 ? (function() {
_b = []; _d = 0; _e = spaces;
for (_c = 0, i = _d; (_d <= _e ? i <= _e : i >= _e); (_d <= _e ? i += 1 : i -= 1), _c++) {
_b.push(' ');
}
return _b;
}).call(this).join('') : '';
puts("cake " + name + spaces + " # " + (task.description));
}}
if (switches.length) {
return puts(oparse.help());
}
};
// Print an error and exit when attempting to all an undefined task.
no_such_task = function no_such_task(task) {
process.stdio.writeError("No such task: \"" + task + "\"\n");
return process.exit(1);
};
})();

View File

@@ -1,17 +1,72 @@
(function(){
var _a, _b, lexer, parser, path, tag;
// Set up for both the browser and the server.
var Lexer, compile, helpers, lexer, parser, path, process_scripts;
// CoffeeScript can be used both on the server, as a command-line compiler based
// on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
// contains the main entry functions for tokenzing, parsing, and compiling source
// CoffeeScript into JavaScript.
// If included on a webpage, it will automatically sniff out, compile, and
// execute all scripts present in `text/coffeescript` tags.
// Set up dependencies correctly for both the server and the browser.
if ((typeof process !== "undefined" && process !== null)) {
process.mixin(require('nodes'));
path = require('path');
lexer = new (require('lexer').Lexer)();
parser = require('parser').parser;
Lexer = require('./lexer').Lexer;
parser = require('./parser').parser;
helpers = require('./helpers').helpers;
helpers.extend(global, require('./nodes'));
require.registerExtension ? require.registerExtension('.coffee', function(content) {
return compile(content);
}) : null;
} else {
lexer = new Lexer();
parser = exports.parser;
this.exports = (this.CoffeeScript = {});
Lexer = this.Lexer;
parser = this.parser;
helpers = this.helpers;
}
// Thin wrapper for Jison compatibility around the real lexer.
// The current CoffeeScript version number.
exports.VERSION = '0.6.0';
// Instantiate a Lexer for our use here.
lexer = new Lexer();
// Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
// compiler.
exports.compile = (compile = function compile(code, options) {
options = options || {};
try {
return (parser.parse(lexer.tokenize(code))).compile(options);
} catch (err) {
if (options.source) {
err.message = "In " + (options.source) + ", " + (err.message);
}
throw err;
}
});
// Tokenize a string of CoffeeScript code, and return the array of tokens.
exports.tokens = function tokens(code) {
return lexer.tokenize(code);
};
// Tokenize and parse a string of CoffeeScript code, and return the AST. You can
// then compile it by calling `.compile()` on the root, or traverse it by using
// `.traverse()` with a callback.
exports.nodes = function nodes(code) {
return parser.parse(lexer.tokenize(code));
};
// Compile and execute a string of CoffeeScript (on the server), correctly
// setting `__filename`, `__dirname`, and relative `require()`.
exports.run = (function(code, options) {
var __dirname, __filename;
module.filename = (__filename = options.source);
__dirname = path.dirname(__filename);
return eval(exports.compile(code, options));
});
// Extend CoffeeScript with a custom language extension. It should hook in to
// the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
// push a token on to the stack that contains a **Node** as the value (as a
// peer of the nodes in [nodes.coffee](nodes.html)).
exports.extend = function extend(func) {
return Lexer.extensions.push(func);
};
// The real Lexer produces a generic stream of tokens. This object provides a
// thin wrapper around it, compatible with the Jison API. We can then pass it
// directly as a "Jison lexer".
parser.lexer = {
lex: function lex() {
var token;
@@ -23,7 +78,8 @@
},
setInput: function setInput(tokens) {
this.tokens = tokens;
return this.pos = 0;
this.pos = 0;
return this.pos;
},
upcomingInput: function upcomingInput() {
return "";
@@ -32,26 +88,24 @@
return this.pos;
}
};
exports.VERSION = '0.5.2';
// Compile CoffeeScript to JavaScript, using the Coffee/Jison compiler.
exports.compile = function compile(code, options) {
return (parser.parse(lexer.tokenize(code))).compile(options);
};
// Just the tokens.
exports.tokenize = function tokenize(code) {
return lexer.tokenize(code);
};
// Just the nodes.
exports.tree = function tree(code) {
return parser.parse(lexer.tokenize(code));
};
// Activate CoffeeScript in the browser by having it compile and eval
// all script tags with a content-type of text/coffeescript.
// Activate CoffeeScript in the browser by having it compile and evaluate
// all script tags with a content-type of `text/coffeescript`. This happens
// on page load. Unfortunately, the text contents of remote scripts cannot be
// accessed from the browser, so only inline script tags will work.
if ((typeof document !== "undefined" && document !== null) && document.getElementsByTagName) {
_a = document.getElementsByTagName('script');
for (_b = 0; _b < _a.length; _b++) {
tag = _a[_b];
tag.type === 'text/coffeescript' ? eval(exports.compile(tag.innerHTML)) : null;
process_scripts = function process_scripts() {
var _a, _b, _c, _d, tag;
_a = []; _c = document.getElementsByTagName('script');
for (_b = 0, _d = _c.length; _b < _d; _b++) {
tag = _c[_b];
tag.type === 'text/coffeescript' ? _a.push(eval(exports.compile(tag.innerHTML))) : null;
}
return _a;
};
if (window.addEventListener) {
window.addEventListener('load', process_scripts, false);
} else if (window.attachEvent) {
window.attachEvent('onload', process_scripts);
}
}
})();

227
lib/command.js Normal file
View File

@@ -0,0 +1,227 @@
(function(){
var BANNER, CoffeeScript, SWITCHES, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, usage, version, watch_scripts, write_js;
// The `coffee` utility. Handles command-line compilation of CoffeeScript
// into various forms: saved into `.js` files or printed to stdout, piped to
// [JSLint](http://javascriptlint.com/) or recompiled every time the source is
// saved, printed as a token stream or as the syntax tree, or launch an
// interactive REPL.
// External dependencies.
fs = require('fs');
path = require('path');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
// The help banner that is printed when `coffee` is called without arguments.
BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee';
// The list of all the valid option flags that `coffee` knows how to handle.
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['--no-wrap', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
// Top-level objects shared by all the functions.
options = {};
sources = [];
option_parser = null;
// Run `coffee` by parsing passed options and determining what action to take.
// Many flags cause us to divert before compiling anything. Flags passed after
// `--` will be passed verbatim to your script as arguments in `process.argv`
exports.run = function run() {
var flags, separator;
parse_options();
if (options.help) {
return usage();
}
if (options.version) {
return version();
}
if (options.interactive) {
return require('./repl');
}
if (options.stdio) {
return compile_stdio();
}
if (options.eval) {
return compile_script('console', sources[0]);
}
if (!(sources.length)) {
return usage();
}
separator = sources.indexOf('--');
flags = [];
if (separator >= 0) {
flags = sources.slice((separator + 1), sources.length);
sources = sources.slice(0, separator);
}
process.ARGV = (process.argv = flags);
if (options.watch) {
watch_scripts();
}
return compile_scripts();
};
// Asynchronously read in each CoffeeScript in a list of source files and
// compile them.
compile_scripts = function compile_scripts() {
var _a, _b, _c, _d, compile, source;
compile = function compile(source) {
return path.exists(source, function(exists) {
if (!(exists)) {
throw new Error("File not found: " + source);
}
return fs.readFile(source, function(err, code) {
return compile_script(source, code);
});
});
};
_a = []; _c = sources;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
source = _c[_b];
_a.push(compile(source));
}
return _a;
};
// Compile a single source script, containing the given code, according to the
// requested options. Both compile_scripts and watch_scripts share this method
// in common. If evaluating the script directly sets `__filename`, `__dirname`
// and `module.filename` to be correct relative to the script's path.
compile_script = function compile_script(source, code) {
var code_opts, js, o;
o = options;
code_opts = compile_options(source);
try {
if (o.tokens) {
return print_tokens(CoffeeScript.tokens(code));
} else if (o.nodes) {
return puts(CoffeeScript.nodes(code).toString());
} else if (o.run) {
return CoffeeScript.run(code, code_opts);
} else {
js = CoffeeScript.compile(code, code_opts);
if (o.print) {
return process.stdio.write(js);
} else if (o.compile) {
return write_js(source, js);
} else if (o.lint) {
return lint(js);
}
}
} catch (err) {
if (o.watch) {
return puts(err.message);
} else {
throw err;
}
}
};
// Attach the appropriate listeners to compile scripts incoming over **stdin**,
// and write them back to **stdout**.
compile_stdio = function compile_stdio() {
var code;
code = '';
process.stdio.open();
process.stdio.addListener('data', function(string) {
if (string) {
return code += string;
}
});
return process.stdio.addListener('close', function() {
return compile_script('stdio', code);
});
};
// Watch a list of source CoffeeScript files using `fs.watchFile`, recompiling
// them every time the files are updated. May be used in combination with other
// options, such as `--lint` or `--print`.
watch_scripts = function watch_scripts() {
var _a, _b, _c, _d, source, watch;
watch = function watch(source) {
return fs.watchFile(source, {
persistent: true,
interval: 500
}, function(curr, prev) {
if (curr.mtime.getTime() === prev.mtime.getTime()) {
return null;
}
return fs.readFile(source, function(err, code) {
return compile_script(source, code);
});
});
};
_a = []; _c = sources;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
source = _c[_b];
_a.push(watch(source));
}
return _a;
};
// Write out a JavaScript source file with the compiled code. By default, files
// are written out in `cwd` as `.js` files with the same name, but the output
// directory can be customized with `--output`.
write_js = function write_js(source, js) {
var dir, filename, js_path;
filename = path.basename(source, path.extname(source)) + '.js';
dir = options.output || path.dirname(source);
js_path = path.join(dir, filename);
return fs.writeFile(js_path, js);
};
// Pipe compiled JS through JSLint (requires a working `jsl` command), printing
// any errors or warnings that arise.
lint = function lint(js) {
var jsl;
jsl = process.createChildProcess('jsl', ['-nologo', '-stdin']);
jsl.addListener('output', function(result) {
if (result) {
return puts(result.replace(/\n/g, ''));
}
});
jsl.addListener('error', function(result) {
if (result) {
return puts(result);
}
});
jsl.write(js);
return jsl.close();
};
// Pretty-print a stream of tokens.
print_tokens = function print_tokens(tokens) {
var _a, _b, _c, _d, _e, strings, tag, token, value;
strings = (function() {
_a = []; _c = tokens;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
token = _c[_b];
_a.push((function() {
_e = [token[0], token[1].toString().replace(/\n/, '\\n')];
tag = _e[0];
value = _e[1];
return "[" + tag + " " + value + "]";
}).call(this));
}
return _a;
}).call(this);
return puts(strings.join(' '));
};
// Use the [OptionParser module](optparse.html) to extract all options from
// `process.argv` that are specified in `SWITCHES`.
parse_options = function parse_options() {
var o;
option_parser = new optparse.OptionParser(SWITCHES, BANNER);
o = (options = option_parser.parse(process.argv));
options.run = !(o.compile || o.print || o.lint);
options.print = !!(o.print || (o.eval || o.stdio && o.compile));
sources = options.arguments.slice(2, options.arguments.length);
return sources;
};
// The compile-time options to pass to the CoffeeScript compiler.
compile_options = function compile_options(source) {
var o;
o = {
source: source
};
o['no_wrap'] = options['no-wrap'];
return o;
};
// Print the `--help` usage message and exit.
usage = function usage() {
puts(option_parser.help());
return process.exit(0);
};
// Print the `--version` message and exit.
version = function version() {
puts("CoffeeScript version " + (CoffeeScript.VERSION));
return process.exit(0);
};
})();

View File

@@ -1,191 +0,0 @@
(function(){
var BANNER, CoffeeScript, SWITCHES, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, usage, version, watch_scripts, write_js;
fs = require('fs');
path = require('path');
optparse = require('optparse');
CoffeeScript = require('coffee-script');
BANNER = "coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee";
SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
options = {};
sources = [];
option_parser = null;
// The CommandLine handles all of the functionality of the `coffee` utility.
exports.run = function run() {
var flags, separator;
parse_options();
if (options.help) {
return usage();
}
if (options.version) {
return version();
}
if (options.interactive) {
return require('repl');
}
if (options.stdio) {
return compile_stdio();
}
if (options.eval) {
return compile_script('unknown', sources[0]);
}
if (!(sources.length)) {
return usage();
}
separator = sources.indexOf('--');
flags = [];
if (separator >= 0) {
flags = sources.slice((separator + 1), sources.length);
sources = sources.slice(0, separator);
}
process.ARGV = flags;
if (options.watch) {
watch_scripts();
}
compile_scripts();
return this;
};
// The "--help" usage message.
usage = function usage() {
puts('\n' + option_parser.help() + '\n');
return process.exit(0);
};
// The "--version" message.
version = function version() {
puts("CoffeeScript version " + CoffeeScript.VERSION);
return process.exit(0);
};
// Compiles the source CoffeeScript, returning the desired JavaScript, tokens,
// or JSLint results.
compile_scripts = function compile_scripts() {
var _a, _b, _c, compile, source;
compile = function compile(source) {
return fs.readFile(source, function(err, code) {
return compile_script(source, code);
});
};
_a = []; _b = sources;
for (_c = 0; _c < _b.length; _c++) {
source = _b[_c];
_a.push(compile(source));
}
return _a;
};
// Compile a single source script, containing the given code, according to the
// requested options. Both compile_scripts and watch_scripts share this method.
compile_script = function compile_script(source, code) {
var js, o;
o = options;
try {
if (o.tokens) {
return print_tokens(CoffeeScript.tokenize(code));
} else if (o.tree) {
return puts(CoffeeScript.tree(code).toString());
} else {
js = CoffeeScript.compile(code, compile_options());
if (o.run) {
return eval(js);
} else if (o.lint) {
return lint(js);
} else if (o.print || o.eval) {
return print(js);
} else {
return write_js(source, js);
}
}
} catch (err) {
if (o.watch) {
return puts(err.message);
} else {
throw err;
}
}
};
// Listen for and compile scripts over stdio.
compile_stdio = function compile_stdio() {
var code;
code = '';
process.stdio.open();
process.stdio.addListener('data', function(string) {
if (string) {
return code += string;
}
});
return process.stdio.addListener('close', function() {
return process.stdio.write(CoffeeScript.compile(code, compile_options()));
});
};
// Watch a list of source CoffeeScript files, recompiling them every time the
// files are updated.
watch_scripts = function watch_scripts() {
var _a, _b, _c, source, watch;
watch = function watch(source) {
return process.watchFile(source, {
persistent: true,
interval: 500
}, function(curr, prev) {
if (curr.mtime.getTime() === prev.mtime.getTime()) {
return null;
}
return fs.readFile(source, function(err, code) {
return compile_script(source, code);
});
});
};
_a = []; _b = sources;
for (_c = 0; _c < _b.length; _c++) {
source = _b[_c];
_a.push(watch(source));
}
return _a;
};
// Write out a JavaScript source file with the compiled code.
write_js = function write_js(source, js) {
var dir, filename, js_path;
filename = path.basename(source, path.extname(source)) + '.js';
dir = options.output || path.dirname(source);
js_path = path.join(dir, filename);
return fs.writeFile(js_path, js);
};
// Pipe compiled JS through JSLint (requires a working 'jsl' command).
lint = function lint(js) {
var jsl;
jsl = process.createChildProcess('jsl', ['-nologo', '-stdin']);
jsl.addListener('output', function(result) {
if (result) {
return puts(result.replace(/\n/g, ''));
}
});
jsl.addListener('error', function(result) {
if (result) {
return puts(result);
}
});
jsl.write(js);
return jsl.close();
};
// Pretty-print a token stream.
print_tokens = function print_tokens(tokens) {
var _a, _b, _c, strings, token;
strings = (function() {
_a = []; _b = tokens;
for (_c = 0; _c < _b.length; _c++) {
token = _b[_c];
_a.push('[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']');
}
return _a;
}).call(this);
return puts(strings.join(' '));
};
// Use OptionParser for all the options.
parse_options = function parse_options() {
option_parser = new optparse.OptionParser(SWITCHES, BANNER);
options = option_parser.parse(process.ARGV);
return sources = options.arguments.slice(2, options.arguments.length);
};
// The options to pass to the CoffeeScript compiler.
compile_options = function compile_options() {
return options['no-wrap'] ? {
no_wrap: true
} : {};
};
})();

File diff suppressed because it is too large Load Diff

143
lib/helpers.js Normal file
View File

@@ -0,0 +1,143 @@
(function(){
var balanced_string, compact, count, del, extend, flatten, helpers, include, merge, starts;
var __hasProp = Object.prototype.hasOwnProperty;
// This file contains the common helper functions that we'd like to share among
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
// arrays, count characters, that sort of thing.
// Set up exported variables for both **Node.js** and the browser.
if (!((typeof process !== "undefined" && process !== null))) {
this.exports = this;
}
helpers = (exports.helpers = {});
// Does a list include a value?
helpers.include = (include = function include(list, value) {
return list.indexOf(value) >= 0;
});
// Peek at the beginning of a given string to see if it matches a sequence.
helpers.starts = (starts = function starts(string, literal, start) {
return string.substring(start, (start || 0) + literal.length) === literal;
});
// Trim out all falsy values from an array.
helpers.compact = (compact = function compact(array) {
var _a, _b, _c, _d, item;
_a = []; _c = array;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
item = _c[_b];
item ? _a.push(item) : null;
}
return _a;
});
// Count the number of occurences of a character in a string.
helpers.count = (count = function count(string, letter) {
var num, pos;
num = 0;
pos = string.indexOf(letter);
while (pos !== -1) {
num += 1;
pos = string.indexOf(letter, pos + 1);
}
return num;
});
// Merge objects, returning a fresh copy with attributes from both sides.
// Used every time `BaseNode#compile` is called, to allow properties in the
// options hash to propagate down the tree without polluting other branches.
helpers.merge = (merge = function merge(options, overrides) {
var _a, _b, fresh, key, val;
fresh = {};
_a = options;
for (key in _a) { if (__hasProp.call(_a, key)) {
val = _a[key];
(fresh[key] = val);
}}
if (overrides) {
_b = overrides;
for (key in _b) { if (__hasProp.call(_b, key)) {
val = _b[key];
(fresh[key] = val);
}}
}
return fresh;
});
// Extend a source object with the properties of another object (shallow copy).
// We use this to simulate Node's deprecated `process.mixin`
helpers.extend = (extend = function extend(object, properties) {
var _a, _b, key, val;
_a = []; _b = properties;
for (key in _b) { if (__hasProp.call(_b, key)) {
val = _b[key];
_a.push((object[key] = val));
}}
return _a;
});
// Return a completely flattened version of an array. Handy for getting a
// list of `children` from the nodes.
helpers.flatten = (flatten = function flatten(array) {
var _a, _b, _c, item, memo;
memo = [];
_b = array;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
item = _b[_a];
item instanceof Array ? (memo = memo.concat(item)) : memo.push(item);
}
return memo;
});
// Delete a key from an object, returning the value. Useful when a node is
// looking for a particular method in an options hash.
helpers.del = (del = function del(obj, key) {
var val;
val = obj[key];
delete obj[key];
return val;
});
// Matches a balanced group such as a single or double-quoted string. Pass in
// a series of delimiters, all of which must be nested correctly within the
// contents of the string. This method allows us to have strings within
// interpolations within strings, ad infinitum.
helpers.balanced_string = (balanced_string = function balanced_string(str, delimited, options) {
var _a, _b, _c, _d, close, i, levels, open, pair, slash;
options = options || {};
slash = delimited[0][0] === '/';
levels = [];
i = 0;
while (i < str.length) {
if (levels.length && starts(str, '\\', i)) {
i += 1;
} else {
_b = delimited;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
pair = _b[_a];
_d = pair;
open = _d[0];
close = _d[1];
if (levels.length && starts(str, close, i) && levels[levels.length - 1] === pair) {
levels.pop();
i += close.length - 1;
if (!(levels.length)) {
i += 1;
}
break;
} else if (starts(str, open, i)) {
levels.push(pair);
i += open.length - 1;
break;
}
}
}
if (!levels.length || slash && starts(str, '\n', i)) {
break;
}
i += 1;
}
if (levels.length) {
if (slash) {
return false;
}
throw new Error("SyntaxError: Unterminated " + (levels.pop()[0]) + " starting on line " + (this.line + 1));
}
if (!i) {
return false;
} else {
return str.substring(0, i);
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +0,0 @@
(function(){
var coffee, factories, file, loader, os, puts;
// The Narwhal-compatibility wrapper for CoffeeScript.
// Require external dependencies.
os = require('os');
file = require('file');
coffee = require('./coffee-script');
// Alias print to "puts", for Node.js compatibility:
puts = print;
// Compile a string of CoffeeScript into JavaScript.
exports.compile = function compile(source) {
return coffee.compile(source);
};
// Compile a given CoffeeScript file into JavaScript.
exports.compileFile = function compileFile(path) {
return coffee.compile(file.read(path));
};
// Make a factory for the CoffeeScript environment.
exports.makeNarwhalFactory = function makeNarwhalFactory(path) {
var code, factoryText;
code = exports.compileFile(path);
factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}";
if (system.engine === "rhino") {
return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null);
} else {
// eval requires parentheses, but parentheses break compileFunction.
return eval("(" + factoryText + ")");
}
};
// The Narwhal loader for '.coffee' files.
factories = {};
loader = {};
// Reload the coffee-script environment from source.
loader.reload = function reload(topId, path) {
return factories[topId] = function() {
return exports.makeNarwhalFactory(path);
};
};
// Ensure that the coffee-script environment is loaded.
loader.load = function load(topId, path) {
return factories[topId] = factories[topId] || this.reload(topId, path);
};
require.loader.loaders.unshift([".coffee", loader]);
})();

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +1,90 @@
(function(){
var LONG_FLAG, OPTIONAL, SHORT_FLAG, build_rule, build_rules, op, spaces;
// Create an OptionParser with a list of valid options.
op = (exports.OptionParser = function OptionParser(rules, banner) {
this.banner = banner || 'Usage: [Options]';
this.options_title = 'Available options:';
this.rules = build_rules(rules);
return this;
});
// Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
op.prototype.parse = function parse(args) {
var _a, _b, arg, is_option, options, rule;
arguments = Array.prototype.slice.call(arguments, 0);
options = {
arguments: []
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, build_rule, build_rules, normalize_arguments;
// A simple **OptionParser** class to parse option flags from the command-line.
// Use it like so:
// parser: new OptionParser switches, help_banner
// options: parser.parse process.argv
exports.OptionParser = (function() {
OptionParser = function OptionParser(rules, banner) {
this.banner = banner;
this.rules = build_rules(rules);
return this;
};
args = args.concat([]);
while (((arg = args.shift()))) {
is_option = false;
_a = this.rules;
for (_b = 0; _b < _a.length; _b++) {
rule = _a[_b];
if (rule.letter === arg || rule.flag === arg) {
options[rule.name] = rule.argument ? args.shift() : true;
is_option = true;
break;
// Initialize with a list of valid options, in the form:
// [short-flag, long-flag, description]
// Along with an an optional banner for the usage help.
// Parse the list of arguments, populating an `options` object with all of the
// specified options, and returning it. `options.arguments` will be an array
// containing the remaning non-option arguments. This is a simpler API than
// many option parsers that allow you to attach callback actions for every
// flag. Instead, you're responsible for interpreting the options object.
OptionParser.prototype.parse = function parse(args) {
var _a, _b, _c, arg, is_option, matched_rule, options, rule;
options = {
arguments: []
};
args = normalize_arguments(args);
while ((arg = args.shift())) {
is_option = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
matched_rule = false;
_b = this.rules;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
rule = _b[_a];
if (rule.short_flag === arg || rule.long_flag === arg) {
options[rule.name] = rule.has_argument ? args.shift() : true;
matched_rule = true;
break;
}
}
if (is_option && !matched_rule) {
throw new Error("unrecognized option: " + arg);
}
if (!(is_option)) {
options.arguments.push(arg);
}
}
if (!(is_option)) {
options.arguments.push(arg);
return options;
};
// Return the help text for this **OptionParser**, listing and describing all
// of the valid options, for `--help` and such.
OptionParser.prototype.help = function help() {
var _a, _b, _c, _d, _e, _f, _g, i, let_part, lines, rule, spaces;
lines = ['Available options:'];
if (this.banner) {
lines.unshift("" + this.banner + "\n");
}
}
return options;
};
// Return the help text for this OptionParser, for --help and such.
op.prototype.help = function help() {
var _a, _b, _c, _d, has_shorts, lines, longest, rule, text;
longest = 0;
has_shorts = false;
lines = [this.banner, '', this.options_title];
_a = this.rules;
for (_b = 0; _b < _a.length; _b++) {
rule = _a[_b];
if (rule.letter) {
has_shorts = true;
_b = this.rules;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
rule = _b[_a];
spaces = 15 - rule.long_flag.length;
spaces = spaces > 0 ? (function() {
_d = []; _f = 0; _g = spaces;
for (_e = 0, i = _f; (_f <= _g ? i <= _g : i >= _g); (_f <= _g ? i += 1 : i -= 1), _e++) {
_d.push(' ');
}
return _d;
}).call(this).join('') : '';
let_part = rule.short_flag ? rule.short_flag + ', ' : ' ';
lines.push(" " + let_part + (rule.long_flag) + spaces + (rule.description));
}
if (rule.flag.length > longest) {
longest = rule.flag.length;
}
}
_c = this.rules;
for (_d = 0; _d < _c.length; _d++) {
rule = _c[_d];
has_shorts ? (text = rule.letter ? spaces(2) + rule.letter + ', ' : spaces(6)) : null;
text += spaces(longest, rule.flag) + spaces(3);
text += rule.description;
lines.push(text);
}
return lines.join('\n');
};
// Private:
return "\n" + (lines.join('\n')) + "\n";
};
return OptionParser;
}).call(this);
// Helpers
// -------
// Regex matchers for option flags.
LONG_FLAG = /^(--[\w\-]+)/;
SHORT_FLAG = /^(-\w+)/;
LONG_FLAG = /^(--\w[\w\-]+)/;
SHORT_FLAG = /^(-\w)/;
MULTI_FLAG = /^-(\w{2,})/;
OPTIONAL = /\[(.+)\]/;
// Build rules from a list of valid switch tuples in the form:
// [letter-flag, long-flag, help], or [long-flag, help].
// Build and return the list of option rules. If the optional *short-flag* is
// unspecified, leave it out by padding with `null`.
build_rules = function build_rules(rules) {
var _a, _b, _c, tuple;
_a = []; _b = rules;
for (_c = 0; _c < _b.length; _c++) {
tuple = _b[_c];
var _a, _b, _c, _d, tuple;
_a = []; _c = rules;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
tuple = _c[_b];
_a.push((function() {
if (tuple.length < 3) {
tuple.unshift(null);
@@ -79,33 +94,39 @@
}
return _a;
};
// Build a rule from a short-letter-flag, long-form-flag, and help text.
build_rule = function build_rule(letter, flag, description) {
// Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the
// description of what the option does.
build_rule = function build_rule(short_flag, long_flag, description) {
var match;
match = flag.match(OPTIONAL);
flag = flag.match(LONG_FLAG)[1];
match = long_flag.match(OPTIONAL);
long_flag = long_flag.match(LONG_FLAG)[1];
return {
name: flag.substr(2),
letter: letter,
flag: flag,
name: long_flag.substr(2),
short_flag: short_flag,
long_flag: long_flag,
description: description,
argument: !!(match && match[1])
has_argument: !!(match && match[1])
};
};
// Space-pad a string with the specified number of characters.
spaces = function spaces(num, text) {
var builder;
builder = [];
if (text) {
if (text.length >= num) {
return text;
// Normalize arguments by expanding merged flags into multiple flags. This allows
// you to have `-wl` be the same as `--watch --lint`.
normalize_arguments = function normalize_arguments(args) {
var _a, _b, _c, _d, _e, _f, arg, l, match, result;
args = args.slice(0);
result = [];
_b = args;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
arg = _b[_a];
if ((match = arg.match(MULTI_FLAG))) {
_e = match[1].split('');
for (_d = 0, _f = _e.length; _d < _f; _d++) {
l = _e[_d];
result.push('-' + l);
}
} else {
result.push(arg);
}
num -= text.length;
builder.push(text);
}
while (num -= 1) {
builder.push(' ');
}
return builder.join('');
return result;
};
})();

File diff suppressed because one or more lines are too long

View File

@@ -1,22 +1,31 @@
(function(){
var coffee, prompt, quit, readline;
// A CoffeeScript port/version of the Node.js REPL.
// Required modules.
coffee = require('coffee-script');
// Shortcut variables.
var CoffeeScript, helpers, prompt, run;
// A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
// and evaluates it. Good for simple tests, or poking around the **Node.js** API.
// Using it looks like this:
// coffee> puts "$num bottles of beer" for num in [99..1]
// Require the **coffee-script** module to get access to the compiler.
CoffeeScript = require('./coffee-script');
helpers = require('./helpers').helpers;
// Our prompt.
prompt = 'coffee> ';
quit = function quit() {
return process.exit(0);
};
// The main REPL function. Called everytime a line of code is entered.
// Attempt to evaluate the command. If there's an exception, print it.
readline = function readline(code) {
// Quick alias for quitting the REPL.
helpers.extend(global, {
quit: function quit() {
return process.exit(0);
}
});
// The main REPL function. **run** is called every time a line of code is entered.
// Attempt to evaluate the command. If there's an exception, print it out instead
// of exiting.
run = function run(code) {
var val;
try {
val = eval(coffee.compile(code, {
val = CoffeeScript.run(code, {
no_wrap: true,
globals: true
}));
globals: true,
source: 'repl'
});
if (val !== undefined) {
p(val);
}
@@ -25,8 +34,8 @@
}
return print(prompt);
};
// Start up the REPL.
process.stdio.addListener('data', readline);
// Start up the REPL by opening **stdio** and listening for input.
process.stdio.addListener('data', run);
process.stdio.open();
print(prompt);
})();

View File

@@ -1,383 +1,372 @@
(function(){
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_START, EXPRESSION_TAIL, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, pair, re;
var __hasProp = Object.prototype.hasOwnProperty;
if (!((typeof process !== "undefined" && process !== null))) {
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, helpers, include, pair;
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
return function() {
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
};
}, __hasProp = Object.prototype.hasOwnProperty;
// The CoffeeScript language has a good deal of optional syntax, implicit syntax,
// and shorthand syntax. This can greatly complicate a grammar and bloat
// the resulting parse table. Instead of making the parser handle it all, we take
// a series of passes over the token stream, using this **Rewriter** to convert
// shorthand into the unambiguous long form, add implicit indentation and
// parentheses, balance incorrect nestings, and generally clean things up.
// Set up exported variables for both Node.js and the browser.
if ((typeof process !== "undefined" && process !== null)) {
helpers = require('./helpers').helpers;
} else {
this.exports = this;
helpers = this.helpers;
}
// In order to keep the grammar simple, the stream of tokens that the Lexer
// emits is rewritten by the Rewriter, smoothing out ambiguities, mis-nested
// indentation, and single-line flavors of expressions.
exports.Rewriter = (re = function re() { });
// Tokens that must be balanced.
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']];
// Tokens that signal the start of a balanced pair.
EXPRESSION_START = (function() {
_a = []; _b = BALANCED_PAIRS;
for (_c = 0; _c < _b.length; _c++) {
pair = _b[_c];
_a.push(pair[0]);
}
return _a;
}).call(this);
// Tokens that signal the end of a balanced pair.
EXPRESSION_TAIL = (function() {
_d = []; _e = BALANCED_PAIRS;
for (_f = 0; _f < _e.length; _f++) {
pair = _e[_f];
_d.push(pair[1]);
}
return _d;
}).call(this);
// Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_TAIL);
// Tokens pairs that, in immediate succession, indicate an implicit call.
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END'];
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT', '@', '->', '=>', '[', '(', '{'];
// The inverse mappings of token pairs we're trying to fix up.
INVERSES = {};
_g = BALANCED_PAIRS;
for (_h = 0; _h < _g.length; _h++) {
pair = _g[_h];
INVERSES[pair[0]] = pair[1];
INVERSES[pair[1]] = pair[0];
}
// Single-line flavors of block expressions that have unclosed endings.
// The grammar can't disambiguate them, so we insert the implicit indentation.
SINGLE_LINERS = ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN'];
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN', 'PARAM_START'];
// Rewrite the token stream in multiple passes, one logical filter at
// a time. This could certainly be changed into a single pass through the
// stream, with a big ol' efficient switch, but it's much nicer like this.
re.prototype.rewrite = function rewrite(tokens) {
this.tokens = tokens;
this.adjust_comments();
this.remove_leading_newlines();
this.remove_mid_expression_newlines();
this.move_commas_outside_outdents();
this.close_open_calls_and_indexes();
this.add_implicit_indentation();
this.add_implicit_parentheses();
this.ensure_balance(BALANCED_PAIRS);
this.rewrite_closing_parens();
return this.tokens;
};
// Rewrite the token stream, looking one token ahead and behind.
// Allow the return value of the block to tell us how many tokens to move
// forwards (or backwards) in the stream, to make sure we don't miss anything
// as the stream changes length under our feet.
re.prototype.scan_tokens = function scan_tokens(block) {
var i, move;
i = 0;
while (true) {
if (!(this.tokens[i])) {
break;
// Import the helpers we need.
include = helpers.include;
// The **Rewriter** class is used by the [Lexer](lexer.html), directly against
// its internal array of tokens.
exports.Rewriter = (function() {
Rewriter = function Rewriter() { };
// Rewrite the token stream in multiple passes, one logical filter at
// a time. This could certainly be changed into a single pass through the
// stream, with a big ol' efficient switch, but it's much nicer to work with
// like this. The order of these passes matters -- indentation must be
// corrected before implicit parentheses can be wrapped around blocks of code.
Rewriter.prototype.rewrite = function rewrite(tokens) {
this.tokens = tokens;
this.adjust_comments();
this.remove_leading_newlines();
this.remove_mid_expression_newlines();
this.close_open_calls_and_indexes();
this.add_implicit_indentation();
this.add_implicit_parentheses();
this.ensure_balance(BALANCED_PAIRS);
this.rewrite_closing_parens();
return this.tokens;
};
// Rewrite the token stream, looking one token ahead and behind.
// Allow the return value of the block to tell us how many tokens to move
// forwards (or backwards) in the stream, to make sure we don't miss anything
// as tokens are inserted and removed, and the stream changes length under
// our feet.
Rewriter.prototype.scan_tokens = function scan_tokens(block) {
var i, move;
i = 0;
while (true) {
if (!(this.tokens[i])) {
break;
}
move = block(this.tokens[i - 1], this.tokens[i], this.tokens[i + 1], i);
i += move;
}
move = block(this.tokens[i - 1], this.tokens[i], this.tokens[i + 1], i);
i += move;
}
return true;
};
// Massage newlines and indentations so that comments don't have to be
// correctly indented, or appear on their own line.
re.prototype.adjust_comments = function adjust_comments() {
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
var after, before;
if (!(token[0] === 'COMMENT')) {
return 1;
}
before = this.tokens[i - 2];
after = this.tokens[i + 2];
if (before && after && ((before[0] === 'INDENT' && after[0] === 'OUTDENT') || (before[0] === 'OUTDENT' && after[0] === 'INDENT')) && before[1] === after[1]) {
this.tokens.splice(i + 2, 1);
this.tokens.splice(i - 2, 1);
return 0;
} else if (prev && prev[0] === 'TERMINATOR' && after && after[0] === 'INDENT') {
this.tokens.splice(i + 2, 1);
this.tokens[i - 1] = after;
return 1;
} else if (prev && prev[0] !== 'TERMINATOR' && prev[0] !== 'INDENT' && prev[0] !== 'OUTDENT') {
this.tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]]);
return 2;
} else {
return 1;
}
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
// Leading newlines would introduce an ambiguity in the grammar, so we
// dispatch them here.
re.prototype.remove_leading_newlines = function remove_leading_newlines() {
if (this.tokens[0][0] === 'TERMINATOR') {
return this.tokens.shift();
}
};
// Some blocks occur in the middle of expressions -- when we're expecting
// this, remove their trailing newlines.
re.prototype.remove_mid_expression_newlines = function remove_mid_expression_newlines() {
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
if (!(post && EXPRESSION_CLOSE.indexOf(post[0]) >= 0 && token[0] === 'TERMINATOR')) {
return 1;
}
this.tokens.splice(i, 1);
return 0;
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
// Make sure that we don't accidentally break trailing commas, which need
// to go on the outside of expression closers.
re.prototype.move_commas_outside_outdents = function move_commas_outside_outdents() {
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
if (token[0] === 'OUTDENT' && prev[0] === ',') {
this.tokens.splice(i, 1, token);
}
return 1;
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
// We've tagged the opening parenthesis of a method call, and the opening
// bracket of an indexing operation. Match them with their close.
re.prototype.close_open_calls_and_indexes = function close_open_calls_and_indexes() {
var brackets, parens;
parens = [0];
brackets = [0];
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
var _i;
if ((_i = token[0]) === 'CALL_START') {
parens.push(0);
} else if (_i === 'INDEX_START') {
brackets.push(0);
} else if (_i === '(') {
parens[parens.length - 1] += 1;
} else if (_i === '[') {
brackets[brackets.length - 1] += 1;
} else if (_i === ')') {
if (parens[parens.length - 1] === 0) {
parens.pop();
token[0] = 'CALL_END';
} else {
parens[parens.length - 1] -= 1;
}
} else if (_i === ']') {
if (brackets[brackets.length - 1] === 0) {
brackets.pop();
token[0] = 'INDEX_END';
} else {
brackets[brackets.length - 1] -= 1;
}
}
return 1;
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
// Methods may be optionally called without parentheses, for simple cases.
// Insert the implicit parentheses here, so that the parser doesn't have to
// deal with them.
re.prototype.add_implicit_parentheses = function add_implicit_parentheses() {
var stack;
stack = [0];
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
var _i, _j, _k, _l, idx, last, size, stack_pointer, tag, tmp;
tag = token[0];
if (tag === 'INDENT') {
stack.push(0);
}
if (tag === 'OUTDENT') {
last = stack.pop();
stack[stack.length - 1] += last;
}
if (IMPLICIT_END.indexOf(tag) >= 0 || !(typeof post !== "undefined" && post !== null)) {
if (tag === 'INDENT' && prev && IMPLICIT_BLOCK.indexOf(prev[0]) >= 0) {
return true;
};
// Massage newlines and indentations so that comments don't have to be
// correctly indented, or appear on a line of their own.
Rewriter.prototype.adjust_comments = function adjust_comments() {
return this.scan_tokens(__bind(function(prev, token, post, i) {
var after;
if (!(token[0] === 'COMMENT')) {
return 1;
}
if (stack[stack.length - 1] > 0 || tag === 'INDENT') {
idx = tag === 'OUTDENT' ? i + 1 : i;
stack_pointer = tag === 'INDENT' ? 2 : 1;
_k = 0; _l = stack[stack.length - stack_pointer];
for (_j = 0, tmp=_k; (_k <= _l ? tmp < _l : tmp > _l); (_k <= _l ? tmp += 1 : tmp -= 1), _j++) {
this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
}
size = stack[stack.length - stack_pointer] + 1;
stack[stack.length - stack_pointer] = 0;
return size;
}
}
if (!(prev && IMPLICIT_FUNC.indexOf(prev[0]) >= 0 && IMPLICIT_CALL.indexOf(tag) >= 0)) {
return 1;
}
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
stack[stack.length - 1] += 1;
return 2;
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
// Because our grammar is LALR(1), it can't handle some single-line
// expressions that lack ending delimiters. Use the lexer to add the implicit
// blocks, so it doesn't need to.
// ')' can close a single-line block, but we need to make sure it's balanced.
re.prototype.add_implicit_indentation = function add_implicit_indentation() {
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
var idx, insertion, parens, starter, tok;
if (!(SINGLE_LINERS.indexOf(token[0]) >= 0 && post[0] !== 'INDENT' && !(token[0] === 'ELSE' && post[0] === 'IF'))) {
return 1;
}
starter = token[0];
this.tokens.splice(i + 1, 0, ['INDENT', 2, token[2]]);
idx = i + 1;
parens = 0;
while (true) {
idx += 1;
tok = this.tokens[idx];
if ((!tok || (SINGLE_CLOSERS.indexOf(tok[0]) >= 0 && tok[1] !== ';') || (tok[0] === ')' && parens === 0)) && !(starter === 'ELSE' && tok[0] === 'ELSE')) {
insertion = this.tokens[idx - 1][0] === "," ? idx - 1 : idx;
this.tokens.splice(insertion, 0, ['OUTDENT', 2, token[2]]);
break;
}
if (tok[0] === '(') {
parens += 1;
}
if (tok[0] === ')') {
parens -= 1;
}
}
if (!(token[0] === 'THEN')) {
return 1;
}
this.tokens.splice(i, 1);
return 0;
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
// Ensure that all listed pairs of tokens are correctly balanced throughout
// the course of the token stream.
re.prototype.ensure_balance = function ensure_balance(pairs) {
var _i, _j, key, levels, unclosed, value;
levels = {};
this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
var _i, _j, _k, close, open;
_i = pairs;
for (_j = 0; _j < _i.length; _j++) {
pair = _i[_j];
_k = pair;
open = _k[0];
close = _k[1];
levels[open] = levels[open] || 0;
if (token[0] === open) {
levels[open] += 1;
}
if (token[0] === close) {
levels[open] -= 1;
}
if (levels[open] < 0) {
throw new Error("too many " + token[1]);
}
}
return 1;
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
unclosed = (function() {
_i = []; _j = levels;
for (key in _j) { if (__hasProp.call(_j, key)) {
value = _j[key];
if (value > 0) {
_i.push(key);
}
}}
return _i;
}).call(this);
if (unclosed.length) {
throw new Error("unclosed " + unclosed[0]);
}
};
// We'd like to support syntax like this:
// el.click((event) ->
// el.hide())
// In order to accomplish this, move outdents that follow closing parens
// inwards, safely. The steps to accomplish this are:
//
// 1. Check that all paired tokens are balanced and in order.
// 2. Rewrite the stream with a stack: if you see an '(' or INDENT, add it
// to the stack. If you see an ')' or OUTDENT, pop the stack and replace
// it with the inverse of what we've just popped.
// 3. Keep track of "debt" for tokens that we fake, to make sure we end
// up balanced in the end.
//
re.prototype.rewrite_closing_parens = function rewrite_closing_parens() {
var _i, debt, key, stack, val;
stack = [];
debt = {};
_i = INVERSES;
for (key in _i) { if (__hasProp.call(_i, key)) {
val = _i[key];
((debt[key] = 0));
}}
return this.scan_tokens((function(__this) {
var __func = function(prev, token, post, i) {
var inv, match, mtag, tag;
tag = token[0];
inv = INVERSES[token[0]];
// Push openers onto the stack.
if (EXPRESSION_START.indexOf(tag) >= 0) {
stack.push(token);
return 1;
// The end of an expression, check stack and debt for a pair.
} else if (EXPRESSION_TAIL.indexOf(tag) >= 0) {
// If the tag is already in our debt, swallow it.
if (debt[inv] > 0) {
debt[inv] -= 1;
this.tokens.splice(i, 1);
return 0;
after = this.tokens[i + 2];
if (after && after[0] === 'INDENT') {
this.tokens.splice(i + 2, 1);
this.tokens.splice(i, 0, after);
return 1;
} else if (prev && prev[0] !== 'TERMINATOR' && prev[0] !== 'INDENT' && prev[0] !== 'OUTDENT') {
this.tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]]);
return 2;
} else {
// Pop the stack of open delimiters.
match = stack.pop();
mtag = match[0];
// Continue onwards if it's the expected tag.
if (tag === INVERSES[mtag]) {
return 1;
return 1;
}
}, this));
};
// Leading newlines would introduce an ambiguity in the grammar, so we
// dispatch them here.
Rewriter.prototype.remove_leading_newlines = function remove_leading_newlines() {
var _a;
_a = [];
while (this.tokens[0] && this.tokens[0][0] === 'TERMINATOR') {
_a.push(this.tokens.shift());
}
return _a;
};
// Some blocks occur in the middle of expressions -- when we're expecting
// this, remove their trailing newlines.
Rewriter.prototype.remove_mid_expression_newlines = function remove_mid_expression_newlines() {
return this.scan_tokens(__bind(function(prev, token, post, i) {
if (!(post && include(EXPRESSION_CLOSE, post[0]) && token[0] === 'TERMINATOR')) {
return 1;
}
this.tokens.splice(i, 1);
return 0;
}, this));
};
// The lexer has tagged the opening parenthesis of a method call, and the
// opening bracket of an indexing operation. Match them with their paired
// close.
Rewriter.prototype.close_open_calls_and_indexes = function close_open_calls_and_indexes() {
var brackets, parens;
parens = [0];
brackets = [0];
return this.scan_tokens(__bind(function(prev, token, post, i) {
var _a;
if ((_a = token[0]) === 'CALL_START') {
parens.push(0);
} else if (_a === 'INDEX_START') {
brackets.push(0);
} else if (_a === '(') {
parens[parens.length - 1] += 1;
} else if (_a === '[') {
brackets[brackets.length - 1] += 1;
} else if (_a === ')') {
if (parens[parens.length - 1] === 0) {
parens.pop();
token[0] = 'CALL_END';
} else {
// Unexpected close, insert correct close, adding to the debt.
parens[parens.length - 1] -= 1;
}
} else if (_a === ']') {
if (brackets[brackets.length - 1] === 0) {
brackets.pop();
token[0] = 'INDEX_END';
} else {
brackets[brackets.length - 1] -= 1;
}
}
return 1;
}, this));
};
// Methods may be optionally called without parentheses, for simple cases.
// Insert the implicit parentheses here, so that the parser doesn't have to
// deal with them.
Rewriter.prototype.add_implicit_parentheses = function add_implicit_parentheses() {
var calls, parens, stack, start_parens;
stack = [0];
calls = 0;
parens = 0;
start_parens = 0;
return this.scan_tokens(__bind(function(prev, token, post, i) {
var _a, _b, _c, idx, last, open, size, stack_pointer, tag, tmp;
tag = token[0];
if (tag === 'CALL_START') {
calls += 1;
} else if (tag === 'CALL_END') {
calls -= 1;
} else if (tag === '(') {
parens += 1;
} else if (tag === ')') {
parens -= 1;
} else if (tag === 'INDENT') {
stack.push(0);
} else if (tag === 'OUTDENT') {
last = stack.pop();
stack[stack.length - 1] += last;
}
open = stack[stack.length - 1] > 0;
if (!(typeof post !== "undefined" && post !== null) || (start_parens > parens) || (parens === 0 && include(IMPLICIT_END, tag))) {
if (tag === 'INDENT' && prev && include(IMPLICIT_BLOCK, prev[0])) {
return 1;
}
if (tag === 'OUTDENT' && token.generated) {
return 1;
}
if (open || tag === 'INDENT') {
idx = tag === 'OUTDENT' ? i + 1 : i;
stack_pointer = tag === 'INDENT' ? 2 : 1;
_b = 0; _c = stack[stack.length - stack_pointer];
for (_a = 0, tmp = _b; (_b <= _c ? tmp < _c : tmp > _c); (_b <= _c ? tmp += 1 : tmp -= 1), _a++) {
this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
}
size = stack[stack.length - stack_pointer] + 1;
stack[stack.length - stack_pointer] = 0;
return size;
}
}
if (!(prev && include(IMPLICIT_FUNC, prev[0]) && include(IMPLICIT_CALL, tag))) {
return 1;
}
calls = 0;
start_parens = tag === '(' ? parens - 1 : parens;
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
stack[stack.length - 1] += 1;
return 2;
}, this));
};
// Because our grammar is LALR(1), it can't handle some single-line
// expressions that lack ending delimiters. The **Rewriter** adds the implicit
// blocks, so it doesn't need to. ')' can close a single-line block,
// but we need to make sure it's balanced.
Rewriter.prototype.add_implicit_indentation = function add_implicit_indentation() {
return this.scan_tokens(__bind(function(prev, token, post, i) {
var idx, insertion, outdent, parens, pre, starter, tok;
if (!(include(SINGLE_LINERS, token[0]) && post[0] !== 'INDENT' && !(token[0] === 'ELSE' && post[0] === 'IF'))) {
return 1;
}
starter = token[0];
this.tokens.splice(i + 1, 0, ['INDENT', 2, token[2]]);
idx = i + 1;
parens = 0;
while (true) {
idx += 1;
tok = this.tokens[idx];
pre = this.tokens[idx - 1];
if ((!tok || (include(SINGLE_CLOSERS, tok[0]) && tok[1] !== ';') || (tok[0] === ')' && parens === 0)) && !(starter === 'ELSE' && tok[0] === 'ELSE')) {
insertion = pre[0] === "," ? idx - 1 : idx;
outdent = ['OUTDENT', 2, token[2]];
outdent.generated = true;
this.tokens.splice(insertion, 0, outdent);
break;
}
if (tok[0] === '(') {
parens += 1;
}
if (tok[0] === ')') {
parens -= 1;
}
}
if (!(token[0] === 'THEN')) {
return 1;
}
this.tokens.splice(i, 1);
return 0;
}, this));
};
// Ensure that all listed pairs of tokens are correctly balanced throughout
// the course of the token stream.
Rewriter.prototype.ensure_balance = function ensure_balance(pairs) {
var _a, _b, key, levels, line, open, open_line, unclosed, value;
levels = {};
open_line = {};
this.scan_tokens(__bind(function(prev, token, post, i) {
var _a, _b, _c, _d, close, open, pair;
_b = pairs;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
pair = _b[_a];
_d = pair;
open = _d[0];
close = _d[1];
levels[open] = levels[open] || 0;
if (token[0] === open) {
if (levels[open] === 0) {
open_line[open] = token[2];
}
levels[open] += 1;
}
if (token[0] === close) {
levels[open] -= 1;
}
if (levels[open] < 0) {
throw new Error("too many " + (token[1]) + " on line " + (token[2] + 1));
}
}
return 1;
}, this));
unclosed = (function() {
_a = []; _b = levels;
for (key in _b) { if (__hasProp.call(_b, key)) {
value = _b[key];
value > 0 ? _a.push(key) : null;
}}
return _a;
}).call(this);
if (unclosed.length) {
open = unclosed[0];
line = open_line[open] + 1;
throw new Error("unclosed " + open + " on line " + line);
}
};
// We'd like to support syntax like this:
// el.click((event) ->
// el.hide())
// In order to accomplish this, move outdents that follow closing parens
// inwards, safely. The steps to accomplish this are:
// 1. Check that all paired tokens are balanced and in order.
// 2. Rewrite the stream with a stack: if you see an `EXPRESSION_START`, add it
// to the stack. If you see an `EXPRESSION_END`, pop the stack and replace
// it with the inverse of what we've just popped.
// 3. Keep track of "debt" for tokens that we manufacture, to make sure we end
// up balanced in the end.
Rewriter.prototype.rewrite_closing_parens = function rewrite_closing_parens() {
var _a, debt, key, stack, val;
stack = [];
debt = {};
_a = INVERSES;
for (key in _a) { if (__hasProp.call(_a, key)) {
val = _a[key];
(debt[key] = 0);
}}
return this.scan_tokens(__bind(function(prev, token, post, i) {
var inv, match, mtag, tag;
tag = token[0];
inv = INVERSES[token[0]];
if (include(EXPRESSION_START, tag)) {
stack.push(token);
return 1;
} else if (include(EXPRESSION_END, tag)) {
if (debt[inv] > 0) {
debt[inv] -= 1;
this.tokens.splice(i, 1);
return 0;
} else {
match = stack.pop();
mtag = match[0];
if (tag === INVERSES[mtag]) {
return 1;
}
debt[mtag] += 1;
val = mtag === 'INDENT' ? match[1] : INVERSES[mtag];
this.tokens.splice(i, 0, [INVERSES[mtag], val]);
return 1;
}
} else {
return 1;
}
} else {
return 1;
}
};
return (function() {
return __func.apply(__this, arguments);
});
})(this));
};
}, this));
};
return Rewriter;
}).call(this);
// Constants
// ---------
// List of the token pairs that must be balanced.
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'], ['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']];
// The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
// look things up from either end.
INVERSES = {};
_b = BALANCED_PAIRS;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
pair = _b[_a];
INVERSES[pair[0]] = pair[1];
INVERSES[pair[1]] = pair[0];
}
// The tokens that signal the start of a balanced pair.
EXPRESSION_START = (function() {
_d = []; _f = BALANCED_PAIRS;
for (_e = 0, _g = _f.length; _e < _g; _e++) {
pair = _f[_e];
_d.push(pair[0]);
}
return _d;
}).call(this);
// The tokens that signal the end of a balanced pair.
EXPRESSION_END = (function() {
_h = []; _j = BALANCED_PAIRS;
for (_i = 0, _k = _j.length; _i < _k; _i++) {
pair = _j[_i];
_h.push(pair[1]);
}
return _h;
}).call(this);
// Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
// Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-'];
// If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT', 'THIS', 'NULL', '@', '->', '=>', '[', '(', '{'];
// Tokens indicating that the implicit call must enclose a block of expressions.
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
// Tokens that always mark the end of an implicit call for single-liners.
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT'];
// Single-line flavors of block expressions that have unclosed endings.
// The grammar can't disambiguate them, so we insert the implicit indentation.
SINGLE_LINERS = ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN'];
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
})();

View File

@@ -1,114 +1,137 @@
(function(){
var Scope;
var __hasProp = Object.prototype.hasOwnProperty;
// The **Scope** class regulates lexical scoping within CoffeeScript. As you
// generate code, you create a tree of scopes in the same shape as the nested
// function bodies. Each scope knows about the variables declared within it,
// and has a reference to its parent enclosing scope. In this way, we know which
// variables are new and need to be declared with `var`, and which are shared
// with the outside.
// Set up exported variables for both **Node.js** and the browser.
if (!((typeof process !== "undefined" && process !== null))) {
this.exports = this;
}
// Scope objects form a tree corresponding to the shape of the function
// definitions present in the script. They provide lexical scope, to determine
// whether a variable has been seen before or if it needs to be declared.
//
// Initialize a scope with its parent, for lookups up the chain,
// as well as the Expressions body where it should declare its variables,
// and the function that it wraps.
Scope = (exports.Scope = function Scope(parent, expressions, method) {
var _a;
_a = [parent, expressions, method];
this.parent = _a[0];
this.expressions = _a[1];
this.method = _a[2];
this.variables = {};
this.temp_var = this.parent ? this.parent.temp_var : '_a';
return this;
});
// Look up a variable in lexical scope, or declare it if not found.
Scope.prototype.find = function find(name) {
if (this.check(name)) {
return true;
}
this.variables[name] = 'var';
return false;
};
// Define a local variable as originating from a parameter in current scope
// -- no var required.
Scope.prototype.parameter = function parameter(name) {
return this.variables[name] = 'param';
};
// Just check to see if a variable has already been declared.
Scope.prototype.check = function check(name) {
if (this.variables[name]) {
return true;
}
return !!(this.parent && this.parent.check(name));
};
// You can reset a found variable on the immediate scope.
Scope.prototype.reset = function reset(name) {
return delete this.variables[name];
};
// Find an available, short, name for a compiler-generated variable.
Scope.prototype.free_variable = function free_variable() {
var ordinal;
while (this.check(this.temp_var)) {
ordinal = 1 + parseInt(this.temp_var.substr(1), 36);
this.temp_var = '_' + ordinal.toString(36).replace(/\d/g, 'a');
}
this.variables[this.temp_var] = 'var';
return this.temp_var;
};
// Ensure that an assignment is made at the top of scope (or top-level
// scope, if requested).
Scope.prototype.assign = function assign(name, value, top_level) {
if (top_level && this.parent) {
return this.parent.assign(name, value, top_level);
}
return this.variables[name] = {
value: value,
assigned: true
exports.Scope = (function() {
Scope = function Scope(parent, expressions, method) {
var _a;
_a = [parent, expressions, method];
this.parent = _a[0];
this.expressions = _a[1];
this.method = _a[2];
this.variables = {};
if (this.parent) {
this.temp_var = this.parent.temp_var;
} else {
Scope.root = this;
this.temp_var = '_a';
}
return this;
};
};
// Does this scope reference any variables that need to be declared in the
// given function body?
Scope.prototype.has_declarations = function has_declarations(body) {
return body === this.expressions && this.declared_variables().length;
};
// Does this scope reference any assignments that need to be declared at the
// top of the given function body?
Scope.prototype.has_assignments = function has_assignments(body) {
return body === this.expressions && this.assigned_variables().length;
};
// Return the list of variables first declared in current scope.
Scope.prototype.declared_variables = function declared_variables() {
var _a, _b, key, val;
return (function() {
// The top-level **Scope** object.
Scope.root = null;
// Initialize a scope with its parent, for lookups up the chain,
// as well as a reference to the **Expressions** node is belongs to, which is
// where it should declare its variables, and a reference to the function that
// it wraps.
// Look up a variable name in lexical scope, and declare it if it does not
// already exist.
Scope.prototype.find = function find(name) {
if (this.check(name)) {
return true;
}
this.variables[name] = 'var';
return false;
};
// Test variables and return true the first time fn(v, k) returns true
Scope.prototype.any = function any(fn) {
var _a, k, v;
_a = this.variables;
for (v in _a) { if (__hasProp.call(_a, v)) {
k = _a[v];
if (fn(v, k)) {
return true;
}
}}
return false;
};
// Reserve a variable name as originating from a function parameter for this
// scope. No `var` required for internal references.
Scope.prototype.parameter = function parameter(name) {
this.variables[name] = 'param';
return this.variables[name];
};
// Just check to see if a variable has already been declared, without reserving.
Scope.prototype.check = function check(name) {
if (this.variables[name]) {
return true;
}
return !!(this.parent && this.parent.check(name));
};
// If we need to store an intermediate result, find an available name for a
// compiler-generated variable. `_a`, `_b`, and so on...
Scope.prototype.free_variable = function free_variable() {
var ordinal;
while (this.check(this.temp_var)) {
ordinal = 1 + parseInt(this.temp_var.substr(1), 36);
this.temp_var = '_' + ordinal.toString(36).replace(/\d/g, 'a');
}
this.variables[this.temp_var] = 'var';
return this.temp_var;
};
// Ensure that an assignment is made at the top of this scope
// (or at the top-level scope, if requested).
Scope.prototype.assign = function assign(name, value) {
this.variables[name] = {
value: value,
assigned: true
};
return this.variables[name];
};
// Does this scope reference any variables that need to be declared in the
// given function body?
Scope.prototype.has_declarations = function has_declarations(body) {
return body === this.expressions && this.any(function(k, val) {
return val === 'var';
});
};
// Does this scope reference any assignments that need to be declared at the
// top of the given function body?
Scope.prototype.has_assignments = function has_assignments(body) {
return body === this.expressions && this.any(function(k, val) {
return val.assigned;
});
};
// Return the list of variables first declared in this scope.
Scope.prototype.declared_variables = function declared_variables() {
var _a, _b, key, val;
return (function() {
_a = []; _b = this.variables;
for (key in _b) { if (__hasProp.call(_b, key)) {
val = _b[key];
val === 'var' ? _a.push(key) : null;
}}
return _a;
}).call(this).sort();
};
// Return the list of assignments that are supposed to be made at the top
// of this scope.
Scope.prototype.assigned_variables = function assigned_variables() {
var _a, _b, key, val;
_a = []; _b = this.variables;
for (key in _b) { if (__hasProp.call(_b, key)) {
val = _b[key];
if (val === 'var') {
_a.push(key);
}
val.assigned ? _a.push("" + key + " = " + (val.value)) : null;
}}
return _a;
}).call(this).sort();
};
// Return the list of variables that are supposed to be assigned at the top
// of scope.
Scope.prototype.assigned_variables = function assigned_variables() {
var _a, _b, key, val;
_a = []; _b = this.variables;
for (key in _b) { if (__hasProp.call(_b, key)) {
val = _b[key];
if (val.assigned) {
_a.push(key + ' = ' + val.value);
}
}}
return _a;
};
// Compile the string representing all of the declared variables for this scope.
Scope.prototype.compiled_declarations = function compiled_declarations() {
return this.declared_variables().join(', ');
};
// Compile the string performing all of the variable assignments for this scope.
Scope.prototype.compiled_assignments = function compiled_assignments() {
return this.assigned_variables().join(', ');
};
};
// Compile the JavaScript for all of the variable declarations in this scope.
Scope.prototype.compiled_declarations = function compiled_declarations() {
return this.declared_variables().join(', ');
};
// Compile the JavaScript for all of the variable assignments in this scope.
Scope.prototype.compiled_assignments = function compiled_assignments() {
return this.assigned_variables().join(', ');
};
return Scope;
}).call(this);
})();

12
lib/utilities.js Normal file
View File

@@ -0,0 +1,12 @@
(function(){
if (!((typeof process !== "undefined" && process !== null))) {
this.exports = this;
}
exports.utilities = {
extend: "function(child, parent) {\n var ctor = function(){ };\n ctor.prototype = parent.prototype;\n child.__superClass__ = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n }",
bind: "function(func, obj, args) {\n return function() {\n return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);\n };\n }",
range: "function(array, from, to, exclusive) {\n return [\n (from < 0 ? from + array.length : from || 0),\n (to < 0 ? to + array.length : to || array.length) + (exclusive ? 0 : 1)\n ];\n }",
hasProp: 'Object.prototype.hasOwnProperty',
slice: 'Array.prototype.slice'
};
})();

View File

@@ -3,5 +3,5 @@
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language"],
"author": "Jeremy Ashkenas",
"version": "0.5.2"
"version": "0.6.0"
}

View File

@@ -1,45 +1,68 @@
# `cake` is a simplified version of Make (Rake, Jake) for CoffeeScript.
# `cake` is a simplified version of [Make](http://www.gnu.org/software/make/)
# ([Rake](http://rake.rubyforge.org/), [Jake](http://github.com/280north/jake))
# for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
# and can call them from the command line, or invoke them from other tasks.
#
# Running `cake` with no arguments will print out a list of all the tasks in the
# current directory's Cakefile.
fs: require 'fs'
path: require 'path'
coffee: require 'coffee-script'
# External dependencies.
fs: require 'fs'
path: require 'path'
helpers: require('./helpers').helpers
optparse: require './optparse'
CoffeeScript: require './coffee-script'
# Keep track of the list of defined tasks, the accepted options, and so on.
tasks: {}
options: {}
switches: []
oparse: null
no_such_task: (task) ->
process.stdio.writeError('No such task: "' + task + '"\n')
process.exit(1)
# Mixin the top-level Cake functions for Cakefiles to use directly.
helpers.extend global, {
# Mixin the Cake functionality.
process.mixin {
# Define a task with a name, a description, and the action itself.
# Define a Cake task with a short name, a sentence description,
# and the function to run as the action itself.
task: (name, description, action) ->
tasks[name]: {name: name, description: description, action: action}
# Invoke another task in the Cakefile.
# Define an option that the Cakefile accepts. The parsed options hash,
# containing all of the command-line options passed, will be made available
# as the first argument to the action.
option: (letter, flag, description) ->
switches.push [letter, flag, description]
# Invoke another task in the current Cakefile.
invoke: (name) ->
no_such_task name unless tasks[name]
tasks[name].action()
tasks[name].action options
}
# Display the list of Cake tasks.
# Run `cake`. Executes all of the tasks you pass, in order. Note that Node's
# asynchrony may cause tasks to execute in a different order than you'd expect.
# If no tasks are passed, print the help screen.
exports.run: ->
path.exists 'Cakefile', (exists) ->
throw new Error("Cakefile not found in ${process.cwd()}") unless exists
args: process.argv[2...process.argv.length]
CoffeeScript.run fs.readFileSync('Cakefile'), {source: 'Cakefile'}
oparse: new optparse.OptionParser switches
return print_tasks() unless args.length
options: oparse.parse(args)
invoke arg for arg in options.arguments
# Display the list of Cake tasks in a format similar to `rake -T`
print_tasks: ->
puts ''
for name, task of tasks
spaces: 20 - name.length
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
puts "cake " + name + spaces + ' # ' + task.description
# Running `cake` runs the tasks you pass asynchronously (node-style), or
# prints them out, with no arguments.
exports.run: ->
path.exists 'Cakefile', (exists) ->
throw new Error('Cakefile not found in ' + process.cwd()) unless exists
args: process.ARGV[2...process.ARGV.length]
fs.readFile 'Cakefile', (err, source) ->
eval coffee.compile source
return print_tasks() unless args.length
for arg in args
no_such_task arg unless tasks[arg]
tasks[arg].action()
puts "cake $name$spaces # ${task.description}"
puts oparse.help() if switches.length
# Print an error and exit when attempting to all an undefined task.
no_such_task: (task) ->
process.stdio.writeError "No such task: \"$task\"\n"
process.exit 1

View File

@@ -1,19 +1,74 @@
# Set up for both the browser and the server.
if process?
process.mixin require 'nodes'
path: require 'path'
lexer: new (require('lexer').Lexer)()
parser: require('parser').parser
else
lexer: new Lexer()
parser: exports.parser
this.exports: this.CoffeeScript: {}
# CoffeeScript can be used both on the server, as a command-line compiler based
# on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
# contains the main entry functions for tokenzing, parsing, and compiling source
# CoffeeScript into JavaScript.
#
# If included on a webpage, it will automatically sniff out, compile, and
# execute all scripts present in `text/coffeescript` tags.
# Thin wrapper for Jison compatibility around the real lexer.
# Set up dependencies correctly for both the server and the browser.
if process?
path: require 'path'
Lexer: require('./lexer').Lexer
parser: require('./parser').parser
helpers: require('./helpers').helpers
helpers.extend global, require './nodes'
if require.registerExtension
require.registerExtension '.coffee', (content) -> compile content
else
this.exports: this.CoffeeScript: {}
Lexer: this.Lexer
parser: this.parser
helpers: this.helpers
# The current CoffeeScript version number.
exports.VERSION: '0.6.0'
# Instantiate a Lexer for our use here.
lexer: new Lexer()
# Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
# compiler.
exports.compile: compile: (code, options) ->
options: or {}
try
(parser.parse lexer.tokenize code).compile options
catch err
err.message: "In ${options.source}, ${err.message}" if options.source
throw err
# Tokenize a string of CoffeeScript code, and return the array of tokens.
exports.tokens: (code) ->
lexer.tokenize code
# Tokenize and parse a string of CoffeeScript code, and return the AST. You can
# then compile it by calling `.compile()` on the root, or traverse it by using
# `.traverse()` with a callback.
exports.nodes: (code) ->
parser.parse lexer.tokenize code
# Compile and execute a string of CoffeeScript (on the server), correctly
# setting `__filename`, `__dirname`, and relative `require()`.
exports.run: ((code, options) ->
module.filename: __filename: options.source
__dirname: path.dirname(__filename)
eval exports.compile code, options
)
# Extend CoffeeScript with a custom language extension. It should hook in to
# the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
# push a token on to the stack that contains a **Node** as the value (as a
# peer of the nodes in [nodes.coffee](nodes.html)).
exports.extend: (func) ->
Lexer.extensions.push func
# The real Lexer produces a generic stream of tokens. This object provides a
# thin wrapper around it, compatible with the Jison API. We can then pass it
# directly as a "Jison lexer".
parser.lexer: {
lex: ->
token: @tokens[@pos] or [""]
@pos += 1
@pos: + 1
this.yylineno: token[2]
this.yytext: token[1]
token[0]
@@ -24,22 +79,15 @@ parser.lexer: {
showPosition: -> @pos
}
exports.VERSION: '0.5.2'
# Compile CoffeeScript to JavaScript, using the Coffee/Jison compiler.
exports.compile: (code, options) ->
(parser.parse lexer.tokenize code).compile(options)
# Just the tokens.
exports.tokenize: (code) ->
lexer.tokenize code
# Just the nodes.
exports.tree: (code) ->
parser.parse lexer.tokenize code
# Activate CoffeeScript in the browser by having it compile and eval
# all script tags with a content-type of text/coffeescript.
# Activate CoffeeScript in the browser by having it compile and evaluate
# all script tags with a content-type of `text/coffeescript`. This happens
# on page load. Unfortunately, the text contents of remote scripts cannot be
# accessed from the browser, so only inline script tags will work.
if document? and document.getElementsByTagName
for tag in document.getElementsByTagName('script') when tag.type is 'text/coffeescript'
eval exports.compile tag.innerHTML
process_scripts: ->
for tag in document.getElementsByTagName('script') when tag.type is 'text/coffeescript'
eval exports.compile tag.innerHTML
if window.addEventListener
window.addEventListener 'load', process_scripts, false
else if window.attachEvent
window.attachEvent 'onload', process_scripts

161
src/command.coffee Normal file
View File

@@ -0,0 +1,161 @@
# The `coffee` utility. Handles command-line compilation of CoffeeScript
# into various forms: saved into `.js` files or printed to stdout, piped to
# [JSLint](http://javascriptlint.com/) or recompiled every time the source is
# saved, printed as a token stream or as the syntax tree, or launch an
# interactive REPL.
# External dependencies.
fs: require 'fs'
path: require 'path'
optparse: require './optparse'
CoffeeScript: require './coffee-script'
# The help banner that is printed when `coffee` is called without arguments.
BANNER: '''
coffee compiles CoffeeScript source files into JavaScript.
Usage:
coffee path/to/script.coffee
'''
# The list of all the valid option flags that `coffee` knows how to handle.
SWITCHES: [
['-c', '--compile', 'compile to JavaScript and save as .js files']
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
['-o', '--output [DIR]', 'set the directory for compiled JavaScript']
['-w', '--watch', 'watch scripts for changes, and recompile']
['-p', '--print', 'print the compiled JavaScript to stdout']
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
['-s', '--stdio', 'listen for and compile scripts over stdio']
['-e', '--eval', 'compile a string from the command line']
[ '--no-wrap', 'compile without the top-level function wrapper']
['-t', '--tokens', 'print the tokens that the lexer produces']
['-n', '--nodes', 'print the parse tree that Jison produces']
['-v', '--version', 'display CoffeeScript version']
['-h', '--help', 'display this help message']
]
# Top-level objects shared by all the functions.
options: {}
sources: []
option_parser: null
# Run `coffee` by parsing passed options and determining what action to take.
# Many flags cause us to divert before compiling anything. Flags passed after
# `--` will be passed verbatim to your script as arguments in `process.argv`
exports.run: ->
parse_options()
return usage() if options.help
return version() if options.version
return require './repl' if options.interactive
return compile_stdio() if options.stdio
return compile_script 'console', sources[0] if options.eval
return usage() unless sources.length
separator: sources.indexOf '--'
flags: []
if separator >= 0
flags: sources[(separator + 1)...sources.length]
sources: sources[0...separator]
process.ARGV: process.argv: flags
watch_scripts() if options.watch
compile_scripts()
# Asynchronously read in each CoffeeScript in a list of source files and
# compile them.
compile_scripts: ->
compile: (source) ->
path.exists source, (exists) ->
throw new Error "File not found: $source" unless exists
fs.readFile source, (err, code) -> compile_script(source, code)
compile(source) for source in sources
# Compile a single source script, containing the given code, according to the
# requested options. Both compile_scripts and watch_scripts share this method
# in common. If evaluating the script directly sets `__filename`, `__dirname`
# and `module.filename` to be correct relative to the script's path.
compile_script: (source, code) ->
o: options
code_opts: compile_options source
try
if o.tokens then print_tokens CoffeeScript.tokens code
else if o.nodes then puts CoffeeScript.nodes(code).toString()
else if o.run then CoffeeScript.run code, code_opts
else
js: CoffeeScript.compile code, code_opts
if o.print then process.stdio.write js
else if o.compile then write_js source, js
else if o.lint then lint js
catch err
if o.watch then puts err.message else throw err
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
# and write them back to **stdout**.
compile_stdio: ->
code: ''
process.stdio.open()
process.stdio.addListener 'data', (string) ->
code: + string if string
process.stdio.addListener 'close', ->
compile_script 'stdio', code
# Watch a list of source CoffeeScript files using `fs.watchFile`, recompiling
# them every time the files are updated. May be used in combination with other
# options, such as `--lint` or `--print`.
watch_scripts: ->
watch: (source) ->
fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
return if curr.mtime.getTime() is prev.mtime.getTime()
fs.readFile source, (err, code) -> compile_script(source, code)
watch(source) for source in sources
# Write out a JavaScript source file with the compiled code. By default, files
# are written out in `cwd` as `.js` files with the same name, but the output
# directory can be customized with `--output`.
write_js: (source, js) ->
filename: path.basename(source, path.extname(source)) + '.js'
dir: options.output or path.dirname(source)
js_path: path.join dir, filename
fs.writeFile js_path, js
# Pipe compiled JS through JSLint (requires a working `jsl` command), printing
# any errors or warnings that arise.
lint: (js) ->
jsl: process.createChildProcess('jsl', ['-nologo', '-stdin'])
jsl.addListener 'output', (result) ->
puts result.replace(/\n/g, '') if result
jsl.addListener 'error', (result) ->
puts result if result
jsl.write js
jsl.close()
# Pretty-print a stream of tokens.
print_tokens: (tokens) ->
strings: for token in tokens
[tag, value]: [token[0], token[1].toString().replace(/\n/, '\\n')]
"[$tag $value]"
puts strings.join(' ')
# Use the [OptionParser module](optparse.html) to extract all options from
# `process.argv` that are specified in `SWITCHES`.
parse_options: ->
option_parser: new optparse.OptionParser SWITCHES, BANNER
o: options: option_parser.parse(process.argv)
options.run: not (o.compile or o.print or o.lint)
options.print: !! (o.print or (o.eval or o.stdio and o.compile))
sources: options.arguments[2...options.arguments.length]
# The compile-time options to pass to the CoffeeScript compiler.
compile_options: (source) ->
o: {source: source}
o['no_wrap']: options['no-wrap']
o
# Print the `--help` usage message and exit.
usage: ->
puts option_parser.help()
process.exit 0
# Print the `--version` message and exit.
version: ->
puts "CoffeeScript version ${CoffeeScript.VERSION}"
process.exit 0

View File

@@ -1,134 +0,0 @@
fs: require 'fs'
path: require 'path'
optparse: require 'optparse'
CoffeeScript: require 'coffee-script'
BANNER: '''
coffee compiles CoffeeScript source files into JavaScript.
Usage:
coffee path/to/script.coffee
'''
SWITCHES: [
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
['-r', '--run', 'compile and run a CoffeeScript']
['-o', '--output [DIR]', 'set the directory for compiled JavaScript']
['-w', '--watch', 'watch scripts for changes, and recompile']
['-p', '--print', 'print the compiled JavaScript to stdout']
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
['-s', '--stdio', 'listen for and compile scripts over stdio']
['-e', '--eval', 'compile a string from the command line']
['-n', '--no-wrap', 'compile without the top-level function wrapper']
['-t', '--tokens', 'print the tokens that the lexer produces']
['-tr','--tree', 'print the parse tree that Jison produces']
['-v', '--version', 'display CoffeeScript version']
['-h', '--help', 'display this help message']
]
options: {}
sources: []
option_parser: null
# The CommandLine handles all of the functionality of the `coffee` utility.
exports.run: ->
parse_options()
return usage() if options.help
return version() if options.version
return require 'repl' if options.interactive
return compile_stdio() if options.stdio
return compile_script 'unknown', sources[0] if options.eval
return usage() unless sources.length
separator: sources.indexOf '--'
flags: []
if separator >= 0
flags: sources[(separator + 1)...sources.length]
sources: sources[0...separator]
process.ARGV = flags
watch_scripts() if options.watch
compile_scripts()
this
# The "--help" usage message.
usage: ->
puts '\n' + option_parser.help() + '\n'
process.exit 0
# The "--version" message.
version: ->
puts "CoffeeScript version " + CoffeeScript.VERSION
process.exit 0
# Compiles the source CoffeeScript, returning the desired JavaScript, tokens,
# or JSLint results.
compile_scripts: ->
compile: (source) ->
fs.readFile source, (err, code) -> compile_script(source, code)
compile(source) for source in sources
# Compile a single source script, containing the given code, according to the
# requested options. Both compile_scripts and watch_scripts share this method.
compile_script: (source, code) ->
o: options
try
if o.tokens then print_tokens CoffeeScript.tokenize code
else if o.tree then puts CoffeeScript.tree(code).toString()
else
js: CoffeeScript.compile code, compile_options()
if o.run then eval js
else if o.lint then lint js
else if o.print or o.eval then print js
else write_js source, js
catch err
if o.watch then puts err.message else throw err
# Listen for and compile scripts over stdio.
compile_stdio: ->
code: ''
process.stdio.open()
process.stdio.addListener 'data', (string) ->
code += string if string
process.stdio.addListener 'close', ->
process.stdio.write CoffeeScript.compile code, compile_options()
# Watch a list of source CoffeeScript files, recompiling them every time the
# files are updated.
watch_scripts: ->
watch: (source) ->
process.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
return if curr.mtime.getTime() is prev.mtime.getTime()
fs.readFile source, (err, code) -> compile_script(source, code)
watch(source) for source in sources
# Write out a JavaScript source file with the compiled code.
write_js: (source, js) ->
filename: path.basename(source, path.extname(source)) + '.js'
dir: options.output or path.dirname(source)
js_path: path.join dir, filename
fs.writeFile js_path, js
# Pipe compiled JS through JSLint (requires a working 'jsl' command).
lint: (js) ->
jsl: process.createChildProcess('jsl', ['-nologo', '-stdin'])
jsl.addListener 'output', (result) ->
puts result.replace(/\n/g, '') if result
jsl.addListener 'error', (result) ->
puts result if result
jsl.write js
jsl.close()
# Pretty-print a token stream.
print_tokens: (tokens) ->
strings: for token in tokens
'[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']'
puts strings.join(' ')
# Use OptionParser for all the options.
parse_options: ->
option_parser: new optparse.OptionParser SWITCHES, BANNER
options: option_parser.parse(process.ARGV)
sources: options.arguments[2...options.arguments.length]
# The options to pass to the CoffeeScript compiler.
compile_options: ->
if options['no-wrap'] then {no_wrap: true} else {}

View File

@@ -1,66 +1,80 @@
# The CoffeeScript parser is generated by [Jison](http://github.com/zaach/jison)
# from this grammar file. Jison is a bottom-up parser generator, similar in
# style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript.
# It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](http://en.wikipedia.org/wiki/LR_grammar)
# type grammars. To create the Jison parser, we list the pattern to match
# on the left-hand side, and the action to take (usually the creation of syntax
# tree nodes) on the right. As the parser runs, it
# shifts tokens from our token stream, from left to right, and
# [attempts to match](http://en.wikipedia.org/wiki/Bottom-up_parsing)
# the token sequence against the rules below. When a match can be made, it
# reduces into the [nonterminal](http://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols)
# (the enclosing name at the top), and we proceed from there.
#
# If you run the `cake build:parser` command, Jison constructs a parse table
# from our rules and saves it into `lib/parser.js`.
# The only dependency is on the **Jison.Parser**.
Parser: require('jison').Parser
# DSL ===================================================================
# Jison DSL
# ---------
# Detect functions: [
# Since we're going to be wrapped in a function by Jison in any case, if our
# action immediately returns a value, we can optimize by removing the function
# wrapper and just returning the value directly.
unwrap: /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
# Quickie DSL for Jison access.
o: (pattern_string, func, options) ->
if func
func: if match: (func + "").match(unwrap) then match[1] else '(' + func + '())'
[pattern_string, '$$ = ' + func + ';', options]
else
[pattern_string, '$$ = $1;', options]
# Our handy DSL for Jison grammar generation, thanks to
# [Tim Caswell](http://github.com/creationix). For every rule in the grammar,
# we pass the pattern-defining string, the action to run, and extra options,
# optionally. If no action is specified, we simply pass the value of the
# previous nonterminal.
o: (pattern_string, action, options) ->
return [pattern_string, '$$ = $1;', options] unless action
action: if match: (action + '').match(unwrap) then match[1] else "($action())"
[pattern_string, "$$ = $action;", options]
# Precedence ===========================================================
operators: [
["left", '?']
["nonassoc", 'UMINUS', 'UPLUS', 'NOT', '!', '!!', '~', '++', '--']
["left", '*', '/', '%']
["left", '+', '-']
["left", '<<', '>>', '>>>']
["left", '&', '|', '^']
["left", '<=', '<', '>', '>=']
["right", 'DELETE', 'INSTANCEOF', 'TYPEOF']
["right", '==', '!=', 'IS', 'ISNT']
["left", '&&', '||', 'AND', 'OR']
["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=']
["left", '.']
["right", 'INDENT']
["left", 'OUTDENT']
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
["right", 'FOR', 'NEW', 'SUPER']
["left", 'EXTENDS']
["right", 'ASSIGN', 'RETURN']
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']
]
# Grammar ==============================================================
# Grammatical Rules
# -----------------
# In all of the rules that follow, you'll see the name of the nonterminal as
# the key to a list of alternative matches. With each match's action, the
# dollar-sign variables are provided by Jison as references to the value of
# their numeric position, so in this rule:
#
# "Expression UNLESS Expression"
#
# `$1` would be the value of the first `Expression`, `$2` would be the token
# for the `UNLESS` terminal, and `$3` would be the value of the second
# `Expression`.
grammar: {
# All parsing will end in this rule, being the trunk of the AST.
# The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
# all parsing must end here.
Root: [
o "", -> new Expressions()
o "TERMINATOR", -> new Expressions()
o "Expressions", -> $1
o "Block TERMINATOR", -> $1
o "", -> new Expressions()
o "TERMINATOR", -> new Expressions()
o "Expressions"
o "Block TERMINATOR"
]
# Any list of expressions or method body, seperated by line breaks or semis.
# Any list of expressions or method body, seperated by line breaks or
# semicolons.
Expressions: [
o "Expression", -> Expressions.wrap([$1])
o "Expressions TERMINATOR Expression", -> $1.push($3)
o "Expressions TERMINATOR", -> $1
o "Expression", -> Expressions.wrap [$1]
o "Expressions TERMINATOR Expression", -> $1.push $3
o "Expressions TERMINATOR"
]
# All types of expressions in our language. The basic unit of CoffeeScript
# is the expression.
# All the different types of expressions in our language. The basic unit of
# CoffeeScript is the **Expression** -- you'll notice that there is no
# "statement" nonterminal. Expressions serve as the building blocks
# of many other rules, making them somewhat circular.
Expression: [
o "Value"
o "Call"
o "Curry"
o "Code"
o "Operation"
o "Assign"
@@ -72,255 +86,273 @@ grammar: {
o "For"
o "Switch"
o "Extends"
o "Class"
o "Splat"
o "Existence"
o "Comment"
o "Extension"
]
# A block of expressions. Note that the Rewriter will convert some postfix
# forms into blocks for us, by altering the token stream.
# A an indented block of expressions. Note that the [Rewriter](rewriter.html)
# will convert some postfix forms into blocks for us, by adjusting the
# token stream.
Block: [
o "INDENT Expressions OUTDENT", -> $2
o "INDENT OUTDENT", -> new Expressions()
o "TERMINATOR Comment", -> Expressions.wrap [$2]
]
# A literal identifier, a variable name or property.
Identifier: [
o "IDENTIFIER", -> new LiteralNode(yytext)
o "IDENTIFIER", -> new LiteralNode yytext
]
# Alphanumerics are separated from the other **Literal** matchers because
# they can also serve as keys in object literals.
AlphaNumeric: [
o "NUMBER", -> new LiteralNode(yytext)
o "STRING", -> new LiteralNode(yytext)
o "NUMBER", -> new LiteralNode yytext
o "STRING", -> new LiteralNode yytext
]
# All hard-coded values. These can be printed straight to JavaScript.
# All of our immediate values. These can (in general), be passed straight
# through and printed to JavaScript.
Literal: [
o "AlphaNumeric", -> $1
o "JS", -> new LiteralNode(yytext)
o "REGEX", -> new LiteralNode(yytext)
o "BREAK", -> new LiteralNode(yytext)
o "CONTINUE", -> new LiteralNode(yytext)
o "TRUE", -> new LiteralNode(true)
o "FALSE", -> new LiteralNode(false)
o "YES", -> new LiteralNode(true)
o "NO", -> new LiteralNode(false)
o "ON", -> new LiteralNode(true)
o "OFF", -> new LiteralNode(false)
o "AlphaNumeric"
o "JS", -> new LiteralNode yytext
o "REGEX", -> new LiteralNode yytext
o "BREAK", -> new LiteralNode yytext
o "CONTINUE", -> new LiteralNode yytext
o "TRUE", -> new LiteralNode true
o "FALSE", -> new LiteralNode false
o "YES", -> new LiteralNode true
o "NO", -> new LiteralNode false
o "ON", -> new LiteralNode true
o "OFF", -> new LiteralNode false
]
# Assignment to a variable (or index).
# Assignment of a variable, property, or index to a value.
Assign: [
o "Value ASSIGN Expression", -> new AssignNode($1, $3)
o "Assignable ASSIGN Expression", -> new AssignNode $1, $3
]
# Assignment within an object literal (can be quoted).
# Assignment when it happens within an object literal. The difference from
# the ordinary **Assign** is that these allow numbers and strings as keys.
AssignObj: [
o "Identifier ASSIGN Expression", -> new AssignNode(new ValueNode($1), $3, 'object')
o "AlphaNumeric ASSIGN Expression", -> new AssignNode(new ValueNode($1), $3, 'object')
o "Identifier ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
o "AlphaNumeric ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
o "Comment"
]
# A return statement.
# A return statement from a function body.
Return: [
o "RETURN Expression", -> new ReturnNode($2)
o "RETURN", -> new ReturnNode(new ValueNode(new LiteralNode('null')))
o "RETURN Expression", -> new ReturnNode $2
o "RETURN", -> new ReturnNode new ValueNode new LiteralNode 'null'
]
# A comment.
# A comment. Because CoffeeScript passes comments through to JavaScript, we
# have to parse comments like any other construct, and identify all of the
# positions in which they can occur in the grammar.
Comment: [
o "COMMENT", -> new CommentNode(yytext)
o "COMMENT", -> new CommentNode yytext
]
# Arithmetic and logical operators
# For Ruby's Operator precedence, see: [
# https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
Operation: [
o "! Expression", -> new OpNode('!', $2)
o "!! Expression", -> new OpNode('!!', $2)
o("- Expression", (-> new OpNode('-', $2)), {prec: 'UMINUS'})
o("+ Expression", (-> new OpNode('+', $2)), {prec: 'UPLUS'})
o "NOT Expression", -> new OpNode('not', $2)
o "~ Expression", -> new OpNode('~', $2)
o "-- Expression", -> new OpNode('--', $2)
o "++ Expression", -> new OpNode('++', $2)
o "DELETE Expression", -> new OpNode('delete', $2)
o "TYPEOF Expression", -> new OpNode('typeof', $2)
o "Expression --", -> new OpNode('--', $1, null, true)
o "Expression ++", -> new OpNode('++', $1, null, true)
o "Expression * Expression", -> new OpNode('*', $1, $3)
o "Expression / Expression", -> new OpNode('/', $1, $3)
o "Expression % Expression", -> new OpNode('%', $1, $3)
o "Expression + Expression", -> new OpNode('+', $1, $3)
o "Expression - Expression", -> new OpNode('-', $1, $3)
o "Expression << Expression", -> new OpNode('<<', $1, $3)
o "Expression >> Expression", -> new OpNode('>>', $1, $3)
o "Expression >>> Expression", -> new OpNode('>>>', $1, $3)
o "Expression & Expression", -> new OpNode('&', $1, $3)
o "Expression | Expression", -> new OpNode('|', $1, $3)
o "Expression ^ Expression", -> new OpNode('^', $1, $3)
o "Expression <= Expression", -> new OpNode('<=', $1, $3)
o "Expression < Expression", -> new OpNode('<', $1, $3)
o "Expression > Expression", -> new OpNode('>', $1, $3)
o "Expression >= Expression", -> new OpNode('>=', $1, $3)
o "Expression == Expression", -> new OpNode('==', $1, $3)
o "Expression != Expression", -> new OpNode('!=', $1, $3)
o "Expression IS Expression", -> new OpNode('is', $1, $3)
o "Expression ISNT Expression", -> new OpNode('isnt', $1, $3)
o "Expression && Expression", -> new OpNode('&&', $1, $3)
o "Expression || Expression", -> new OpNode('||', $1, $3)
o "Expression AND Expression", -> new OpNode('and', $1, $3)
o "Expression OR Expression", -> new OpNode('or', $1, $3)
o "Expression ? Expression", -> new OpNode('?', $1, $3)
o "Expression -= Expression", -> new OpNode('-=', $1, $3)
o "Expression += Expression", -> new OpNode('+=', $1, $3)
o "Expression /= Expression", -> new OpNode('/=', $1, $3)
o "Expression *= Expression", -> new OpNode('*=', $1, $3)
o "Expression %= Expression", -> new OpNode('%=', $1, $3)
o "Expression ||= Expression", -> new OpNode('||=', $1, $3)
o "Expression &&= Expression", -> new OpNode('&&=', $1, $3)
o "Expression ?= Expression", -> new OpNode('?=', $1, $3)
o "Expression INSTANCEOF Expression", -> new OpNode('instanceof', $1, $3)
o "Expression IN Expression", -> new OpNode('in', $1, $3)
]
# The existence operator.
# [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
Existence: [
o "Expression ?", -> new ExistenceNode($1)
o "Expression ?", -> new ExistenceNode $1
]
# Function definition.
# The **Code** node is the function literal. It's defined by an indented block
# of **Expressions** preceded by a function arrow, with an optional parameter
# list.
Code: [
o "PARAM_START ParamList PARAM_END FuncGlyph Block", -> new CodeNode($2, $5, $4)
o "FuncGlyph Block", -> new CodeNode([], $2, $1)
o "PARAM_START ParamList PARAM_END FuncGlyph Block", -> new CodeNode $2, $5, $4
o "FuncGlyph Block", -> new CodeNode [], $2, $1
]
# The symbols to signify functions, and bound functions.
# CoffeeScript has two different symbols for functions. `->` is for ordinary
# functions, and `=>` is for functions bound to the current value of *this*.
FuncGlyph: [
o "->", -> 'func'
o "=>", -> 'boundfunc'
]
# The parameters to a function definition.
# The list of parameters that a function accepts can be of any length.
ParamList: [
o "", -> []
o "Param", -> [$1]
o "ParamList , Param", -> $1.concat [$3]
]
# A Parameter (or ParamSplat) in a function definition.
# A single parameter in a function definition can be ordinary, or a splat
# that hoovers up the remaining arguments.
Param: [
o "PARAM", -> new LiteralNode(yytext)
o "Param . . .", -> new SplatNode($1)
o "PARAM", -> new LiteralNode yytext
o "Param . . .", -> new SplatNode $1
]
# A regular splat.
# A splat that occurs outside of a parameter list.
Splat: [
o "Expression . . .", -> new SplatNode($1)
o "Expression . . .", -> new SplatNode $1
]
# Expressions that can be treated as values.
# Variables and properties that can be assigned to.
SimpleAssignable: [
o "Identifier", -> new ValueNode $1
o "Value Accessor", -> $1.push $2
o "Invocation Accessor", -> new ValueNode $1, [$2]
o "ThisProperty"
]
# Everything that can be assigned to.
Assignable: [
o "SimpleAssignable"
o "Array", -> new ValueNode $1
o "Object", -> new ValueNode $1
]
# The types of things that can be treated as values -- assigned to, invoked
# as functions, indexed into, named as a class, etc.
Value: [
o "Identifier", -> new ValueNode($1)
o "Literal", -> new ValueNode($1)
o "Array", -> new ValueNode($1)
o "Object", -> new ValueNode($1)
o "Parenthetical", -> new ValueNode($1)
o "Range", -> new ValueNode($1)
o "This", -> $1
o "Value Accessor", -> $1.push($2)
o "Invocation Accessor", -> new ValueNode($1, [$2])
o "Assignable"
o "Literal", -> new ValueNode $1
o "Parenthetical", -> new ValueNode $1
o "Range", -> new ValueNode $1
o "This"
o "NULL", -> new ValueNode new LiteralNode 'null'
]
# Accessing into an object or array, through dot or index notation.
# The general group of accessors into an object, by property, by prototype
# or by array index or slice.
Accessor: [
o "PROPERTY_ACCESS Identifier", -> new AccessorNode($2)
o "PROTOTYPE_ACCESS Identifier", -> new AccessorNode($2, 'prototype')
o "SOAK_ACCESS Identifier", -> new AccessorNode($2, 'soak')
o "PROPERTY_ACCESS Identifier", -> new AccessorNode $2
o "PROTOTYPE_ACCESS Identifier", -> new AccessorNode $2, 'prototype'
o "::", -> new AccessorNode(new LiteralNode('prototype'))
o "SOAK_ACCESS Identifier", -> new AccessorNode $2, 'soak'
o "Index"
o "Slice", -> new SliceNode($1)
o "Slice", -> new SliceNode $1
]
# Indexing into an object or array.
# Indexing into an object or array using bracket notation.
Index: [
o "INDEX_START Expression INDEX_END", -> new IndexNode($2)
o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode($2, 'soak')
o "INDEX_START Expression INDEX_END", -> new IndexNode $2
o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode $2, 'soak'
]
# An object literal.
# In CoffeeScript, an object literal is simply a list of assignments.
Object: [
o "{ AssignList }", -> new ObjectNode($2)
o "{ AssignList }", -> new ObjectNode $2
o "{ IndentedAssignList }", -> new ObjectNode $2
o "{ AssignList , }", -> new ObjectNode $2
o "{ IndentedAssignList , }", -> new ObjectNode $2
]
# Assignment within an object literal (comma or newline separated).
# Assignment of properties within an object literal can be separated by
# comma, as in JavaScript, or simply by newline.
AssignList: [
o "", -> []
o "AssignObj", -> [$1]
o "AssignList , AssignObj", -> $1.concat [$3]
o "AssignList TERMINATOR AssignObj", -> $1.concat [$3]
o "AssignList , TERMINATOR AssignObj", -> $1.concat [$4]
]
# An **AssignList** within a block indentation.
IndentedAssignList: [
o "INDENT AssignList OUTDENT", -> $2
o "INDENT AssignList , OUTDENT", -> $2
]
# All flavors of function call (instantiation, super, and regular).
# Class definitions have optional bodies of prototype property assignments,
# and optional references to the superclass.
Class: [
o "CLASS SimpleAssignable", -> new ClassNode $2
o "CLASS SimpleAssignable EXTENDS Value", -> new ClassNode $2, $4
o "CLASS SimpleAssignable INDENT ClassBody OUTDENT", -> new ClassNode $2, null, $4
o "CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT", -> new ClassNode $2, $4, $6
]
# Assignments that can happen directly inside a class declaration.
ClassAssign: [
o "AssignObj", -> $1
o "ThisProperty ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'this'
]
# A list of assignments to a class.
ClassBody: [
o "", -> []
o "ClassAssign", -> [$1]
o "ClassBody TERMINATOR ClassAssign", -> $1.concat $3
]
# The three flavors of function call: normal, object instantiation with `new`,
# and calling `super()`
Call: [
o "Invocation", -> $1
o "Invocation"
o "NEW Invocation", -> $2.new_instance()
o "Super", -> $1
o "Super"
]
# Extending an object's prototype.
# Binds a function call to a context and/or arguments.
Curry: [
o "Value <- Arguments", -> new CurryNode $1, $3
]
# Extending an object by setting its prototype chain to reference a parent
# object.
Extends: [
o "Value EXTENDS Value", -> new ExtendsNode($1, $3)
o "SimpleAssignable EXTENDS Value", -> new ExtendsNode $1, $3
]
# A generic function invocation.
# Ordinary function invocation, or a chained series of calls.
Invocation: [
o "Value Arguments", -> new CallNode($1, $2)
o "Invocation Arguments", -> new CallNode($1, $2)
o "Value Arguments", -> new CallNode $1, $2
o "Invocation Arguments", -> new CallNode $1, $2
]
# The list of arguments to a function invocation.
# The list of arguments to a function call.
Arguments: [
o "CALL_START ArgList CALL_END", -> $2
o "CALL_START ArgList , CALL_END", -> $2
]
# Calling super.
Super: [
o "SUPER CALL_START ArgList CALL_END", -> new CallNode('super', $3)
o "SUPER CALL_START ArgList CALL_END", -> new CallNode 'super', $3
o "SUPER CALL_START ArgList , CALL_END", -> new CallNode 'super', $3
]
# This references, either naked or to a property.
# A reference to the *this* current object.
This: [
o "@", -> new ValueNode(new LiteralNode('this'))
o "@ Identifier", -> new ValueNode(new LiteralNode('this'), [new AccessorNode($2)])
o "THIS", -> new ValueNode new LiteralNode 'this'
o "@", -> new ValueNode new LiteralNode 'this'
]
# The range literal.
# A reference to a property on *this*.
ThisProperty: [
o "@ Identifier", -> new ValueNode new LiteralNode('this'), [new AccessorNode($2)]
]
# The CoffeeScript range literal.
Range: [
o "[ Expression . . Expression ]", -> new RangeNode($2, $5)
o "[ Expression . . . Expression ]", -> new RangeNode($2, $6, true)
o "[ Expression . . Expression ]", -> new RangeNode $2, $5
o "[ Expression . . . Expression ]", -> new RangeNode $2, $6, true
]
# The slice literal.
Slice: [
o "INDEX_START Expression . . Expression INDEX_END", -> new RangeNode($2, $5)
o "INDEX_START Expression . . . Expression INDEX_END", -> new RangeNode($2, $6, true)
o "INDEX_START Expression . . Expression INDEX_END", -> new RangeNode $2, $5
o "INDEX_START Expression . . . Expression INDEX_END", -> new RangeNode $2, $6, true
]
# The array literal.
Array: [
o "[ ArgList ]", -> new ArrayNode($2)
o "[ ArgList ]", -> new ArrayNode $2
o "[ ArgList , ]", -> new ArrayNode $2
]
# A list of arguments to a method call, or as the contents of an array.
# The **ArgList** is both the list of objects passed into a function call,
# as well as the contents of an array literal
# (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o "", -> []
o "Expression", -> [$1]
@@ -329,128 +361,255 @@ grammar: {
o "ArgList TERMINATOR Expression", -> $1.concat [$3]
o "ArgList , TERMINATOR Expression", -> $1.concat [$4]
o "ArgList , INDENT Expression", -> $1.concat [$4]
o "ArgList OUTDENT", -> $1
o "ArgList OUTDENT"
o "ArgList , OUTDENT"
]
# Just simple, comma-separated, required arguments (no fancy syntax).
# Just simple, comma-separated, required arguments (no fancy syntax). We need
# this to be separate from the **ArgList** for use in **Switch** blocks, where
# having the newlines wouldn't make sense.
SimpleArgs: [
o "Expression", -> $1
o "Expression"
o "SimpleArgs , Expression", ->
if $1 instanceof Array then $1.concat([$3]) else [$1].concat([$3])
]
# Try/catch/finally exception handling blocks.
# The variants of *try/catch/finally* exception handling blocks.
Try: [
o "TRY Block Catch", -> new TryNode($2, $3[0], $3[1])
o "TRY Block FINALLY Block", -> new TryNode($2, null, null, $4)
o "TRY Block Catch FINALLY Block", -> new TryNode($2, $3[0], $3[1], $5)
o "TRY Block Catch", -> new TryNode $2, $3[0], $3[1]
o "TRY Block FINALLY Block", -> new TryNode $2, null, null, $4
o "TRY Block Catch FINALLY Block", -> new TryNode $2, $3[0], $3[1], $5
]
# A catch clause.
# A catch clause names its error and runs a block of code.
Catch: [
o "CATCH Identifier Block", -> [$2, $3]
]
# Throw an exception.
# Throw an exception object.
Throw: [
o "THROW Expression", -> new ThrowNode($2)
o "THROW Expression", -> new ThrowNode $2
]
# Parenthetical expressions.
# Parenthetical expressions. Note that the **Parenthetical** is a **Value**,
# not an **Expression**, so if you need to use an expression in a place
# where only values are accepted, wrapping it in parentheses will always do
# the trick.
Parenthetical: [
o "( Expression )", -> new ParentheticalNode($2)
o "( Expression )", -> new ParentheticalNode $2
]
# The condition for a while loop.
# A language extension to CoffeeScript from the outside. We simply pass
# it through unaltered.
Extension: [
o "EXTENSION", -> yytext
]
# The condition portion of a while loop.
WhileSource: [
o "WHILE Expression", -> new WhileNode($2)
o "WHILE Expression WHEN Expression", -> new WhileNode($2, {filter : $4})
o "WHILE Expression", -> new WhileNode $2
o "WHILE Expression WHEN Expression", -> new WhileNode $2, {filter : $4}
]
# The while loop. (there is no do..while).
# The while loop can either be normal, with a block of expressions to execute,
# or postfix, with a single expression. There is no do..while.
While: [
o "WhileSource Block", -> $1.add_body $2
o "Expression WhileSource", -> $2.add_body $1
o "Expression WhileSource", -> $2.add_body Expressions.wrap [$1]
]
# Array comprehensions, including guard and current index.
# Looks a little confusing, check nodes.rb for the arguments to ForNode.
# Array, object, and range comprehensions, at the most generic level.
# Comprehensions can either be normal, with a block of expressions to execute,
# or postfix, with a single expression.
For: [
o "Expression FOR ForVariables ForSource", -> new ForNode($1, $4, $3[0], $3[1])
o "FOR ForVariables ForSource Block", -> new ForNode($4, $3, $2[0], $2[1])
o "Expression FOR ForVariables ForSource", -> new ForNode $1, $4, $3[0], $3[1]
o "FOR ForVariables ForSource Block", -> new ForNode $4, $3, $2[0], $2[1]
]
# An array comprehension has variables for the current element and index.
# An array or range comprehension has variables for the current element and
# (optional) reference to the current index. Or, *key, value*, in the case
# of object comprehensions.
ForVariables: [
o "Identifier", -> [$1]
o "Identifier , Identifier", -> [$1, $3]
]
# The source of the array comprehension can optionally be filtered.
# The source of a comprehension is an array or object with an optional filter
# clause. If it's an array comprehension, you can also choose to step through
# in fixed-size increments.
ForSource: [
o "IN Expression", -> {source: $2}
o "OF Expression", -> {source: $2, object: true}
o "ForSource WHEN Expression", -> $1.filter: $3; $1
o "ForSource BY Expression", -> $1.step: $3; $1
o "IN Expression", -> {source: $2}
o "OF Expression", -> {source: $2, object: true}
o "IN Expression WHEN Expression", -> {source: $2, filter: $4}
o "OF Expression WHEN Expression", -> {source: $2, filter: $4, object: true}
o "IN Expression BY Expression", -> {source: $2, step: $4}
o "IN Expression WHEN Expression BY Expression", -> {source: $2, filter: $4; step: $6}
o "IN Expression BY Expression WHEN Expression", -> {source: $2, step: $4, filter: $6}
]
# Switch/When blocks.
# The CoffeeScript switch/when/else block replaces the JavaScript
# switch/case/default by compiling into an if-else chain.
Switch: [
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition($2)
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else($6, true)
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition $2
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else $6, true
]
# The inner list of whens.
# The inner list of whens is left recursive. At code-generation time, the
# IfNode will rewrite them into a proper chain.
Whens: [
o "When", -> $1
o "When"
o "Whens When", -> $1.push $2
]
# An individual when.
# An individual **When** clause, with action.
When: [
o "LEADING_WHEN SimpleArgs Block", -> new IfNode($2, $3, null, {statement: true})
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode($2, $3, null, {statement: true})
o "Comment TERMINATOR When", -> $3.comment: $1; $3
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, null, {statement: true}
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, null, {statement: true}
o "Comment TERMINATOR When", -> $3.comment: $1; $3
]
# The most basic form of "if".
# The most basic form of *if* is a condition and an action. The following
# if-related rules are broken up along these lines in order to avoid
# ambiguity.
IfStart: [
o "IF Expression Block", -> new IfNode($2, $3)
o "IfStart ElsIfs", -> $1.add_else($2)
o "IF Expression Block", -> new IfNode $2, $3
o "IfStart ElsIf", -> $1.add_else $2
]
# An **IfStart** can optionally be followed by an else block.
IfBlock: [
o "IfStart", -> $1
o "IfStart ELSE Block", -> $1.add_else($3)
o "IfStart"
o "IfStart ELSE Block", -> $1.add_else $3
]
# Multiple elsifs can be chained together.
ElsIfs: [
# An *else if* continuation of the *if* expression.
ElsIf: [
o "ELSE IF Expression Block", -> (new IfNode($3, $4)).force_statement()
o "ElsIfs ElsIf", -> $1.add_else($2)
]
# The full complement of if blocks, including postfix one-liner ifs and unlesses.
# The full complement of *if* expressions, including postfix one-liner
# *if* and *unless*.
If: [
o "IfBlock", -> $1
o "Expression IF Expression", -> new IfNode($3, Expressions.wrap([$1]), null, {statement: true})
o "Expression UNLESS Expression", -> new IfNode($3, Expressions.wrap([$1]), null, {statement: true, invert: true})
o "IfBlock"
o "Expression IF Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true}
o "Expression UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true, invert: true}
]
# Arithmetic and logical operators, working on one or more operands.
# Here they are grouped by order of precedence. The actual precedence rules
# are defined at the bottom of the page. It would be shorter if we could
# combine most of these rules into a single generic *Operand OpSymbol Operand*
# -type rule, but in order to make the precedence binding possible, separate
# rules are necessary.
Operation: [
o "! Expression", -> new OpNode '!', $2
o "!! Expression", -> new OpNode '!!', $2
o("- Expression", (-> new OpNode('-', $2)), {prec: 'UMINUS'})
o("+ Expression", (-> new OpNode('+', $2)), {prec: 'UPLUS'})
o "~ Expression", -> new OpNode '~', $2
o "-- Expression", -> new OpNode '--', $2
o "++ Expression", -> new OpNode '++', $2
o "DELETE Expression", -> new OpNode 'delete', $2
o "TYPEOF Expression", -> new OpNode 'typeof', $2
o "Expression --", -> new OpNode '--', $1, null, true
o "Expression ++", -> new OpNode '++', $1, null, true
o "Expression * Expression", -> new OpNode '*', $1, $3
o "Expression / Expression", -> new OpNode '/', $1, $3
o "Expression % Expression", -> new OpNode '%', $1, $3
o "Expression + Expression", -> new OpNode '+', $1, $3
o "Expression - Expression", -> new OpNode '-', $1, $3
o "Expression << Expression", -> new OpNode '<<', $1, $3
o "Expression >> Expression", -> new OpNode '>>', $1, $3
o "Expression >>> Expression", -> new OpNode '>>>', $1, $3
o "Expression & Expression", -> new OpNode '&', $1, $3
o "Expression | Expression", -> new OpNode '|', $1, $3
o "Expression ^ Expression", -> new OpNode '^', $1, $3
o "Expression <= Expression", -> new OpNode '<=', $1, $3
o "Expression < Expression", -> new OpNode '<', $1, $3
o "Expression > Expression", -> new OpNode '>', $1, $3
o "Expression >= Expression", -> new OpNode '>=', $1, $3
o "Expression == Expression", -> new OpNode '==', $1, $3
o "Expression != Expression", -> new OpNode '!=', $1, $3
o "Expression && Expression", -> new OpNode '&&', $1, $3
o "Expression || Expression", -> new OpNode '||', $1, $3
o "Expression ? Expression", -> new OpNode '?', $1, $3
o "Expression -= Expression", -> new OpNode '-=', $1, $3
o "Expression += Expression", -> new OpNode '+=', $1, $3
o "Expression /= Expression", -> new OpNode '/=', $1, $3
o "Expression *= Expression", -> new OpNode '*=', $1, $3
o "Expression %= Expression", -> new OpNode '%=', $1, $3
o "Expression ||= Expression", -> new OpNode '||=', $1, $3
o "Expression &&= Expression", -> new OpNode '&&=', $1, $3
o "Expression ?= Expression", -> new OpNode '?=', $1, $3
o "Expression INSTANCEOF Expression", -> new OpNode 'instanceof', $1, $3
o "Expression IN Expression", -> new OpNode 'in', $1, $3
]
}
# Helpers ==============================================================
# Precedence
# ----------
# Make the Jison parser.
bnf: {}
# Operators at the top of this list have higher precedence than the ones lower
# down. Following these rules is what makes `2 + 3 * 4` parse as:
#
# 2 + (3 * 4)
#
# And not:
#
# (2 + 3) * 4
operators: [
["left", '?']
["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--']
["left", '*', '/', '%']
["left", '+', '-']
["left", '<<', '>>', '>>>']
["left", '&', '|', '^']
["left", '<=', '<', '>', '>=']
["right", 'DELETE', 'INSTANCEOF', 'TYPEOF']
["left", '==', '!=']
["left", '&&', '||']
["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=']
["left", '.']
["right", 'INDENT']
["left", 'OUTDENT']
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
["right", 'FOR', 'NEW', 'SUPER', 'CLASS']
["left", 'EXTENDS']
["right", 'ASSIGN', 'RETURN']
["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']
]
# Wrapping Up
# -----------
# Finally, now what we have our **grammar** and our **operators**, we can create
# our **Jison.Parser**. We do this by processing all of our rules, recording all
# terminals (every symbol which does not appear as the name of a rule above)
# as "tokens".
tokens: []
for name, non_terminal of grammar
bnf[name]: for option in non_terminal
for part in option[0].split(" ")
if !grammar[part]
tokens.push(part)
if name == "Root"
option[1] = "return " + option[1]
option
tokens: tokens.join(" ")
exports.parser: new Parser({tokens: tokens, bnf: bnf, operators: operators.reverse(), startSymbol: 'Root'}, {debug: false})
for name, alternatives of grammar
grammar[name]: for alt in alternatives
for token in alt[0].split ' '
tokens.push token unless grammar[token]
alt[1] = "return ${alt[1]}" if name is 'Root'
alt
# Initialize the **Parser** with our list of terminal **tokens**, our **grammar**
# rules, and the name of the root. Reverse the operators because Jison orders
# precedence from low to high, and we have it high to low
# (as in [Yacc](http://dinosaur.compilertools.net/yacc/index.html)).
exports.parser: new Parser {
tokens: tokens.join ' '
bnf: grammar
operators: operators.reverse()
startSymbol: 'Root'
}

87
src/helpers.coffee Normal file
View File

@@ -0,0 +1,87 @@
# This file contains the common helper functions that we'd like to share among
# the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
# arrays, count characters, that sort of thing.
# Set up exported variables for both **Node.js** and the browser.
this.exports: this unless process?
helpers: exports.helpers: {}
# Does a list include a value?
helpers.include: include: (list, value) ->
list.indexOf(value) >= 0
# Peek at the beginning of a given string to see if it matches a sequence.
helpers.starts: starts: (string, literal, start) ->
string.substring(start, (start or 0) + literal.length) is literal
# Trim out all falsy values from an array.
helpers.compact: compact: (array) -> item for item in array when item
# Count the number of occurences of a character in a string.
helpers.count: count: (string, letter) ->
num: 0
pos: string.indexOf(letter)
while pos isnt -1
num: + 1
pos: string.indexOf(letter, pos + 1)
num
# Merge objects, returning a fresh copy with attributes from both sides.
# Used every time `BaseNode#compile` is called, to allow properties in the
# options hash to propagate down the tree without polluting other branches.
helpers.merge: merge: (options, overrides) ->
fresh: {}
(fresh[key]: val) for key, val of options
(fresh[key]: val) for key, val of overrides if overrides
fresh
# Extend a source object with the properties of another object (shallow copy).
# We use this to simulate Node's deprecated `process.mixin`
helpers.extend: extend: (object, properties) ->
(object[key]: val) for key, val of properties
# Return a completely flattened version of an array. Handy for getting a
# list of `children` from the nodes.
helpers.flatten: flatten: (array) ->
memo: []
for item in array
if item instanceof Array then memo: memo.concat(item) else memo.push(item)
memo
# Delete a key from an object, returning the value. Useful when a node is
# looking for a particular method in an options hash.
helpers.del: del: (obj, key) ->
val: obj[key]
delete obj[key]
val
# Matches a balanced group such as a single or double-quoted string. Pass in
# a series of delimiters, all of which must be nested correctly within the
# contents of the string. This method allows us to have strings within
# interpolations within strings, ad infinitum.
helpers.balanced_string: balanced_string: (str, delimited, options) ->
options: or {}
slash: delimited[0][0] is '/'
levels: []
i: 0
while i < str.length
if levels.length and starts str, '\\', i
i: + 1
else
for pair in delimited
[open, close]: pair
if levels.length and starts(str, close, i) and levels[levels.length - 1] is pair
levels.pop()
i: + close.length - 1
i: + 1 unless levels.length
break
else if starts str, open, i
levels.push(pair)
i: + open.length - 1
break
break if not levels.length or slash and starts str, '\n', i
i: + 1
if levels.length
return false if slash
throw new Error "SyntaxError: Unterminated ${levels.pop()[0]} starting on line ${@line + 1}"
if not i then false else str.substring(0, i)

View File

@@ -1,17 +1,438 @@
# The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
# matches against the beginning of the source code. When a match is found,
# a token is produced, we consume the match, and start again. Tokens are in the
# form:
#
# [tag, value, line_number]
#
# Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison).
# Set up the Lexer for both Node.js and the browser, depending on where we are.
if process?
Rewriter: require('./rewriter').Rewriter
helpers: require('./helpers').helpers
else
this.exports: this
Rewriter: this.Rewriter
Rewriter: this.Rewriter
helpers: this.helpers
# The lexer reads a stream of CoffeeScript and divvys it up into tagged
# tokens. A minor bit of the ambiguity in the grammar has been avoided by
# Import the helpers we need.
include: helpers.include
count: helpers.count
starts: helpers.starts
compact: helpers.compact
balanced_string: helpers.balanced_string
# The Lexer Class
# ---------------
# The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
# tokens. Some potential ambiguity in the grammar has been avoided by
# pushing some extra smarts into the Lexer.
exports.Lexer: lex: ->
exports.Lexer: class Lexer
# Constants ============================================================
# **tokenize** is the Lexer's main method. Scan by attempting to match tokens
# one at a time, using a regular expression anchored at the start of the
# remaining code, or a custom recursive token-matching method
# (for interpolations). When the next token has been recorded, we move forward
# within the code past the token, and begin again.
#
# Each tokenizing method is responsible for incrementing `@i` by the number of
# characters it has consumed. `@i` can be thought of as our finger on the page
# of source.
#
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
# unless explicitly asked not to.
tokenize: (code, options) ->
code : code.replace /(\r|\s+$)/g, ''
o : options or {}
@code : code # The remainder of the source code.
@i : 0 # Current character position we're parsing.
@line : o.line or 0 # The current line.
@indent : 0 # The current indentation level.
@indents : [] # The stack of all current indentation levels.
@tokens : [] # Stream of parsed tokens in the form ['TYPE', value, line]
while @i < @code.length
@chunk: @code.slice @i
@extract_next_token()
@close_indentation()
return @tokens if o.rewrite is off
(new Rewriter()).rewrite @tokens
# Keywords that CoffeScript shares in common with JS.
# At every position, run through this list of attempted matches,
# short-circuiting if any of them succeed. Their order determines precedence:
# `@literal_token` is the fallback catch-all.
extract_next_token: ->
return if @extension_token()
return if @identifier_token()
return if @number_token()
return if @heredoc_token()
return if @regex_token()
return if @comment_token()
return if @line_token()
return if @whitespace_token()
return if @js_token()
return if @string_token()
return @literal_token()
# Tokenizers
# ----------
# Language extensions get the highest priority, first chance to tag tokens
# as something else.
extension_token: ->
for extension in Lexer.extensions
return true if extension.call this
false
# Matches identifying literals: variables, keywords, method names, etc.
# Check to ensure that JavaScript reserved words aren't being used as
# identifiers. Because CoffeeScript reserves a handful of keywords that are
# allowed in JavaScript, we're careful not to tag them as keywords when
# referenced as property names here, so you can still do `jQuery.is()` even
# though `is` means `===` otherwise.
identifier_token: ->
return false unless id: @match IDENTIFIER, 1
@name_access_type()
accessed: include ACCESSORS, @tag 0
tag: 'IDENTIFIER'
tag: id.toUpperCase() if not accessed and include(KEYWORDS, id)
@identifier_error id if include RESERVED, id
tag: 'LEADING_WHEN' if tag is 'WHEN' and include LINE_BREAK, @tag()
@i: + id.length
if not accessed
tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id
return @tag_half_assignment tag if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
@token tag, id
true
# Matches numbers, including decimals, hex, and exponential notation.
number_token: ->
return false unless number: @match NUMBER, 1
@token 'NUMBER', number
@i: + number.length
true
# Matches strings, including multi-line strings. Ensures that quotation marks
# are balanced within the string's contents, and within nested interpolations.
string_token: ->
return false unless starts(@chunk, '"') or starts(@chunk, "'")
return false unless string:
@balanced_token(['"', '"'], ['${', '}']) or
@balanced_token ["'", "'"]
@interpolate_string string.replace STRING_NEWLINES, " \\\n"
@line: + count string, "\n"
@i: + string.length
true
# Matches heredocs, adjusting indentation to the correct level, as heredocs
# preserve whitespace, but ignore indentation to the left.
heredoc_token: ->
return false unless match: @chunk.match(HEREDOC)
quote: match[1].substr 0, 1
doc: @sanitize_heredoc match[2] or match[4], quote
@interpolate_string "$quote$doc$quote"
@line: + count match[1], "\n"
@i: + match[1].length
true
# Matches JavaScript interpolated directly into the source via backticks.
js_token: ->
return false unless starts @chunk, '`'
return false unless script: @balanced_token ['`', '`']
@token 'JS', script.replace JS_CLEANER, ''
@i: + script.length
true
# Matches regular expression literals. Lexing regular expressions is difficult
# to distinguish from division, so we borrow some basic heuristics from
# JavaScript and Ruby, borrow slash balancing from `@balanced_token`, and
# borrow interpolation from `@interpolate_string`.
regex_token: ->
return false unless @chunk.match REGEX_START
return false if include NOT_REGEX, @tag()
return false unless regex: @balanced_token ['/', '/']
regex: + (flags: @chunk.substr(regex.length).match REGEX_FLAGS)
if regex.match REGEX_INTERPOLATION
str: regex.substring(1).split('/')[0]
str: str.replace REGEX_ESCAPE, (escaped) -> '\\' + escaped
@tokens: @tokens.concat [['(', '('], ['NEW', 'new'], ['IDENTIFIER', 'RegExp'], ['CALL_START', '(']]
@interpolate_string "\"$str\"", yes
@tokens: @tokens.concat [[',', ','], ['STRING', "\"$flags\""], [')', ')'], [')', ')']]
else
@token 'REGEX', regex
@i: + regex.length
true
# Matches a token in which which the passed delimiter pairs must be correctly
# balanced (ie. strings, JS literals).
balanced_token: (delimited...) ->
balanced_string @chunk, delimited
# Matches and conumes comments. We pass through comments into JavaScript,
# so they're treated as real tokens, like any other part of the language.
comment_token: ->
return false unless comment: @match COMMENT, 1
@line: + (comment.match(MULTILINER) or []).length
lines: compact comment.replace(COMMENT_CLEANER, '').split MULTILINER
i: @tokens.length - 1
if @unfinished()
i: - 1 while @tokens[i] and not include LINE_BREAK, @tokens[i][0]
@tokens.splice(i + 1, 0, ['COMMENT', lines, @line], ['TERMINATOR', '\n', @line])
@i: + comment.length
true
# Matches newlines, indents, and outdents, and determines which is which.
# If we can detect that the current line is continued onto the the next line,
# then the newline is suppressed:
#
# elements
# .each( ... )
# .map( ... )
#
# Keeps track of the level of indentation, because a single outdent token
# can close multiple indents, so we need to know how far in we happen to be.
line_token: ->
return false unless indent: @match MULTI_DENT, 1
@line: + indent.match(MULTILINER).length
@i : + indent.length
prev: @prev(2)
size: indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length
next_character: @chunk.match(MULTI_DENT)[4]
no_newlines: next_character is '.' or @unfinished()
if size is @indent
return @suppress_newlines() if no_newlines
return @newline_token indent
else if size > @indent
return @suppress_newlines() if no_newlines
diff: size - @indent
@token 'INDENT', diff
@indents.push diff
else
@outdent_token @indent - size, no_newlines
@indent: size
true
# Record an outdent token or multiple tokens, if we happen to be moving back
# inwards past several recorded indents.
outdent_token: (move_out, no_newlines) ->
while move_out > 0 and @indents.length
last_indent: @indents.pop()
@token 'OUTDENT', last_indent
move_out: - last_indent
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR' or no_newlines
true
# Matches and consumes non-meaningful whitespace. Tag the previous token
# as being "spaced", because there are some cases where it makes a difference.
whitespace_token: ->
return false unless space: @match WHITESPACE, 1
prev: @prev()
prev.spaced: true if prev
@i: + space.length
true
# Generate a newline token. Consecutive newlines get merged together.
newline_token: (newlines) ->
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR'
true
# Use a `\` at a line-ending to suppress the newline.
# The slash is removed here once its job is done.
suppress_newlines: ->
@tokens.pop() if @value() is "\\"
true
# We treat all other single characters as a token. Eg.: `( ) , . !`
# Multi-character operators are also literal tokens, so that Jison can assign
# the proper order of operations. There are some symbols that we tag specially
# here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
# parentheses that indicate a method call from regular parentheses, and so on.
literal_token: ->
match: @chunk.match OPERATOR
value: match and match[1]
space: match and match[2]
@tag_parameters() if value and value.match CODE
value: or @chunk.substr 0, 1
prev_spaced: @prev() and @prev().spaced
tag: value
if value.match ASSIGNMENT
tag: 'ASSIGN'
@assignment_error() if include JS_FORBIDDEN, @value
else if value is ';'
tag: 'TERMINATOR'
else if value is '[' and @tag() is '?' and not prev_spaced
tag: 'SOAKED_INDEX_START'
@soaked_index: true
@tokens.pop()
else if value is ']' and @soaked_index
tag: 'SOAKED_INDEX_END'
@soaked_index: false
else if include(CALLABLE, @tag()) and not prev_spaced
tag: 'CALL_START' if value is '('
tag: 'INDEX_START' if value is '['
@i: + value.length
return @tag_half_assignment tag if space and prev_spaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
@token tag, value
true
# Token Manipulators
# ------------------
# As we consume a new `IDENTIFIER`, look at the previous token to determine
# if it's a special kind of accessor.
name_access_type: ->
@tag(1, 'PROTOTYPE_ACCESS') if @value() is '::'
if @value() is '.' and not (@value(2) is '.')
if @tag(2) is '?'
@tag(1, 'SOAK_ACCESS')
@tokens.splice(-2, 1)
else
@tag 1, 'PROPERTY_ACCESS'
# Sanitize a heredoc by escaping internal double quotes and erasing all
# external indentation on the left-hand side.
sanitize_heredoc: (doc, quote) ->
indent: (doc.match(HEREDOC_INDENT) or ['']).sort()[0]
doc.replace(new RegExp("^" +indent, 'gm'), '')
.replace(MULTILINER, "\\n")
.replace(new RegExp(quote, 'g'), '\\"')
# Tag a half assignment.
tag_half_assignment: (tag) ->
last: @tokens.pop()
@tokens.push ["$tag=", "$tag=", last[2]]
true
# A source of ambiguity in our grammar used to be parameter lists in function
# definitions versus argument lists in function calls. Walk backwards, tagging
# parameters specially in order to make things easier for the parser.
tag_parameters: ->
return if @tag() isnt ')'
i: 0
while true
i: + 1
tok: @prev i
return if not tok
switch tok[0]
when 'IDENTIFIER' then tok[0]: 'PARAM'
when ')' then tok[0]: 'PARAM_END'
when '(' then return tok[0]: 'PARAM_START'
true
# Close up all remaining open blocks at the end of the file.
close_indentation: ->
@outdent_token @indent
# The error for when you try to use a forbidden word in JavaScript as
# an identifier.
identifier_error: (word) ->
throw new Error "SyntaxError: Reserved word \"$word\" on line ${@line + 1}"
# The error for when you try to assign to a reserved word in JavaScript,
# like "function" or "default".
assignment_error: ->
throw new Error "SyntaxError: Reserved word \"${@value()}\" on line ${@line + 1} can't be assigned"
# Expand variables and expressions inside double-quoted strings using
# [ECMA Harmony's interpolation syntax](http://wiki.ecmascript.org/doku.php?id=strawman:string_interpolation)
# for substitution of bare variables as well as arbitrary expressions.
#
# "Hello $name."
# "Hello ${name.capitalize()}."
#
# If it encounters an interpolation, this method will recursively create a
# new Lexer, tokenize the interpolated contents, and merge them into the
# token stream.
interpolate_string: (str, escape_quotes) ->
if str.length < 3 or not starts str, '"'
@token 'STRING', str
else
lexer: new Lexer()
tokens: []
quote: str.substring 0, 1
[i, pi]: [1, 1]
while i < str.length - 1
if starts str, '\\', i
i: + 1
else if match: str.substring(i).match INTERPOLATION
[group, interp]: match
interp: "this.${ interp.substring(1) }" if starts interp, '@'
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i
tokens.push ['IDENTIFIER', interp]
i: + group.length - 1
pi: i + 1
else if (expr: balanced_string str.substring(i), [['${', '}']])
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i
inner: expr.substring(2, expr.length - 1)
if inner.length
nested: lexer.tokenize "($inner)", {rewrite: no, line: @line}
nested.pop()
tokens.push ['TOKENS', nested]
else
tokens.push ['STRING', "$quote$quote"]
i: + expr.length - 1
pi: i + 1
i: + 1
tokens.push ['STRING', "$quote${ str.substring(pi, i) }$quote"] if pi < i and pi < str.length - 1
tokens.unshift ['STRING', '""'] unless tokens[0][0] is 'STRING'
for token, i in tokens
[tag, value]: token
if tag is 'TOKENS'
@tokens: @tokens.concat value
else if tag is 'STRING' and escape_quotes
escaped: value.substring(1, value.length - 1).replace(/"/g, '\\"')
@token tag, "\"$escaped\""
else
@token tag, value
@token '+', '+' if i < tokens.length - 1
tokens
# Helpers
# -------
# Add a token to the results, taking note of the line number.
token: (tag, value) ->
@tokens.push [tag, value, @line]
# Peek at a tag in the current token stream.
tag: (index, tag) ->
return unless tok: @prev index
return tok[0]: tag if tag?
tok[0]
# Peek at a value in the current token stream.
value: (index, val) ->
return unless tok: @prev index
return tok[1]: val if val?
tok[1]
# Peek at a previous token, entire.
prev: (index) ->
@tokens[@tokens.length - (index or 1)]
# Attempt to match a string against the current chunk, returning the indexed
# match if successful, and `false` otherwise.
match: (regex, index) ->
return false unless m: @chunk.match regex
if m then m[index] else false
# Are we in the midst of an unfinished expression?
unfinished: ->
prev: @prev(2)
@value() and @value().match and @value().match(NO_NEWLINE) and
prev and (prev[0] isnt '.') and not @value().match(CODE)
# Lexer Properties
# ----------------
# There are no exensions to the core lexer by default.
@extensions: []
# Constants
# ---------
# Keywords that CoffeeScript shares in common with JavaScript.
JS_KEYWORDS: [
"if", "else",
"true", "false",
@@ -20,45 +441,54 @@ JS_KEYWORDS: [
"break", "continue",
"for", "in", "while",
"delete", "instanceof", "typeof",
"switch", "super", "extends"
"switch", "super", "extends", "class",
"this", "null"
]
# CoffeeScript-only keywords -- which we're more relaxed about allowing.
COFFEE_KEYWORDS: [
# CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
# be used standalone, but you can reference them as an attached property.
COFFEE_ALIASES: ["and", "or", "is", "isnt", "not"]
COFFEE_KEYWORDS: COFFEE_ALIASES.concat [
"then", "unless",
"yes", "no", "on", "off",
"and", "or", "is", "isnt", "not",
"of", "by", "where", "when"
]
# The list of keywords passed verbatim to the parser.
# The combined list of keywords is the superset that gets passed verbatim to
# the parser.
KEYWORDS: JS_KEYWORDS.concat COFFEE_KEYWORDS
# The list of keywords that are reserved by JavaScript, but not used, and aren't
# used by CoffeeScript. Using these will throw an error at compile time.
# The list of keywords that are reserved by JavaScript, but not used, or are
# used by CoffeeScript internally. We throw an error when these are encountered,
# to avoid having a JavaScript error at runtime.
RESERVED: [
"case", "default", "do", "function", "var", "void", "with", "class"
"case", "default", "do", "function", "var", "void", "with"
"const", "let", "debugger", "enum", "export", "import", "native"
]
# JavaScript keywords and reserved words together, excluding CoffeeScript ones.
# The superset of both JavaScript keywords and reserved words, none of which may
# be used as identifiers or properties.
JS_FORBIDDEN: JS_KEYWORDS.concat RESERVED
# Token matching regexes. (keep the IDENTIFIER regex in sync with AssignNode.)
IDENTIFIER : /^([a-zA-Z$_](\w|\$)*)/
NUMBER : /^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
STRING : /^(""|''|"([\s\S]*?)([^\\]|\\\\)"|'([\s\S]*?)([^\\]|\\\\)')/
HEREDOC : /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/
JS : /^(``|`([\s\S]*?)([^\\]|\\\\)`)/
OPERATOR : /^([+\*&|\/\-%=<>:!?]+)/
WHITESPACE : /^([ \t]+)/
COMMENT : /^(((\n?[ \t]*)?#[^\n]*)+)/
CODE : /^((-|=)>)/
REGEX : /^(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/
MULTI_DENT : /^((\n([ \t]*))+)(\.)?/
LAST_DENTS : /\n([ \t]*)/g
LAST_DENT : /\n([ \t]*)/
ASSIGNMENT : /^(:|=)$/
# Token matching regexes.
IDENTIFIER : /^([a-zA-Z\$_](\w|\$)*)/
NUMBER : /^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
HEREDOC : /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/
INTERPOLATION : /^\$([a-zA-Z_@]\w*(\.\w+)*)/
OPERATOR : /^([+\*&|\/\-%=<>:!?]+)([ \t]*)/
WHITESPACE : /^([ \t]+)/
COMMENT : /^(((\n?[ \t]*)?#[^\n]*)+)/
CODE : /^((-|=)>)/
MULTI_DENT : /^((\n([ \t]*))+)(\.)?/
LAST_DENTS : /\n([ \t]*)/g
LAST_DENT : /\n([ \t]*)/
ASSIGNMENT : /^(:|=)$/
# Regex-matching-regexes.
REGEX_START : /^\/[^\/ ]/
REGEX_INTERPOLATION: /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/
REGEX_FLAGS : /^[imgy]{0,4}/
REGEX_ESCAPE : /\\[^\$]/g
# Token cleaning regexes.
JS_CLEANER : /(^`|`$)/g
@@ -70,258 +500,36 @@ HEREDOC_INDENT : /^[ \t]+/mg
# Tokens which a regular expression will never immediately follow, but which
# a division operator might.
#
# See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
#
# Our list is shorter, due to sans-parentheses method calls.
NOT_REGEX: [
'IDENTIFIER', 'NUMBER', 'REGEX', 'STRING',
')', '++', '--', ']', '}',
'FALSE', 'NULL', 'TRUE'
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE'
]
# Tokens which could legitimately be invoked or indexed.
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@']
# Tokens which could legitimately be invoked or indexed. A opening
# parentheses or bracket following these tokens will be recorded as the start
# of a function invocation or indexing operation.
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS']
# Tokens that indicate an access -- keywords immediately following will be
# treated as identifiers.
ACCESSORS: ['PROPERTY_ACCESS', 'PROTOTYPE_ACCESS', 'SOAK_ACCESS', '@']
# Tokens that, when immediately preceding a 'WHEN', indicate that its leading.
BEFORE_WHEN: ['INDENT', 'OUTDENT', 'TERMINATOR']
# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
# occurs at the start of a line. We disambiguate these from trailing whens to
# avoid an ambiguity in the grammar.
LINE_BREAK: ['INDENT', 'OUTDENT', 'TERMINATOR']
# Scan by attempting to match tokens one character at a time. Slow and steady.
lex::tokenize: (code) ->
@code : code # Cleanup code by remove extra line breaks, TODO: chomp
@i : 0 # Current character position we're parsing
@line : 1 # The current line.
@indent : 0 # The current indent level.
@indents : [] # The stack of all indent levels we are currently within.
@tokens : [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value]
while @i < @code.length
@chunk: @code.slice(@i)
@extract_next_token()
@close_indentation()
(new Rewriter()).rewrite @tokens
# Half-assignments...
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?']
# At every position, run through this list of attempted matches,
# short-circuiting if any of them succeed.
lex::extract_next_token: ->
return if @identifier_token()
return if @number_token()
return if @heredoc_token()
return if @string_token()
return if @js_token()
return if @regex_token()
return if @indent_token()
return if @comment_token()
return if @whitespace_token()
return @literal_token()
# Tokenizers ==========================================================
# Matches identifying literals: variables, keywords, method names, etc.
lex::identifier_token: ->
return false unless id: @match IDENTIFIER, 1
@tag(1, 'PROTOTYPE_ACCESS') if @value() is '::'
if @value() is '.' and not (@value(2) is '.')
if @tag(2) is '?'
@tag(1, 'SOAK_ACCESS')
@tokens.splice(-2, 1)
else
@tag(1, 'PROPERTY_ACCESS')
tag: 'IDENTIFIER'
tag: id.toUpperCase() if KEYWORDS.indexOf(id) >= 0 and
not ((ACCESSORS.indexOf(@tag()) >= 0) and not @prev().spaced)
throw new Error('SyntaxError: Reserved word "' + id + '" on line ' + @line) if RESERVED.indexOf(id) >= 0
tag: 'LEADING_WHEN' if tag is 'WHEN' and BEFORE_WHEN.indexOf(@tag()) >= 0
@token(tag, id)
@i += id.length
true
# Matches numbers, including decimals, hex, and exponential notation.
lex::number_token: ->
return false unless number: @match NUMBER, 1
@token 'NUMBER', number
@i += number.length
true
# Matches strings, including multi-line strings.
lex::string_token: ->
return false unless string: @match STRING, 1
escaped: string.replace STRING_NEWLINES, " \\\n"
@token 'STRING', escaped
@line += @count string, "\n"
@i += string.length
true
# Matches heredocs, adjusting indentation to the correct level.
lex::heredoc_token: ->
return false unless match = @chunk.match(HEREDOC)
doc: match[2] or match[4]
indent: (doc.match(HEREDOC_INDENT) or ['']).sort()[0]
doc: doc.replace(new RegExp("^" + indent, 'gm'), '')
.replace(MULTILINER, "\\n")
.replace('"', '\\"')
@token 'STRING', '"' + doc + '"'
@line += @count match[1], "\n"
@i += match[1].length
true
# Matches interpolated JavaScript.
lex::js_token: ->
return false unless script: @match JS, 1
@token 'JS', script.replace(JS_CLEANER, '')
@i += script.length
true
# Matches regular expression literals.
lex::regex_token: ->
return false unless regex: @match REGEX, 1
return false if NOT_REGEX.indexOf(@tag()) >= 0
@token 'REGEX', regex
@i += regex.length
true
# Matches and conumes comments.
lex::comment_token: ->
return false unless comment: @match COMMENT, 1
@line += (comment.match(MULTILINER) or []).length
@token 'COMMENT', comment.replace(COMMENT_CLEANER, '').split(MULTILINER)
@token 'TERMINATOR', "\n"
@i += comment.length
true
# Record tokens for indentation differing from the previous line.
lex::indent_token: ->
return false unless indent: @match MULTI_DENT, 1
@line += indent.match(MULTILINER).length
@i += indent.length
next_character: @chunk.match(MULTI_DENT)[4]
prev: @prev(2)
no_newlines: next_character is '.' or (@value() and @value().match(NO_NEWLINE) and prev and (prev[0] isnt '.') and not @value().match(CODE))
return @suppress_newlines(indent) if no_newlines
size: indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length
return @newline_token(indent) if size is @indent
if size > @indent
diff: size - @indent
@token 'INDENT', diff
@indents.push diff
else
@outdent_token @indent - size
@indent: size
true
# Record an oudent token or tokens, if we're moving back inwards past
# multiple recorded indents.
lex::outdent_token: (move_out) ->
while move_out > 0 and @indents.length
last_indent: @indents.pop()
@token 'OUTDENT', last_indent
move_out -= last_indent
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR'
true
# Matches and consumes non-meaningful whitespace.
lex::whitespace_token: ->
return false unless space: @match WHITESPACE, 1
prev: @prev()
prev.spaced: true if prev
@i += space.length
true
# Multiple newlines get merged together.
# Use a trailing \ to escape newlines.
lex::newline_token: (newlines) ->
@token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR'
true
# Tokens to explicitly escape newlines are removed once their job is done.
lex::suppress_newlines: (newlines) ->
@tokens.pop() if @value() is "\\"
true
# We treat all other single characters as a token. Eg.: ( ) , . !
# Multi-character operators are also literal tokens, so that Racc can assign
# the proper order of operations.
lex::literal_token: ->
match: @chunk.match(OPERATOR)
value: match and match[1]
@tag_parameters() if value and value.match(CODE)
value ||= @chunk.substr(0, 1)
not_spaced: not @prev() or not @prev().spaced
tag: value
if value.match(ASSIGNMENT)
tag: 'ASSIGN'
throw new Error('SyntaxError: Reserved word "' + @value() + '" on line ' + @line + ' can\'t be assigned') if JS_FORBIDDEN.indexOf(@value()) >= 0
else if value is ';'
tag: 'TERMINATOR'
else if value is '[' and @tag() is '?' and not_spaced
tag: 'SOAKED_INDEX_START'
@soaked_index: true
@tokens.pop()
else if value is ']' and @soaked_index
tag: 'SOAKED_INDEX_END'
@soaked_index: false
else if CALLABLE.indexOf(@tag()) >= 0 and not_spaced
tag: 'CALL_START' if value is '('
tag: 'INDEX_START' if value is '['
@token tag, value
@i += value.length
true
# Helpers =============================================================
# Add a token to the results, taking note of the line number.
lex::token: (tag, value) ->
@tokens.push([tag, value, @line])
# Look at a tag in the current token stream.
lex::tag: (index, tag) ->
return unless tok: @prev(index)
return tok[0]: tag if tag?
tok[0]
# Look at a value in the current token stream.
lex::value: (index, val) ->
return unless tok: @prev(index)
return tok[1]: val if val?
tok[1]
# Look at a previous token.
lex::prev: (index) ->
@tokens[@tokens.length - (index or 1)]
# Count the occurences of a character in a string.
lex::count: (string, letter) ->
num: 0
pos: string.indexOf(letter)
while pos isnt -1
num += 1
pos: string.indexOf(letter, pos + 1)
num
# Attempt to match a string against the current chunk, returning the indexed
# match.
lex::match: (regex, index) ->
return false unless m: @chunk.match(regex)
if m then m[index] else false
# A source of ambiguity in our grammar was parameter lists in function
# definitions (as opposed to argument lists in function calls). Tag
# parameter identifiers in order to avoid this. Also, parameter lists can
# make use of splats.
lex::tag_parameters: ->
return if @tag() isnt ')'
i: 0
while true
i += 1
tok: @prev(i)
return if not tok
switch tok[0]
when 'IDENTIFIER' then tok[0]: 'PARAM'
when ')' then tok[0]: 'PARAM_END'
when '(' then return tok[0]: 'PARAM_START'
true
# Close up all remaining open blocks. IF the first token is an indent,
# axe it.
lex::close_indentation: ->
@outdent_token(@indent)
# Conversions from CoffeeScript operators into JavaScript ones.
CONVERSIONS: {
'and': '&&'
'or': '||'
'is': '=='
'isnt': '!='
'not': '!'
}

View File

@@ -1,42 +0,0 @@
# The Narwhal-compatibility wrapper for CoffeeScript.
# Require external dependencies.
os: require 'os'
file: require 'file'
coffee: require './coffee-script'
# Alias print to "puts", for Node.js compatibility:
puts: print
# Compile a string of CoffeeScript into JavaScript.
exports.compile: (source) ->
coffee.compile source
# Compile a given CoffeeScript file into JavaScript.
exports.compileFile: (path) ->
coffee.compile file.read path
# Make a factory for the CoffeeScript environment.
exports.makeNarwhalFactory: (path) ->
code: exports.compileFile path
factoryText: "function(require,exports,module,system,print){" + code + "/**/\n}"
if system.engine is "rhino"
Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null)
else
# eval requires parentheses, but parentheses break compileFunction.
eval "(" + factoryText + ")"
# The Narwhal loader for '.coffee' files.
factories: {}
loader: {}
# Reload the coffee-script environment from source.
loader.reload: (topId, path) ->
factories[topId]: ->
exports.makeNarwhalFactory path
# Ensure that the coffee-script environment is loaded.
loader.load: (topId, path) ->
factories[topId] ||= this.reload topId, path
require.loader.loaders.unshift [".coffee", loader]

File diff suppressed because it is too large Load Diff

View File

@@ -1,72 +1,88 @@
# Create an OptionParser with a list of valid options.
op: exports.OptionParser: (rules, banner) ->
@banner: banner or 'Usage: [Options]'
@options_title: 'Available options:'
@rules: build_rules(rules)
this
# A simple **OptionParser** class to parse option flags from the command-line.
# Use it like so:
#
# parser: new OptionParser switches, help_banner
# options: parser.parse process.argv
exports.OptionParser: class OptionParser
# Parse the argument array, calling defined callbacks, returning the remaining non-option arguments.
op::parse: (args) ->
options: {arguments: []}
args: args.concat []
while (arg: args.shift())
is_option: false
# Initialize with a list of valid options, in the form:
#
# [short-flag, long-flag, description]
#
# Along with an an optional banner for the usage help.
constructor: (rules, banner) ->
@banner: banner
@rules: build_rules(rules)
# Parse the list of arguments, populating an `options` object with all of the
# specified options, and returning it. `options.arguments` will be an array
# containing the remaning non-option arguments. This is a simpler API than
# many option parsers that allow you to attach callback actions for every
# flag. Instead, you're responsible for interpreting the options object.
parse: (args) ->
options: {arguments: []}
args: normalize_arguments args
while (arg: args.shift())
is_option: !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
matched_rule: no
for rule in @rules
if rule.short_flag is arg or rule.long_flag is arg
options[rule.name]: if rule.has_argument then args.shift() else true
matched_rule: yes
break
throw new Error "unrecognized option: $arg" if is_option and not matched_rule
options.arguments.push arg unless is_option
options
# Return the help text for this **OptionParser**, listing and describing all
# of the valid options, for `--help` and such.
help: ->
lines: ['Available options:']
lines.unshift "$@banner\n" if @banner
for rule in @rules
if rule.letter is arg or rule.flag is arg
options[rule.name]: if rule.argument then args.shift() else true
is_option: true
break
options.arguments.push arg unless is_option
options
spaces: 15 - rule.long_flag.length
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
let_part: if rule.short_flag then rule.short_flag + ', ' else ' '
lines.push " $let_part${rule.long_flag}$spaces${rule.description}"
"\n${ lines.join('\n') }\n"
# Return the help text for this OptionParser, for --help and such.
op::help: ->
longest: 0
has_shorts: false
lines: [@banner, '', @options_title]
for rule in @rules
has_shorts: true if rule.letter
longest: rule.flag.length if rule.flag.length > longest
for rule in @rules
if has_shorts
text: if rule.letter then spaces(2) + rule.letter + ', ' else spaces(6)
text += spaces(longest, rule.flag) + spaces(3)
text += rule.description
lines.push text
lines.join('\n')
# Private:
# Helpers
# -------
# Regex matchers for option flags.
LONG_FLAG: /^(--[\w\-]+)/
SHORT_FLAG: /^(-\w+)/
LONG_FLAG: /^(--\w[\w\-]+)/
SHORT_FLAG: /^(-\w)/
MULTI_FLAG: /^-(\w{2,})/
OPTIONAL: /\[(.+)\]/
# Build rules from a list of valid switch tuples in the form:
# [letter-flag, long-flag, help], or [long-flag, help].
# Build and return the list of option rules. If the optional *short-flag* is
# unspecified, leave it out by padding with `null`.
build_rules: (rules) ->
for tuple in rules
tuple.unshift(null) if tuple.length < 3
build_rule(tuple...)
tuple.unshift null if tuple.length < 3
build_rule tuple...
# Build a rule from a short-letter-flag, long-form-flag, and help text.
build_rule: (letter, flag, description) ->
match: flag.match(OPTIONAL)
flag: flag.match(LONG_FLAG)[1]
# Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the
# description of what the option does.
build_rule: (short_flag, long_flag, description) ->
match: long_flag.match(OPTIONAL)
long_flag: long_flag.match(LONG_FLAG)[1]
{
name: flag.substr(2)
letter: letter
flag: flag
name: long_flag.substr 2
short_flag: short_flag
long_flag: long_flag
description: description
argument: !!(match and match[1])
has_argument: !!(match and match[1])
}
# Space-pad a string with the specified number of characters.
spaces: (num, text) ->
builder: []
if text
return text if text.length >= num
num -= text.length
builder.push text
while num -= 1 then builder.push ' '
builder.join ''
# Normalize arguments by expanding merged flags into multiple flags. This allows
# you to have `-wl` be the same as `--watch --lint`.
normalize_arguments: (args) ->
args: args.slice 0
result: []
for arg in args
if match: arg.match MULTI_FLAG
result.push '-' + l for l in match[1].split ''
else
result.push arg
result

View File

@@ -1,23 +1,33 @@
# A CoffeeScript port/version of the Node.js REPL.
# A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
# and evaluates it. Good for simple tests, or poking around the **Node.js** API.
# Using it looks like this:
#
# coffee> puts "$num bottles of beer" for num in [99..1]
# Required modules.
coffee: require 'coffee-script'
# Require the **coffee-script** module to get access to the compiler.
CoffeeScript: require './coffee-script'
helpers: require('./helpers').helpers
# Shortcut variables.
# Our prompt.
prompt: 'coffee> '
quit: -> process.exit(0)
# The main REPL function. Called everytime a line of code is entered.
# Attempt to evaluate the command. If there's an exception, print it.
readline: (code) ->
# Quick alias for quitting the REPL.
helpers.extend global, {
quit: -> process.exit(0)
}
# The main REPL function. **run** is called every time a line of code is entered.
# Attempt to evaluate the command. If there's an exception, print it out instead
# of exiting.
run: (code) ->
try
val: eval coffee.compile code, {no_wrap: true, globals: true}
val: CoffeeScript.run code, {no_wrap: true, globals: true, source: 'repl'}
p val if val isnt undefined
catch err
puts err.stack or err.toString()
print prompt
# Start up the REPL.
process.stdio.addListener 'data', readline
# Start up the REPL by opening **stdio** and listening for input.
process.stdio.addListener 'data', run
process.stdio.open()
print prompt

View File

@@ -1,253 +1,282 @@
this.exports: this unless process?
# The CoffeeScript language has a good deal of optional syntax, implicit syntax,
# and shorthand syntax. This can greatly complicate a grammar and bloat
# the resulting parse table. Instead of making the parser handle it all, we take
# a series of passes over the token stream, using this **Rewriter** to convert
# shorthand into the unambiguous long form, add implicit indentation and
# parentheses, balance incorrect nestings, and generally clean things up.
# In order to keep the grammar simple, the stream of tokens that the Lexer
# emits is rewritten by the Rewriter, smoothing out ambiguities, mis-nested
# indentation, and single-line flavors of expressions.
exports.Rewriter: re: ->
# Set up exported variables for both Node.js and the browser.
if process?
helpers: require('./helpers').helpers
else
this.exports: this
helpers: this.helpers
# Tokens that must be balanced.
# Import the helpers we need.
include: helpers.include
# The **Rewriter** class is used by the [Lexer](lexer.html), directly against
# its internal array of tokens.
exports.Rewriter: class Rewriter
# Rewrite the token stream in multiple passes, one logical filter at
# a time. This could certainly be changed into a single pass through the
# stream, with a big ol' efficient switch, but it's much nicer to work with
# like this. The order of these passes matters -- indentation must be
# corrected before implicit parentheses can be wrapped around blocks of code.
rewrite: (tokens) ->
@tokens: tokens
@adjust_comments()
@remove_leading_newlines()
@remove_mid_expression_newlines()
@close_open_calls_and_indexes()
@add_implicit_indentation()
@add_implicit_parentheses()
@ensure_balance BALANCED_PAIRS
@rewrite_closing_parens()
@tokens
# Rewrite the token stream, looking one token ahead and behind.
# Allow the return value of the block to tell us how many tokens to move
# forwards (or backwards) in the stream, to make sure we don't miss anything
# as tokens are inserted and removed, and the stream changes length under
# our feet.
scan_tokens: (block) ->
i: 0
while true
break unless @tokens[i]
move: block @tokens[i - 1], @tokens[i], @tokens[i + 1], i
i: + move
true
# Massage newlines and indentations so that comments don't have to be
# correctly indented, or appear on a line of their own.
adjust_comments: ->
@scan_tokens (prev, token, post, i) =>
return 1 unless token[0] is 'COMMENT'
after: @tokens[i + 2]
if after and after[0] is 'INDENT'
@tokens.splice i + 2, 1
@tokens.splice i, 0, after
return 1
else if prev and prev[0] isnt 'TERMINATOR' and prev[0] isnt 'INDENT' and prev[0] isnt 'OUTDENT'
@tokens.splice i, 0, ['TERMINATOR', "\n", prev[2]]
return 2
else
return 1
# Leading newlines would introduce an ambiguity in the grammar, so we
# dispatch them here.
remove_leading_newlines: ->
@tokens.shift() while @tokens[0] and @tokens[0][0] is 'TERMINATOR'
# Some blocks occur in the middle of expressions -- when we're expecting
# this, remove their trailing newlines.
remove_mid_expression_newlines: ->
@scan_tokens (prev, token, post, i) =>
return 1 unless post and include(EXPRESSION_CLOSE, post[0]) and token[0] is 'TERMINATOR'
@tokens.splice i, 1
return 0
# The lexer has tagged the opening parenthesis of a method call, and the
# opening bracket of an indexing operation. Match them with their paired
# close.
close_open_calls_and_indexes: ->
parens: [0]
brackets: [0]
@scan_tokens (prev, token, post, i) =>
switch token[0]
when 'CALL_START' then parens.push 0
when 'INDEX_START' then brackets.push 0
when '(' then parens[parens.length - 1]: + 1
when '[' then brackets[brackets.length - 1]: + 1
when ')'
if parens[parens.length - 1] is 0
parens.pop()
token[0]: 'CALL_END'
else
parens[parens.length - 1]: - 1
when ']'
if brackets[brackets.length - 1] == 0
brackets.pop()
token[0]: 'INDEX_END'
else
brackets[brackets.length - 1]: - 1
return 1
# Methods may be optionally called without parentheses, for simple cases.
# Insert the implicit parentheses here, so that the parser doesn't have to
# deal with them.
add_implicit_parentheses: ->
stack: [0]
calls: 0
parens: 0
start_parens: 0
@scan_tokens (prev, token, post, i) =>
tag: token[0]
switch tag
when 'CALL_START' then calls: + 1
when 'CALL_END' then calls: - 1
when '(' then parens: + 1
when ')' then parens: - 1
when 'INDENT' then stack.push 0
when 'OUTDENT'
last: stack.pop()
stack[stack.length - 1]: + last
open: stack[stack.length - 1] > 0
if !post? or (start_parens > parens) or (parens is 0 and include IMPLICIT_END, tag)
return 1 if tag is 'INDENT' and prev and include IMPLICIT_BLOCK, prev[0]
return 1 if tag is 'OUTDENT' and token.generated
if open or tag is 'INDENT'
idx: if tag is 'OUTDENT' then i + 1 else i
stack_pointer: if tag is 'INDENT' then 2 else 1
for tmp in [0...stack[stack.length - stack_pointer]]
@tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
size: stack[stack.length - stack_pointer] + 1
stack[stack.length - stack_pointer]: 0
return size
return 1 unless prev and include(IMPLICIT_FUNC, prev[0]) and include(IMPLICIT_CALL, tag)
calls: 0
start_parens: if tag is '(' then parens - 1 else parens
@tokens.splice i, 0, ['CALL_START', '(', token[2]]
stack[stack.length - 1]: + 1
return 2
# Because our grammar is LALR(1), it can't handle some single-line
# expressions that lack ending delimiters. The **Rewriter** adds the implicit
# blocks, so it doesn't need to. ')' can close a single-line block,
# but we need to make sure it's balanced.
add_implicit_indentation: ->
@scan_tokens (prev, token, post, i) =>
return 1 unless include(SINGLE_LINERS, token[0]) and
post[0] isnt 'INDENT' and
not (token[0] is 'ELSE' and post[0] is 'IF')
starter: token[0]
@tokens.splice i + 1, 0, ['INDENT', 2, token[2]]
idx: i + 1
parens: 0
while true
idx: + 1
tok: @tokens[idx]
pre: @tokens[idx - 1]
if (not tok or
(include(SINGLE_CLOSERS, tok[0]) and tok[1] isnt ';') or
(tok[0] is ')' and parens is 0)) and
not (starter is 'ELSE' and tok[0] is 'ELSE')
insertion: if pre[0] is "," then idx - 1 else idx
outdent: ['OUTDENT', 2, token[2]]
outdent.generated: true
@tokens.splice insertion, 0, outdent
break
parens: + 1 if tok[0] is '('
parens: - 1 if tok[0] is ')'
return 1 unless token[0] is 'THEN'
@tokens.splice i, 1
return 0
# Ensure that all listed pairs of tokens are correctly balanced throughout
# the course of the token stream.
ensure_balance: (pairs) ->
levels: {}
open_line: {}
@scan_tokens (prev, token, post, i) =>
for pair in pairs
[open, close]: pair
levels[open]: or 0
if token[0] is open
open_line[open]: token[2] if levels[open] == 0
levels[open]: + 1
levels[open]: - 1 if token[0] is close
throw new Error("too many ${token[1]} on line ${token[2] + 1}") if levels[open] < 0
return 1
unclosed: key for key, value of levels when value > 0
if unclosed.length
open: unclosed[0]
line: open_line[open] + 1
throw new Error "unclosed $open on line $line"
# We'd like to support syntax like this:
#
# el.click((event) ->
# el.hide())
#
# In order to accomplish this, move outdents that follow closing parens
# inwards, safely. The steps to accomplish this are:
#
# 1. Check that all paired tokens are balanced and in order.
# 2. Rewrite the stream with a stack: if you see an `EXPRESSION_START`, add it
# to the stack. If you see an `EXPRESSION_END`, pop the stack and replace
# it with the inverse of what we've just popped.
# 3. Keep track of "debt" for tokens that we manufacture, to make sure we end
# up balanced in the end.
#
rewrite_closing_parens: ->
stack: []
debt: {}
(debt[key]: 0) for key, val of INVERSES
@scan_tokens (prev, token, post, i) =>
tag: token[0]
inv: INVERSES[token[0]]
if include EXPRESSION_START, tag
stack.push token
return 1
else if include EXPRESSION_END, tag
if debt[inv] > 0
debt[inv]: - 1
@tokens.splice i, 1
return 0
else
match: stack.pop()
mtag: match[0]
return 1 if tag is INVERSES[mtag]
debt[mtag]: + 1
val: if mtag is 'INDENT' then match[1] else INVERSES[mtag]
@tokens.splice i, 0, [INVERSES[mtag], val]
return 1
else
return 1
# Constants
# ---------
# List of the token pairs that must be balanced.
BALANCED_PAIRS: [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'],
['PARAM_START', 'PARAM_END'], ['CALL_START', 'CALL_END'],
['INDEX_START', 'INDEX_END'], ['SOAKED_INDEX_START', 'SOAKED_INDEX_END']]
# Tokens that signal the start of a balanced pair.
EXPRESSION_START: pair[0] for pair in BALANCED_PAIRS
# Tokens that signal the end of a balanced pair.
EXPRESSION_TAIL: pair[1] for pair in BALANCED_PAIRS
# Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE: ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_TAIL)
# Tokens pairs that, in immediate succession, indicate an implicit call.
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END']
IMPLICIT_BLOCK:['->', '=>', '{', '[', ',']
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT']
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
'TRY', 'DELETE', 'TYPEOF', 'SWITCH',
'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT',
'@', '->', '=>', '[', '(', '{']
# The inverse mappings of token pairs we're trying to fix up.
# The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
# look things up from either end.
INVERSES: {}
for pair in BALANCED_PAIRS
INVERSES[pair[0]]: pair[1]
INVERSES[pair[1]]: pair[0]
# The tokens that signal the start of a balanced pair.
EXPRESSION_START: pair[0] for pair in BALANCED_PAIRS
# The tokens that signal the end of a balanced pair.
EXPRESSION_END: pair[1] for pair in BALANCED_PAIRS
# Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE: ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END
# Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-']
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION',
'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT',
'THIS', 'NULL',
'@', '->', '=>', '[', '(', '{']
# Tokens indicating that the implicit call must enclose a block of expressions.
IMPLICIT_BLOCK: ['->', '=>', '{', '[', ',']
# Tokens that always mark the end of an implicit call for single-liners.
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT']
# Single-line flavors of block expressions that have unclosed endings.
# The grammar can't disambiguate them, so we insert the implicit indentation.
SINGLE_LINERS: ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN']
SINGLE_CLOSERS: ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN', 'PARAM_START']
# Rewrite the token stream in multiple passes, one logical filter at
# a time. This could certainly be changed into a single pass through the
# stream, with a big ol' efficient switch, but it's much nicer like this.
re::rewrite: (tokens) ->
@tokens: tokens
@adjust_comments()
@remove_leading_newlines()
@remove_mid_expression_newlines()
@move_commas_outside_outdents()
@close_open_calls_and_indexes()
@add_implicit_indentation()
@add_implicit_parentheses()
@ensure_balance(BALANCED_PAIRS)
@rewrite_closing_parens()
@tokens
# Rewrite the token stream, looking one token ahead and behind.
# Allow the return value of the block to tell us how many tokens to move
# forwards (or backwards) in the stream, to make sure we don't miss anything
# as the stream changes length under our feet.
re::scan_tokens: (block) ->
i: 0
while true
break unless @tokens[i]
move: block(@tokens[i - 1], @tokens[i], @tokens[i + 1], i)
i += move
true
# Massage newlines and indentations so that comments don't have to be
# correctly indented, or appear on their own line.
re::adjust_comments: ->
@scan_tokens (prev, token, post, i) =>
return 1 unless token[0] is 'COMMENT'
before: @tokens[i - 2]
after: @tokens[i + 2]
if before and after and
((before[0] is 'INDENT' and after[0] is 'OUTDENT') or
(before[0] is 'OUTDENT' and after[0] is 'INDENT')) and
before[1] is after[1]
@tokens.splice(i + 2, 1)
@tokens.splice(i - 2, 1)
return 0
else if prev and prev[0] is 'TERMINATOR' and after and after[0] is 'INDENT'
@tokens.splice(i + 2, 1)
@tokens[i - 1]: after
return 1
else if prev and prev[0] isnt 'TERMINATOR' and prev[0] isnt 'INDENT' and prev[0] isnt 'OUTDENT'
@tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]])
return 2
else
return 1
# Leading newlines would introduce an ambiguity in the grammar, so we
# dispatch them here.
re::remove_leading_newlines: ->
@tokens.shift() if @tokens[0][0] is 'TERMINATOR'
# Some blocks occur in the middle of expressions -- when we're expecting
# this, remove their trailing newlines.
re::remove_mid_expression_newlines: ->
@scan_tokens (prev, token, post, i) =>
return 1 unless post and EXPRESSION_CLOSE.indexOf(post[0]) >= 0 and token[0] is 'TERMINATOR'
@tokens.splice(i, 1)
return 0
# Make sure that we don't accidentally break trailing commas, which need
# to go on the outside of expression closers.
re::move_commas_outside_outdents: ->
@scan_tokens (prev, token, post, i) =>
@tokens.splice(i, 1, token) if token[0] is 'OUTDENT' and prev[0] is ','
return 1
# We've tagged the opening parenthesis of a method call, and the opening
# bracket of an indexing operation. Match them with their close.
re::close_open_calls_and_indexes: ->
parens: [0]
brackets: [0]
@scan_tokens (prev, token, post, i) =>
switch token[0]
when 'CALL_START' then parens.push(0)
when 'INDEX_START' then brackets.push(0)
when '(' then parens[parens.length - 1] += 1
when '[' then brackets[brackets.length - 1] += 1
when ')'
if parens[parens.length - 1] is 0
parens.pop()
token[0]: 'CALL_END'
else
parens[parens.length - 1] -= 1
when ']'
if brackets[brackets.length - 1] == 0
brackets.pop()
token[0]: 'INDEX_END'
else
brackets[brackets.length - 1] -= 1
return 1
# Methods may be optionally called without parentheses, for simple cases.
# Insert the implicit parentheses here, so that the parser doesn't have to
# deal with them.
re::add_implicit_parentheses: ->
stack: [0]
@scan_tokens (prev, token, post, i) =>
tag: token[0]
stack.push(0) if tag is 'INDENT'
if tag is 'OUTDENT'
last: stack.pop()
stack[stack.length - 1] += last
if IMPLICIT_END.indexOf(tag) >= 0 or !post?
return 1 if tag is 'INDENT' and prev and IMPLICIT_BLOCK.indexOf(prev[0]) >= 0
if stack[stack.length - 1] > 0 or tag is 'INDENT'
idx: if tag is 'OUTDENT' then i + 1 else i
stack_pointer: if tag is 'INDENT' then 2 else 1
for tmp in [0...stack[stack.length - stack_pointer]]
@tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
size: stack[stack.length - stack_pointer] + 1
stack[stack.length - stack_pointer]: 0
return size
return 1 unless prev and IMPLICIT_FUNC.indexOf(prev[0]) >= 0 and IMPLICIT_CALL.indexOf(tag) >= 0
@tokens.splice(i, 0, ['CALL_START', '(', token[2]])
stack[stack.length - 1] += 1
return 2
# Because our grammar is LALR(1), it can't handle some single-line
# expressions that lack ending delimiters. Use the lexer to add the implicit
# blocks, so it doesn't need to.
# ')' can close a single-line block, but we need to make sure it's balanced.
re::add_implicit_indentation: ->
@scan_tokens (prev, token, post, i) =>
return 1 unless SINGLE_LINERS.indexOf(token[0]) >= 0 and post[0] isnt 'INDENT' and
not (token[0] is 'ELSE' and post[0] is 'IF')
starter: token[0]
@tokens.splice(i + 1, 0, ['INDENT', 2, token[2]])
idx: i + 1
parens: 0
while true
idx += 1
tok: @tokens[idx]
if (not tok or
(SINGLE_CLOSERS.indexOf(tok[0]) >= 0 and tok[1] isnt ';') or
(tok[0] is ')' && parens is 0)) and
not (starter is 'ELSE' and tok[0] is 'ELSE')
insertion: if @tokens[idx - 1][0] is "," then idx - 1 else idx
@tokens.splice(insertion, 0, ['OUTDENT', 2, token[2]])
break
parens += 1 if tok[0] is '('
parens -= 1 if tok[0] is ')'
return 1 unless token[0] is 'THEN'
@tokens.splice(i, 1)
return 0
# Ensure that all listed pairs of tokens are correctly balanced throughout
# the course of the token stream.
re::ensure_balance: (pairs) ->
levels: {}
@scan_tokens (prev, token, post, i) =>
for pair in pairs
[open, close]: pair
levels[open] ||= 0
levels[open] += 1 if token[0] is open
levels[open] -= 1 if token[0] is close
throw new Error("too many " + token[1]) if levels[open] < 0
return 1
unclosed: key for key, value of levels when value > 0
throw new Error("unclosed " + unclosed[0]) if unclosed.length
# We'd like to support syntax like this:
# el.click((event) ->
# el.hide())
# In order to accomplish this, move outdents that follow closing parens
# inwards, safely. The steps to accomplish this are:
#
# 1. Check that all paired tokens are balanced and in order.
# 2. Rewrite the stream with a stack: if you see an '(' or INDENT, add it
# to the stack. If you see an ')' or OUTDENT, pop the stack and replace
# it with the inverse of what we've just popped.
# 3. Keep track of "debt" for tokens that we fake, to make sure we end
# up balanced in the end.
#
re::rewrite_closing_parens: ->
stack: []
debt: {}
(debt[key]: 0) for key, val of INVERSES
@scan_tokens (prev, token, post, i) =>
tag: token[0]
inv: INVERSES[token[0]]
# Push openers onto the stack.
if EXPRESSION_START.indexOf(tag) >= 0
stack.push(token)
return 1
# The end of an expression, check stack and debt for a pair.
else if EXPRESSION_TAIL.indexOf(tag) >= 0
# If the tag is already in our debt, swallow it.
if debt[inv] > 0
debt[inv] -= 1
@tokens.splice(i, 1)
return 0
else
# Pop the stack of open delimiters.
match: stack.pop()
mtag: match[0]
# Continue onwards if it's the expected tag.
if tag is INVERSES[mtag]
return 1
else
# Unexpected close, insert correct close, adding to the debt.
debt[mtag] += 1
val: if mtag is 'INDENT' then match[1] else INVERSES[mtag]
@tokens.splice(i, 0, [INVERSES[mtag], val])
return 1
else
return 1
SINGLE_CLOSERS: ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']

View File

@@ -1,75 +1,91 @@
# The **Scope** class regulates lexical scoping within CoffeeScript. As you
# generate code, you create a tree of scopes in the same shape as the nested
# function bodies. Each scope knows about the variables declared within it,
# and has a reference to its parent enclosing scope. In this way, we know which
# variables are new and need to be declared with `var`, and which are shared
# with the outside.
# Set up exported variables for both **Node.js** and the browser.
this.exports: this unless process?
# Scope objects form a tree corresponding to the shape of the function
# definitions present in the script. They provide lexical scope, to determine
# whether a variable has been seen before or if it needs to be declared.
#
# Initialize a scope with its parent, for lookups up the chain,
# as well as the Expressions body where it should declare its variables,
# and the function that it wraps.
Scope: exports.Scope: (parent, expressions, method) ->
[@parent, @expressions, @method]: [parent, expressions, method]
@variables: {}
@temp_var: if @parent then @parent.temp_var else '_a'
this
exports.Scope: class Scope
# Look up a variable in lexical scope, or declare it if not found.
Scope::find: (name) ->
return true if @check name
@variables[name]: 'var'
false
# The top-level **Scope** object.
@root: null
# Define a local variable as originating from a parameter in current scope
# -- no var required.
Scope::parameter: (name) ->
@variables[name]: 'param'
# Initialize a scope with its parent, for lookups up the chain,
# as well as a reference to the **Expressions** node is belongs to, which is
# where it should declare its variables, and a reference to the function that
# it wraps.
constructor: (parent, expressions, method) ->
[@parent, @expressions, @method]: [parent, expressions, method]
@variables: {}
if @parent
@temp_var: @parent.temp_var
else
Scope.root: this
@temp_var: '_a'
# Just check to see if a variable has already been declared.
Scope::check: (name) ->
return true if @variables[name]
!!(@parent and @parent.check(name))
# Look up a variable name in lexical scope, and declare it if it does not
# already exist.
find: (name) ->
return true if @check name
@variables[name]: 'var'
false
# You can reset a found variable on the immediate scope.
Scope::reset: (name) ->
delete @variables[name]
# Test variables and return true the first time fn(v, k) returns true
any: (fn) ->
for v, k of @variables when fn(v, k)
return true
return false
# Find an available, short, name for a compiler-generated variable.
Scope::free_variable: ->
while @check @temp_var
ordinal: 1 + parseInt @temp_var.substr(1), 36
@temp_var: '_' + ordinal.toString(36).replace(/\d/g, 'a')
@variables[@temp_var]: 'var'
@temp_var
# Reserve a variable name as originating from a function parameter for this
# scope. No `var` required for internal references.
parameter: (name) ->
@variables[name]: 'param'
# Ensure that an assignment is made at the top of scope (or top-level
# scope, if requested).
Scope::assign: (name, value, top_level) ->
return @parent.assign(name, value, top_level) if top_level and @parent
@variables[name]: {value: value, assigned: true}
# Just check to see if a variable has already been declared, without reserving.
check: (name) ->
return true if @variables[name]
!!(@parent and @parent.check(name))
# Does this scope reference any variables that need to be declared in the
# given function body?
Scope::has_declarations: (body) ->
body is @expressions and @declared_variables().length
# If we need to store an intermediate result, find an available name for a
# compiler-generated variable. `_a`, `_b`, and so on...
free_variable: ->
while @check @temp_var
ordinal: 1 + parseInt @temp_var.substr(1), 36
@temp_var: '_' + ordinal.toString(36).replace(/\d/g, 'a')
@variables[@temp_var]: 'var'
@temp_var
# Does this scope reference any assignments that need to be declared at the
# top of the given function body?
Scope::has_assignments: (body) ->
body is @expressions and @assigned_variables().length
# Ensure that an assignment is made at the top of this scope
# (or at the top-level scope, if requested).
assign: (name, value) ->
@variables[name]: {value: value, assigned: true}
# Return the list of variables first declared in current scope.
Scope::declared_variables: ->
(key for key, val of @variables when val is 'var').sort()
# Does this scope reference any variables that need to be declared in the
# given function body?
has_declarations: (body) ->
body is @expressions and @any (k, val) -> val is 'var'
# Return the list of variables that are supposed to be assigned at the top
# of scope.
Scope::assigned_variables: ->
key + ' = ' + val.value for key, val of @variables when val.assigned
# Does this scope reference any assignments that need to be declared at the
# top of the given function body?
has_assignments: (body) ->
body is @expressions and @any (k, val) -> val.assigned
# Compile the string representing all of the declared variables for this scope.
Scope::compiled_declarations: ->
@declared_variables().join ', '
# Return the list of variables first declared in this scope.
declared_variables: ->
(key for key, val of @variables when val is 'var').sort()
# Compile the string performing all of the variable assignments for this scope.
Scope::compiled_assignments: ->
@assigned_variables().join ', '
# Return the list of assignments that are supposed to be made at the top
# of this scope.
assigned_variables: ->
"$key = ${val.value}" for key, val of @variables when val.assigned
# Compile the JavaScript for all of the variable declarations in this scope.
compiled_declarations: ->
@declared_variables().join ', '
# Compile the JavaScript for all of the variable assignments in this scope.
compiled_assignments: ->
@assigned_variables().join ', '

View File

@@ -4,31 +4,22 @@ area: (x, y, x1, y1) ->
x: y: 10
x1: y1: 20
ok area(x, y, x1, y1) is 100, 'basic arguments'
ok area(x, y, x1, y1) is 100
ok(area(x, y,
x1, y1) is 100, 'arguments on split lines')
x1, y1) is 100)
ok(area(
x
y
x1
y1
) is 100, 'newline delimited arguments')
) is 100)
curried: ->
ok area.apply(this, arguments.concat(20, 20)) is 100, 'arguments converted into an array'
sum_of_args: ->
sum: 0
sum: + val for val in arguments
sum
curried 10, 10
func: ->
arguments: 25
arguments
ok func(100) is 25, 'arguments as a regular identifier'
this.arguments: 10
ok @arguments is 10, 'arguments accessed as a property'
ok sum_of_args(1, 2, 3, 4, 5) is 15

View File

@@ -1,42 +0,0 @@
nums: n * n for n in [1, 2, 3] when n % 2 isnt 0
results: n * 2 for n in nums
ok results.join(',') is '2,18', 'basic array comprehension'
obj: {one: 1, two: 2, three: 3}
names: prop + '!' for prop of obj
odds: prop + '!' for prop, value of obj when value % 2 isnt 0
ok names.join(' ') is "one! two! three!", 'basic object comprehension'
ok odds.join(' ') is "one! three!", 'object comprehension with a filter'
evens: for num in [1, 2, 3, 4, 5, 6] when num % 2 is 0
num *= -1
num -= 2
num * -1
ok evens.join(', ') is '4, 6, 8', 'multiline array comprehension with filter'
ok 2 in evens, 'the in operator still works, standalone'
# Ensure that the closure wrapper preserves local variables.
obj: {}
methods: ['one', 'two', 'three']
for method in methods
name: method
obj[name]: ->
"I'm " + name
ok obj.one() is "I'm one"
ok obj.two() is "I'm two"
ok obj.three() is "I'm three"
array: [0..10]
ok(num % 2 is 0 for num in array by 2, 'naked ranges are expanded into arrays')

View File

@@ -1,3 +1,4 @@
# Can assign the result of a try/catch block.
result: try
nonexistent * missing
catch error
@@ -5,20 +6,22 @@ catch error
result2: try nonexistent * missing catch error then true
ok result is true and result2 is true, 'can assign the result of a try/catch block'
ok result is true and result2 is true
# Can assign a conditional statement.
get_x: -> 10
if x: get_x() then 100
ok x is 10, 'can assign a conditional statement'
ok x is 10
x: if get_x() then 100
ok x is 100, 'can assign a conditional statement'
ok x is 100
# This-assignment.
tester: ->
@example: -> puts 'example function'
this

20
test/test_bind.coffee Normal file
View File

@@ -0,0 +1,20 @@
f: (x,y,z) ->
x * y * z * ((@num or 4) + 5)
obj: {num: 5}
func: f <- obj, 1, 1
ok func(2) is 20
func: f <- {}, 1, 2
ok func(2) is 36
func: f <- obj
ok func(1, 2, 3) is 60
in_first_ten: helpers.include <- null, [0...10]
ok in_first_ten 3
ok in_first_ten 9
ok not in_first_ten -1
ok not in_first_ten 12

View File

@@ -1,4 +1,25 @@
# Basic blocks.
results: [1, 2, 3].map (x) ->
x * x
ok results.join(' ') is '1 4 9', 'basic block syntax'
ok results.join(' ') is '1 4 9'
# Chained blocks, with proper indentation levels:
results: []
counter: {
tick: (func) ->
results.push func()
this
}
counter
.tick ->
3
.tick ->
2
.tick ->
1
ok results.join(' ') is '3 2 1'

Some files were not shown because too many files have changed in this diff Show More