Compare commits

...

205 Commits
1.0.0 ... 1.1.0

Author SHA1 Message Date
Jeremy Ashkenas
09712603c4 coffee-script 1.1.0 2011-05-01 12:08:15 -04:00
Jeremy Ashkenas
2fb7ccc8f0 Revert "Fix for #1304 ... but disallows an alternative syntax."
This reverts commit 31bfe50831.
2011-05-01 10:43:50 -04:00
Jeremy Ashkenas
31bfe50831 Fix for #1304 ... but disallows an alternative syntax. 2011-05-01 10:16:04 -04:00
Jeremy Ashkenas
9aa3b5b78c showing line number information for failed tests. 2011-05-01 10:11:56 -04:00
Jeremy Ashkenas
7480f55e53 making end implicit tokens generated 2011-05-01 10:03:50 -04:00
Jeremy Ashkenas
5fd82e829b fixing test.html 2011-05-01 08:28:00 -04:00
Jeremy Ashkenas
43ebec1812 Merge branch 'master' of github.com:jashkenas/coffee-script 2011-05-01 08:12:27 -04:00
Michael Ficarra
5cdf02f840 Merge pull request #1309 from TrevorBurnham/sandbox.
Fixing unavailability of `global` properties on REPL
2011-04-30 23:26:25 -07:00
Trevor Burnham
824e081005 Fixing unavailability of global properties on REPL 2011-05-01 01:45:14 -04:00
Trevor Burnham
fc992ba380 Using process.mainModule.filename instead of passing __filename 2011-04-30 23:01:36 -04:00
Trevor Burnham
264070bfc7 Making process.execPath point to coffee when running .coffee files
Related: #1303 set `process.argv[0]` to `coffee`. This makes
`process.execPath` consistent with that change.
2011-04-30 19:45:32 -04:00
Jeremy Ashkenas
a91509ba72 reintroducing a variant of kit's in-order script loading fix. 2011-04-30 13:48:54 -04:00
Jeremy Ashkenas
0dfe2429bc reverted @kitgoncharov's commits that broke the browser runner. 2011-04-30 13:33:28 -04:00
Jeremy Ashkenas
f1ad2e1fae Revert "Fix a typo in browser.coffee."
This reverts commit 6793eb383c.
2011-04-30 13:32:26 -04:00
Jeremy Ashkenas
c51679810a fixing unfoldSoak performance my memoizing. #1033 2011-04-30 13:13:09 -04:00
Jeremy Ashkenas
468ad1a2d5 Updating README and website with -g instructions. 2011-04-30 11:10:37 -04:00
Jeremy Ashkenas
bf8fbc2c0e Fixing process.argv[0] ... #1303 2011-04-30 10:59:55 -04:00
Jeremy Ashkenas
0ed8ae28e7 merging #1303 ... setting process.argv[0] to coffee for coffee's run. 2011-04-30 10:39:28 -04:00
Jeremy Ashkenas
f76ad8912c Merge pull request #1305 from benatkin/patch-1.
Updated for npm 1.0: the -g option installs to the global npm bin directory
2011-04-30 07:36:43 -07:00
Jeremy Ashkenas
83e7d442fb slightly less sketchy fix for #1106. 2011-04-30 10:35:56 -04:00
Jeremy Ashkenas
76252659fd Merge pull request #1300 from michaelficarra/issue1106.
fixes issue #1106
2011-04-30 07:29:41 -07:00
Ben Atkin
19036348a5 Updated for npm 1.0: the -g option installs to the global npm bin directory.
Without -g, the bin is in node-modules/.bin/coffee.
2011-04-29 19:57:18 -07:00
Michael Ficarra
7efea4bb23 removed "globals" option of CoffeeScript.compile and enhanced fix from
previous commits
2011-04-29 15:53:30 -04:00
Michael Ficarra
63ce244359 Better fixes for problem mentioned in last 3 commits. Also adds _
special value (as in node's REPL) that always holds return value of last
executed expression. Finally, fixes #1109
2011-04-29 13:59:59 -04:00
Michael Ficarra
0bdf9538d0 Recently discussed problem has been understood. Adding relevant values
to the global scope upon `eval` in REPL.

See bcf1e178a1 (commitcomment-362493)
2011-04-29 09:29:25 -04:00
Michael Ficarra
b88e23892f Fixes broken require from last commit. We're not actually sure yet
*why* `require` and only `require` was affected. All other globals that
I tried were unaffected: `console`, `parseInt`, `process`, `global`,
`Array`, `Object`, `Buffer`, `setTimeout`, ...
2011-04-29 09:18:47 -04:00
Michael Ficarra
bcf1e178a1 Fixes error in REPL where any variable defined in
`src/coffee-script.coffee` is shared with the REPL scope. Example: try
`lexer` or `@VERSION` pre-commit.
2011-04-29 02:32:16 -04:00
Trevor Burnham
fe889b8428 Setting process.argv[0] to 'coffee' in the REPL (aesthetic) 2011-04-28 18:35:42 -04:00
Trevor Burnham
cde7498c8e Setting process.argv[0] to 'coffee' in 'coffee foo.coffee'
See #1301 et al.
2011-04-28 18:27:40 -04:00
Jeremy Ashkenas
a27feb4157 Making the naming of the --join'd coffeescript mandatory. Issue #1076. 2011-04-27 23:06:58 -04:00
Jeremy Ashkenas
a93c835557 Issue #1006, infinite loop in addImplicitParentheses. 2011-04-27 22:49:42 -04:00
Michael Ficarra
5cd5821c18 #1106 test case: making sure __proto__ exists in case v8 ever removes it 2011-04-27 18:57:22 -07:00
Jeremy Ashkenas
3912e29eb7 Merge branch 'master' of github.com:jashkenas/coffee-script 2011-04-27 21:56:31 -04:00
Jeremy Ashkenas
0bad04d374 Issue #1182 -- subclasses with external constructor functions. 2011-04-27 21:56:08 -04:00
Michael Ficarra
50c3a64553 fixes #1106; __proto__ compilation 2011-04-27 21:39:30 -04:00
Michael Ficarra
cd8492dd7b test for #1106 2011-04-27 21:36:29 -04:00
Jeremy Ashkenas
79e160a46b Edited documentation/index.html.erb via GitHub 2011-04-27 06:51:05 -07:00
Timothy Jones
761b3b3646 Merged pull request #1298 from pjaspers/patch-1.
Typo error, s/synax/syntax
2011-04-27 03:18:32 -07:00
Piet Jaspers
937f027f3c Typo error, s/synax/syntax 2011-04-27 00:57:37 -07:00
Jeremy Ashkenas
da14538299 Issue #1272 documentation 2011-04-26 21:47:48 -04:00
Jeremy Ashkenas
02fbf766ad removing erroneous tabs from nodes.coffee. 2011-04-26 21:23:51 -04:00
Jeremy Ashkenas
b13bef7f45 #1256, documentation typo 2011-04-26 20:46:07 -04:00
Jeremy Ashkenas
5e1aadba80 expanding on the sentence that talks about standalone extends ... Issue #1258 2011-04-26 20:42:24 -04:00
Jeremy Ashkenas
44e0bbf342 Issue #1262, print filename in error messages for require module scripts. 2011-04-26 20:35:30 -04:00
Jeremy Ashkenas
a7ed3379df merging in kit's in-order execution patch. 2011-04-23 13:40:40 -04:00
Jeremy Ashkenas
19849e66d4 renaming wordy test titles. 2011-04-23 13:35:15 -04:00
Jeremy Ashkenas
e9dac2fddc Fixes #1280, regex and compound division mixup. 2011-04-23 13:33:35 -04:00
Jeremy Ashkenas
e61fe48b4d Issue #1294, throw the error for a bad symlink reference when compiling a file. 2011-04-23 13:21:58 -04:00
Jeremy Ashkenas
7e8b52ad70 be more consistent about === 2011-04-20 23:43:41 -04:00
Jeremy Ashkenas
d5a5f9572e be consistent about triple-equals-equality. 2011-04-20 23:24:59 -04:00
Jeremy Ashkenas
fe4f7f8b0f Merge branch 'gh-pages' of https://github.com/willmoffat/coffee-script 2011-04-20 23:16:27 -04:00
Jeremy Ashkenas
4e3f80749f merging issue #1127 2011-04-20 23:12:05 -04:00
Jeremy Ashkenas
ff8c340330 Merge branch 'keyboard' of https://github.com/willmoffat/coffee-script 2011-04-20 23:10:48 -04:00
Jeremy Ashkenas
039109ed56 Removing resources section from the homepage, in favor of linking to the Wiki. #1137 2011-04-20 23:08:21 -04:00
Jeremy Ashkenas
f3f34e9ef5 Fixes #1188, scope for self-referencing functions. 2011-04-20 22:16:56 -04:00
Jeremy Ashkenas
2f39102026 merging fix for #1124 2011-04-18 20:44:27 -04:00
Kit Goncharov
6793eb383c Fix a typo in browser.coffee. 2011-04-11 13:50:27 -06:00
Kit Goncharov
2caceda8c4 Enforce script execution order in browser.coffee. 2011-04-11 13:38:38 -06:00
Jeremy Ashkenas
238dc3a5b6 merging in #1268 ... michaelficarra's colored REPL. 2011-04-09 17:42:03 -07:00
Jeremy Ashkenas
390ff30690 Merge branch 'stable' 2011-04-09 17:39:55 -07:00
Jeremy Ashkenas
e1cf187cfe Merge branch 'bugfix-1157' of https://github.com/thejh/coffee-script into stable 2011-04-09 16:11:21 -07:00
Jeremy Ashkenas
8c01df7828 Merge branch 'stable' 2011-04-09 16:02:10 -07:00
Jeremy Ashkenas
ff8faa4cd7 Merge branch 'stable' of github.com:jashkenas/coffee-script into stable 2011-04-09 16:01:20 -07:00
Jeremy Ashkenas
b9aa64fd25 merging in Josh's patch for Node 0.4.x module lookup changes. 2011-04-09 16:00:57 -07:00
Jeremy Ashkenas
8dfd53620c Merge branch 'module-loading' of https://github.com/josh/coffee-script into stable 2011-04-09 16:00:17 -07:00
Michael Ficarra
0090aee0e5 full revert of 4ce374be25 2011-04-09 10:48:14 -04:00
Michael Ficarra
230dea1243 fixes #1274: {}=a() and []=a() compile to false instead of a() 2011-04-09 09:54:45 -04:00
Michael Ficarra
3453bfa513 regression tests for #1274 2011-04-09 09:53:04 -04:00
Michael Ficarra
d0f047dfe7 improved fix for #1266 2011-04-07 19:40:45 -04:00
Michael Ficarra
8e7c454de0 disabling colours for win32 and in presence of NODE_DISABLE_COLORS
environment variable
2011-04-05 20:51:28 -04:00
Michael Ficarra
68c75c7eb1 pretty node-like output in the REPL 2011-04-05 20:40:54 -04:00
Michael Ficarra
31ae260282 unnecessarily strict {in,}equality in existence checks 2011-03-29 17:25:09 -04:00
Jann Horn
8b443b94ea added a test 2011-03-28 23:16:49 +02:00
Jann Horn
6ec9c844e4 fixes #1124 (and uglifies generated JS) 2011-03-28 23:12:27 +02:00
Jeremy Ashkenas
3d3b03e1e4 Merge branch 'stable' of github.com:jashkenas/coffee-script into stable 2011-03-28 08:37:15 -04:00
Jeremy Ashkenas
4d194cb50c rebuilt parser with Jison 0.2.4 2011-03-28 08:36:42 -04:00
Michael Ficarra
b0d2bf4afe Merge branch 'improvedRangeCompilation' of github.com:michaelficarra/coffee-script into michaelficarra-improvedRangeCompilation 2011-03-28 00:51:42 -04:00
Michael Ficarra
8f73bc3b4c Merge branch 'bugfix-1108' of https://github.com/thejh/coffee-script into thejh-bugfix-1108 2011-03-27 23:54:46 -04:00
Michael Ficarra
90495b614f Merge branch 'thejh-bugfix-1099' into stable 2011-03-27 23:47:01 -04:00
Michael Ficarra
f03bcc24ad enhanced tests for #1099 fix 2011-03-27 23:42:49 -04:00
Jann Horn
6646155712 fixes #1157: when compiling multiple scripts, compile them if at least one of them isn't empty 2011-03-27 23:30:55 +02:00
Jann Horn
9d72208d9e added a test (issue #1099) 2011-03-27 21:35:29 +02:00
Jann Horn
e84e703211 fixes bug mentioned by @satyr in #1108
"[v] = a ? b" must compile to
v = (typeof a != "undefined" && a !== null ? a : b)[0];
and not to:
v = typeof a != "undefined" && a !== null ? a : b[0];
2011-03-27 21:22:09 +02:00
Jann Horn
0497c0742f fixes #1099: instead of nothing, compile to false
"if a in []"
2011-03-27 19:46:44 +02:00
Joshua Peek
573e2b0012 Assign module.paths for node_module loading 2011-03-25 15:36:48 -05:00
Michael Ficarra
c4b72fcc79 improved range compilation 2011-03-23 13:49:15 -04:00
Jeremy Ashkenas
a2d7716331 Adding CoffeeScript.mode 2011-03-20 17:40:20 -04:00
Will Moffat
67b5ebdb76 Bind not required for evalJS. 2011-03-19 16:03:53 -07:00
Will Moffat
4c2ce2b45b Merge branch 'master' of https://github.com/jashkenas/coffee-script into keyboard 2011-03-19 15:28:50 -07:00
Jeremy Ashkenas
3b2bade2f2 Use the newer Node.js binding for 'vm'. 2011-03-16 05:47:58 -05:00
Jeremy Ashkenas
cdeb28a793 missing space. 2011-03-16 05:45:17 -05:00
Jeremy Ashkenas
61918a1efa merging stable 2011-03-12 07:41:58 -06:00
Jeremy Ashkenas
963adb5230 merging jcoglan's splat declaration patch. 2011-03-12 07:41:14 -06:00
Jeremy Ashkenas
8f8a1ecf18 Merge branch 'master' of github.com:jashkenas/coffee-script 2011-03-12 07:38:34 -06:00
James Coglan
b9343b458f Fix scoping of splat parameters in argument lists. 2011-03-12 11:46:07 +00:00
Jeremy Ashkenas
ac85fa2fc3 merged stable 2011-03-11 22:44:18 -05:00
Jeremy Ashkenas
b7855857b5 stop trimming all trailing whitespace. 2011-03-11 22:39:32 -05:00
Jeremy Ashkenas
d957c4373b test-ified function_invocation 2011-03-11 22:18:22 -05:00
Jeremy Ashkenas
f485d8f548 test-ified control_flow 2011-03-11 22:09:33 -05:00
Jeremy Ashkenas
b994e235f3 test-ified comprehensions.coffee 2011-03-11 22:05:52 -05:00
Jeremy Ashkenas
2b1aea80ed testified compilation.coffee, removed empty command.coffee 2011-03-11 21:59:17 -05:00
Jeremy Ashkenas
53d8083343 removing empty test file for cake.coffee 2011-03-11 21:55:43 -05:00
Jeremy Ashkenas
d30c125ab7 continuing with the ol' refactorTests 2011-03-11 21:55:26 -05:00
Jeremy Ashkenas
9e2c75b548 removing over-hash-comment 2011-03-11 21:41:12 -05:00
Michael Ficarra
aa54b23713 fixes #1168: leading floating point suppresses newline (thanks, satyr) 2011-02-27 02:11:35 -05:00
Michael Ficarra
dc8e955c4f test for #1168 2011-02-27 02:11:12 -05:00
Timothy Jones
96b22a16eb Closes #1001. Throw cannot be directly used as an expression with parens, but can appear as a statement in an expression. 2011-02-23 15:50:28 +13:00
Timothy Jones
5fbbfbcbe3 Closes #1082. Puts back use of function calls in parameter lists. 2011-02-23 13:20:01 +13:00
Jeremy Ashkenas
faf98dacf6 stricter array splat tests. 2011-02-18 07:15:40 -05:00
Jeremy Ashkenas
86b47a528a adding an array splat test. 2011-02-17 21:56:28 -05:00
Jeremy Ashkenas
cf6c21a0d2 merging in aeosynth's tweaks to package.json 2011-02-17 21:21:31 -05:00
James Campos
b1d900210a add repository to package.json 2011-02-10 18:17:53 -08:00
James Campos
963fc4cebc add homepage to package.json 2011-02-10 17:54:00 -08:00
Will Moffat
80adaa700c Console keyboard shortcuts
Cmd/Ctrl-Enter to run code
Escape to dismiss console
2011-02-10 08:40:53 -08:00
Will Moffat
dfead460ca Disable spellcheck in the code editor.
Firefox highlights all the camelCase variable names in the examples and even WebKit highligts words like 'bitlist'.
2011-02-09 15:52:35 -08:00
Jeremy Ashkenas
6f21f8a402 merging stable 2011-02-01 22:02:57 -05:00
Trevor Burnham
abfc99308d Setting process.argv[1] to equal the filename of the script being run (issue 1087) 2011-02-01 21:41:20 -05:00
Jeremy Ashkenas
955c87ef30 Bumping version to 1.0.2-pre 2011-02-01 21:32:58 -05:00
Jeremy Ashkenas
b4df62bec1 #1085, adding CoffeeScript.mode to the docs. 2011-02-01 21:31:54 -05:00
Jeremy Ashkenas
14d2fa3895 #1085, adding CoffeeScript.mode to the docs. 2011-02-01 21:30:33 -05:00
Jeremy Ashkenas
005c5309c4 Merging in stable at 1.0.1 2011-01-31 23:34:34 -05:00
Jeremy Ashkenas
c44d9ae923 CoffeeScript 1.0.1 2011-01-31 22:39:12 -05:00
Jeremy Ashkenas
a487259e8e Backporting the REPL fix for Node 0.3.7 and Coffee 1.0-stable 2011-01-31 22:27:56 -05:00
Jeremy Ashkenas
37308e6760 Issue #1071, parenthesizing undefined literals when accessed. 2011-01-30 21:16:39 -05:00
Jeremy Ashkenas
4ce374be25 Issue #870 ... placeholders in destructuring assignment. 2011-01-30 20:49:02 -05:00
Jeremy Ashkenas
8b8e8a94ff Issue #997 ... Maloptimized break suppression. 2011-01-30 20:28:11 -05:00
Jeremy Ashkenas
3c9fdde24b resolved merge 2011-01-30 19:40:59 -05:00
Jeremy Ashkenas
578a46fbda Issue #875 -- console.log in the REPL 2011-01-30 19:32:07 -05:00
Jeremy Ashkenas
6fb2088d5f changed 'when' example. 2011-01-30 19:25:36 -05:00
Jeremy Ashkenas
49d9eb687d documenting 'when', a bit. 2011-01-30 17:10:50 -05:00
Jeremy Ashkenas
654c933e30 fixing version number to 1.1.0-pre ... to make it installable with npm. 2011-01-30 17:00:07 -05:00
Timothy Jones
83a86aacb5 Closes #1068. Don't know why CALL_START was in that file. 2011-01-24 19:57:31 +13:00
Timothy Jones
f231809e22 Swapping == with <, just in case. 2011-01-23 00:54:43 +13:00
Timothy Jones
2c8e0a6914 Merge branch 'readline0.3.6' of https://github.com/agnoster/coffee-script into agnoster 2011-01-23 00:43:18 +13:00
Isaac Wolkerstorfer
496816acff Add backwards compatibility for older readline
Check the readline.createInterface for arity. If it is 3,
assume the newer interface requiring separate stdin and stdout.
Otherwise, use the older calling style.
2011-01-22 12:30:22 +01:00
Isaac Wolkerstorfer
78b52f5716 Replace stdio with stdin/stdout pair for readline
On Node.js v0.3.6, the readline interface expects (in, out, complete).
This change makes the coffee-script repl conform to that expectation.
2011-01-22 11:40:25 +01:00
Timothy Jones
2ca108820f Closes #973. New is more careful around the do construct. 2011-01-22 23:26:38 +13:00
Timothy Jones
dc6bd715b2 Closes #970. Statements that use new are wrapped in parens to avoid the closure being used. 2011-01-22 23:12:39 +13:00
Timothy Jones
18a1e01d64 Closes #971. Existensial slices now supported. 2011-01-22 19:56:14 +13:00
Timothy Jones
15e1078d01 I suppose there's no reason to ever call a prototype like a function. 2011-01-22 19:34:30 +13:00
Timothy Jones
06b0c7e928 Closes #1064. Dot accesses force the next token to be an identifier. 2011-01-22 19:29:07 +13:00
Jeremy Ashkenas
3924c2f2bd First draft of fixing shorthand objects mixed with regulars within arrays. 2011-01-19 22:36:30 -05:00
Jeremy Ashkenas
7625d900d3 toTimeString -> toLocaleTimeString 2011-01-19 22:17:53 -05:00
Jeremy Ashkenas
53dc1f2055 Merging in donjones' implicit object fix, hooray. 2011-01-18 23:46:55 -05:00
Jeremy Ashkenas
e706fa4a58 Merge branch 'master' of https://github.com/donjones/coffee-script 2011-01-18 23:38:22 -05:00
Jeremy Ashkenas
65e81e4034 Merge branch '1.0-stable' 2011-01-18 23:29:44 -05:00
Jeremy Ashkenas
1f2f55bea3 merging in chetan51's Node 0.2.5 compatibility patch. Homebrew timestamps. 2011-01-18 23:28:37 -05:00
Jeremy Ashkenas
4b78790096 Making #1050 a syntax error. 2011-01-18 23:10:09 -05:00
Jonas Dohse
236e129e7a Tests for call parameters after implicit objects 2011-01-19 00:32:59 +01:00
Jonas Dohse
d200619774 Check for invalid implicit values 2011-01-18 23:31:50 +01:00
Chetan Surpur
f35ea486a7 Removed dependency on the util module in the coffee source files 2011-01-18 10:19:00 -08:00
Chetan Surpur
a48cd7cb1d Removed dependency on util to extend support to node v0.2.5 2011-01-18 09:45:58 -08:00
Jonas Dohse
d0f13223bc No assignment shortcut in implicit braces
Let

    f a: b, c

compile to

    f({
      a: b
    }, c);
2011-01-18 15:42:59 +01:00
Jeremy Ashkenas
7ae284f432 Allowing an environment variable of MINIFY=false to disable minification of the build:browser cake task. 2011-01-15 15:20:01 -05:00
Jeremy Ashkenas
df872b8223 Merge branch '1.0-stable' 2011-01-15 15:15:33 -05:00
Jeremy Ashkenas
150a8a12a0 A bit more explanation of what's actually going on with build:browser 2011-01-15 15:12:47 -05:00
Jeremy Ashkenas
d8823ed45e Implemented continuable lines in the REPL. Use a trailing slash. Multiline functions are now possible. 2011-01-15 15:06:51 -05:00
Jeremy Ashkenas
9a63b3147f First implementation of autocomplete. 2011-01-15 14:53:07 -05:00
Jeremy Ashkenas
3f586ff4ab Merge branch 'master' into 1.1-pre 2011-01-15 14:50:44 -05:00
Jeremy Ashkenas
c4d4cfe9dc Merge branch 'master' of https://github.com/ryszard/coffee-script into 1.1-pre 2011-01-15 14:50:41 -05:00
Jeremy Ashkenas
08cd112585 trailing comment. 2011-01-15 14:20:45 -05:00
Jeremy Ashkenas
566087b518 Expressions -> Block 2011-01-15 14:19:35 -05:00
Jeremy Ashkenas
f4a7cca075 Issue #1038 ... optimize away trailing return / and return undefined 2011-01-15 14:14:11 -05:00
Jeremy Ashkenas
d9d50fdf54 Leave out the 'Available Options' bit. 2011-01-15 11:04:50 -05:00
Jeremy Ashkenas
4c18ddf549 Fixing issue #1046. 2011-01-15 10:57:50 -05:00
Jeremy Ashkenas
7c7b9a4be1 Merging in 1035 fix. fileName -> filename ... a bit of refactoring. 2011-01-15 10:46:53 -05:00
Jeremy Ashkenas
9faedbf516 bump version to 1.1-pre 2011-01-15 10:28:26 -05:00
Trevor Burnham
ba45dedbd5 Decoupling --require flag processing from file compilation
This change allows files to be `--require`d before entering the REPL. It's also
an opimization, since files are `--require`d only once, rather than being
required again every time a file is compiled.

A secondary change is that `module.filename` is temporarily modified. This is
somewhat less aesthetically appealing than the old approach of using
fs.realpathSync, but it allows you to run `coffee -r ./foo` rather than having
to write `coffee -r ./foo.coffee`, since Node does not accept absolute paths
without a file extension.
2011-01-13 14:50:00 -05:00
Trevor Burnham
7815138386 Fixing require './foo' under --eval and REPL; issue 1035 2011-01-13 14:20:11 -05:00
Jeremy Ashkenas
47e4f4dae1 Merge branch 'issue1011' of http://github.com/michaelficarra/coffee-script 2011-01-10 23:25:28 -05:00
Jeremy Ashkenas
9b3197c6e8 #1026 2011-01-10 23:19:31 -05:00
Jeremy Ashkenas
44355f8eef Issue #1024. 2011-01-10 23:09:21 -05:00
Jeremy Ashkenas
45058dfa79 Adding jEdit highlighter. 2011-01-10 22:03:52 -05:00
Jeremy Ashkenas
83f9cb88cf Issue #1027 ... leading indentation. 2011-01-10 21:58:35 -05:00
Jeremy Ashkenas
c851ed9d60 Removing Roast (deleted) 2011-01-10 21:07:19 -05:00
Michael Ficarra
5f19f65ef2 obeying coffeescript convention of a single space after every comma 2011-01-07 03:20:48 -05:00
Michael Ficarra
8ca8cd046f mismatched issue number in test case for #1012 2011-01-06 23:55:50 -05:00
Michael Ficarra
6832dda2fa improving/minimizing the provided test cases for #1014 2011-01-06 23:47:03 -05:00
Gerald Lewis
782bc6c03a fix for issue 1014 - arguments object in ranged array - apply(this,arguments) instead of call(this) 2011-01-06 21:51:04 -05:00
Michael Ficarra
b158f1cbe6 fix for #1011 2011-01-06 12:38:54 -05:00
Michael Ficarra
944a114400 tests for #1011 2011-01-06 12:38:40 -05:00
Jeremy Ashkenas
5a7120e163 merging in refactorTests. 2011-01-05 21:52:53 -05:00
Michael Ficarra
1f58232e87 adding tests for trailing commas and semicolons 2011-01-03 12:20:35 -05:00
Michael Ficarra
0d3827989d removed global ?= window hack by actually giving tests a global
reference to global
2011-01-03 11:50:54 -05:00
Michael Ficarra
07ff3020cf Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2011-01-03 04:46:58 -05:00
Michael Ficarra
af4748d92b Fixing browser test suite for new filenames after reorganization.
Also added `global ?= window` where necessary. Firefox seems to be
complaining about an unexpected lambda still, though.
2011-01-03 04:37:29 -05:00
Michael Ficarra
240a0b9c93 made sure all files were properly commented 2011-01-03 04:28:47 -05:00
Michael Ficarra
6421c865f5 finished reorganizing test suite 2011-01-03 04:17:00 -05:00
Jeremy Ashkenas
06de5c7ffe joliss, vertical-align top 2011-01-02 21:43:53 -05:00
Michael Ficarra
ccae9ea6a8 final waypoint; remaining files to be sorted:
* _test_existence.coffee
  * _test_pattern_matching.coffee
2011-01-01 23:35:05 -05:00
Michael Ficarra
8692a5fd06 Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-30 22:52:16 -05:00
Michael Ficarra
dcbe62b9b9 test reorganization waypoint 3 2010-12-30 22:48:31 -05:00
Jeremy Ashkenas
9bed99482a Consistently using == instead of === in conjunction with typeof. 2010-12-30 21:15:50 -05:00
Michael Ficarra
fb201976b8 test reorganization waypoint #2 2010-12-29 14:06:57 -05:00
Ryszard Szopa
bb745a8036 Basic REPL autocomplete.
It sort of works, but the tests could are incomplete.
2010-12-29 12:59:23 +01:00
Michael Ficarra
a330eda4b6 Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-29 00:51:26 -05:00
Michael Ficarra
dcfdd144d8 test reorganization waypoint 2010-12-29 00:48:54 -05:00
Michael Ficarra
0fd3ed593c adding new (empty) classifications for tests 2010-12-28 23:33:13 -05:00
Jeremy Ashkenas
83d424f2f4 Issue #985. 2010-12-28 17:46:54 -08:00
Jeremy Ashkenas
c16c90c00a Issue #986 ... Unicode identifiers. 2010-12-28 17:42:20 -08:00
Michael Ficarra
8087a5914c coffee-script/test$ for file in .; do git mv "$file" "_$file"; done 2010-12-28 18:07:15 -05:00
Jeremy Ashkenas
03eccd4958 New favicon.ico 2010-12-27 10:12:42 -08:00
Jeremy Ashkenas
6d3f272551 ln -sfn ... part of Issue #971 2010-12-26 17:34:26 -08:00
Jeremy Ashkenas
7ffb7c19fd Issue #980 ... improperly truncated --help. 2010-12-26 17:15:55 -08:00
Jeremy Ashkenas
f545f18c2d Bumping to version 1.0.1-pre 2010-12-26 16:28:18 -08:00
92 changed files with 4745 additions and 3889 deletions

View File

@@ -16,7 +16,7 @@ header = """
* CoffeeScript Compiler v#{CoffeeScript.VERSION}
* http://coffeescript.org
*
* Copyright 2010, Jeremy Ashkenas
* Copyright 2011, Jeremy Ashkenas
* Released under the MIT License
*/
"""
@@ -50,10 +50,10 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
exec([
"mkdir -p #{lib} #{bin}"
"cp -rf bin lib LICENSE README package.json src #{lib}"
"ln -sf #{lib}/bin/coffee #{bin}/coffee"
"ln -sf #{lib}/bin/cake #{bin}/cake"
"ln -sfn #{lib}/bin/coffee #{bin}/coffee"
"ln -sfn #{lib}/bin/cake #{bin}/cake"
"mkdir -p ~/.node_libraries"
"ln -sf #{lib}/lib #{node}"
"ln -sfn #{lib}/lib #{node}"
].join(' && '), (err, stdout, stderr) ->
if err then console.log stderr.trim() else log 'done', green
)
@@ -94,16 +94,18 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
#{fs.readFileSync "lib/#{name}.js"}
};
"""
{parser, uglify} = require 'uglify-js'
ast = parser.parse """
code = """
this.CoffeeScript = function() {
function require(path){ return require[path]; }
#{code}
return require['./coffee-script']
}()
"""
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle ast, extra: yes
unless process.env.MINIFY is 'false'
{parser, uglify} = require 'uglify-js'
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
console.log "built ... running browser tests:"
invoke 'test:browser'
@@ -150,6 +152,9 @@ runTests = (CoffeeScript) ->
passedTests = 0
failures = []
# make "global" reference available to tests
global.global = global
# Mix in the assert module globally, to make it available for tests.
addGlobal = (name, func) ->
global[name] = ->
@@ -165,7 +170,8 @@ runTests = (CoffeeScript) ->
# Our test helper function for delimiting different test cases.
global.test = (description, fn) ->
try
fn()
fn.test = {description, currentFile}
fn.call(fn)
catch e
e.description = description if description?
e.source = fn.toString() if fn.toString?
@@ -198,6 +204,7 @@ runTests = (CoffeeScript) ->
{error, file} = fail
jsFile = file.replace(/\.coffee$/,'.js')
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
match = error.stack?.match(/on line (\d+):/) unless match
[match, line, col] = match if match
log "\n #{error.toString()}", red
log " #{error.description}", red if error.description
@@ -208,11 +215,11 @@ runTests = (CoffeeScript) ->
fs.readdir 'test', (err, files) ->
files.forEach (file) ->
return unless file.match(/\.coffee$/i)
fileName = path.join 'test', file
fs.readFile fileName, (err, code) ->
currentFile = fileName
filename = path.join 'test', file
fs.readFile filename, (err, code) ->
currentFile = filename
try
CoffeeScript.run code.toString(), {fileName}
CoffeeScript.run code.toString(), {filename}
catch e
failures.push file: currentFile, error: e

View File

@@ -1,4 +1,4 @@
Copyright (c) 2010 Jeremy Ashkenas
Copyright (c) 2011 Jeremy Ashkenas
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

3
README
View File

@@ -26,7 +26,8 @@
sudo bin/cake install
Or, if you have the Node Package Manager installed:
npm install coffee-script
npm install -g coffee-script
(Leave off the -g if you don't wish to install globally.)
Compile a script:
coffee /path/to/script.coffee

View File

@@ -1,5 +1,5 @@
###
CoffeeScript Compiler v1.0.0
CoffeeScript Compiler v1.1.0
Released under the MIT License
###

View File

@@ -1,4 +1,4 @@
for fileName in list
do (fileName) ->
fs.readFile fileName, (err, contents) ->
compile fileName, contents.toString()
for filename in list
do (filename) ->
fs.readFile filename, (err, contents) ->
compile filename, contents.toString()

View File

@@ -45,6 +45,7 @@ table {
}
td {
padding: 9px 15px 9px 0;
vertical-align: top;
}
table.definitions {
width: auto;

View File

@@ -2,21 +2,32 @@
<span class="nv">CoffeeScript.require = </span><span class="nx">require</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>Use standard JavaScript <code>eval</code> to eval code.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.eval = </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="nb">eval</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">options</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>Running code does not provide access to this scope.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.run = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">options = </span><span class="p">{})</span> <span class="o">-&gt;</span>
<span class="nv">options.bare = </span><span class="kc">on</span>
<span class="nb">Function</span><span class="p">(</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">options</span><span class="p">)()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>If we're not in a browser environment, we're finished with the public API.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">return</span> <span class="nx">unless</span> <span class="nb">window</span><span class="o">?</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Load a remote script from the current domain via XHR.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.load = </span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nb">Function</span><span class="p">(</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">options</span><span class="p">)()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>If we're not in a browser environment, we're finished with the public API.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">return</span> <span class="nx">unless</span> <span class="nb">window</span><span class="o">?</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Load a remote script from the current domain via XHR.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.load = </span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">xhr = </span><span class="k">new</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">ActiveXObject</span> <span class="o">or</span> <span class="nx">XMLHttpRequest</span><span class="p">)(</span><span class="s1">&#39;Microsoft.XMLHTTP&#39;</span><span class="p">)</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span> <span class="s1">&#39;GET&#39;</span><span class="p">,</span> <span class="nx">url</span><span class="p">,</span> <span class="kc">true</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">overrideMimeType</span> <span class="s1">&#39;text/plain&#39;</span> <span class="k">if</span> <span class="s1">&#39;overrideMimeType&#39;</span> <span class="k">of</span> <span class="nx">xhr</span>
<span class="nv">xhr.onreadystatechange = </span><span class="o">-&gt;</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span><span class="p">,</span> <span class="nx">options</span> <span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">is</span> <span class="mi">4</span>
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">is</span> <span class="mi">4</span>
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">status</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">]</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span>
<span class="k">else</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;Could not load #{url}&quot;</span>
<span class="nx">callback</span><span class="p">()</span> <span class="k">if</span> <span class="nx">callback</span>
<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span> <span class="kc">null</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</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.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">runScripts = </span><span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">script</span> <span class="k">in</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span> <span class="s1">&#39;script&#39;</span>
<span class="k">if</span> <span class="nx">script</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="nv">scripts = </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span> <span class="s1">&#39;script&#39;</span>
<span class="nv">coffees = </span><span class="p">(</span><span class="nx">s</span> <span class="k">for</span> <span class="nx">s</span> <span class="k">in</span> <span class="nx">scripts</span> <span class="k">when</span> <span class="nx">s</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="p">)</span>
<span class="nv">index = </span><span class="mi">0</span>
<span class="nv">length = </span><span class="nx">coffees</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">do</span> <span class="nv">execute = </span><span class="o">-&gt;</span>
<span class="nv">script = </span><span class="nx">coffees</span><span class="p">[</span><span class="nx">index</span><span class="o">++</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">script</span><span class="o">?</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="k">if</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">load</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">load</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span><span class="p">,</span> <span class="nx">execute</span>
<span class="k">else</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">script</span><span class="p">.</span><span class="nx">innerHTML</span>
<span class="nx">execute</span><span class="p">()</span>
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>Listen for window load, both in browsers and in IE.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span>
<span class="nx">addEventListener</span> <span class="s1">&#39;DOMContentLoaded&#39;</span><span class="p">,</span> <span class="nx">runScripts</span><span class="p">,</span> <span class="kc">no</span>
<span class="k">else</span>

View File

@@ -25,7 +25,7 @@ If no tasks are passed, print the help screen.</p> </td>
<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="nx">slice</span> <span class="mi">2</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="nx">toString</span><span class="p">(),</span> <span class="nx">fileName</span><span class="o">:</span> <span class="s1">&#39;Cakefile&#39;</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="nx">toString</span><span class="p">(),</span> <span class="nx">filename</span><span class="o">:</span> <span class="s1">&#39;Cakefile&#39;</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">printTasks</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>

View File

@@ -6,18 +6,19 @@ 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><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">vm = </span><span class="nx">require</span> <span class="s1">&#39;vm&#39;</span>
<span class="p">{</span><span class="nx">Lexer</span><span class="p">,</span><span class="nx">RESERVED</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;./lexer&#39;</span>
<span class="p">{</span><span class="nx">parser</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;./parser&#39;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>TODO: Remove registerExtension when fully deprecated.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
<span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span><span class="p">[</span><span class="s1">&#39;.coffee&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="nx">module</span><span class="p">,</span> <span class="nx">filename</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">content = </span><span class="nx">compile</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span> <span class="nx">filename</span><span class="p">,</span> <span class="s1">&#39;utf8&#39;</span>
<span class="nv">content = </span><span class="nx">compile</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="nx">filename</span><span class="p">,</span> <span class="s1">&#39;utf8&#39;</span><span class="p">),</span> <span class="p">{</span><span class="nx">filename</span><span class="p">}</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">filename</span>
<span class="k">else</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></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</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;1.0.0&#39;</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Words that cannot be used as identifiers in CoffeeScript code</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.RESERVED = </span><span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Expose helpers for testing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.helpers = </span><span class="nx">require</span> <span class="s1">&#39;./helpers&#39;</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
<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></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</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;1.1.0&#39;</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Words that cannot be used as identifiers in CoffeeScript code</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.RESERVED = </span><span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Expose helpers for testing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.helpers = </span><span class="nx">require</span> <span class="s1">&#39;./helpers&#39;</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</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="nv">options = </span><span class="p">{})</span> <span class="o">-&gt;</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.fileName}, #{err.message}&quot;</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span>
<span class="nv">err.message = </span><span class="s2">&quot;In #{options.filename}, #{err.message}&quot;</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span>
<span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</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="nx">options</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><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>Parse a string of CoffeeScript code or an array of lexed tokens, and
return the AST. You can then compile it by calling <code>.compile()</code> on the root,
@@ -28,14 +29,26 @@ or traverse it by using <code>.traverse()</code> with a callback.</p>
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">source</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</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></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>We want the root module.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root = </span><span class="nx">module</span>
<span class="k">while</span> <span class="nx">root</span><span class="p">.</span><span class="nx">parent</span>
<span class="nv">root = </span><span class="nx">root</span><span class="p">.</span><span class="nx">parent</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Set the filename.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.filename = </span><span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span> <span class="o">or</span> <span class="s1">&#39;.&#39;</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Clear the module cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.moduleCache = </span><span class="p">{}</span> <span class="k">if</span> <span class="nx">root</span><span class="p">.</span><span class="nx">moduleCache</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Compile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">root</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">&#39;.coffee&#39;</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
<span class="nv">root = </span><span class="nx">root</span><span class="p">.</span><span class="nx">parent</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Set the filename.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.filename = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span>
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;.&#39;</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Clear the module cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.moduleCache = </span><span class="p">{}</span> <span class="k">if</span> <span class="nx">root</span><span class="p">.</span><span class="nx">moduleCache</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Assign paths for node_modules loading</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">process</span><span class="p">.</span><span class="nx">binding</span><span class="p">(</span><span class="s1">&#39;natives&#39;</span><span class="p">).</span><span class="nx">module</span>
<span class="p">{</span><span class="nx">Module</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;module&#39;</span>
<span class="nv">root.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Compile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">root</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">&#39;.coffee&#39;</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">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="nx">root</span><span class="p">.</span><span class="nx">filename</span>
<span class="k">else</span>
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
The CoffeeScript REPL uses this to run the input.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.eval = </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">__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span>
<span class="nv">__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">__filename</span>
<span class="nb">eval</span> <span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</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></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
The CoffeeScript REPL uses this to run the input.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.eval = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">options = </span><span class="p">{})</span> <span class="o">-&gt;</span>
<span class="nv">sandbox = </span><span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
<span class="nx">unless</span> <span class="nx">sandbox</span>
<span class="nv">sandbox =</span>
<span class="nx">require</span><span class="o">:</span> <span class="nx">require</span>
<span class="nx">module</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">exports</span><span class="o">:</span> <span class="p">{}</span> <span class="p">}</span>
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">of</span> <span class="nx">global</span>
<span class="nv">sandbox.global = </span><span class="nx">sandbox</span>
<span class="nv">sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = </span><span class="nx">sandbox</span>
<span class="nv">sandbox.__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="s1">&#39;eval&#39;</span>
<span class="nv">sandbox.__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span>
<span class="nv">js = </span><span class="nx">compile</span> <span class="s2">&quot;_=(#{code.trim()})&quot;</span><span class="p">,</span> <span class="nx">options</span>
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInNewContext</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">sandbox</span><span class="p">,</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</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></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</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="nx">lex</span><span class="o">:</span> <span class="o">-&gt;</span>

View File

@@ -4,7 +4,6 @@ into various forms: saved into <code>.js</code> files or printed to stdout, pipe
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="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</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">util = </span><span class="nx">require</span> <span class="s1">&#39;util&#39;</span>
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s1">&#39;./helpers&#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>
@@ -18,7 +17,7 @@ interactive REPL.</p> </td> <td class="code">
<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;-j&#39;</span><span class="p">,</span> <span class="s1">&#39;--join&#39;</span><span class="p">,</span> <span class="s1">&#39;concatenate the scripts before compiling&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-j&#39;</span><span class="p">,</span> <span class="s1">&#39;--join [FILE]&#39;</span><span class="p">,</span> <span class="s1">&#39;concatenate the scripts before compiling&#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>
@@ -41,6 +40,7 @@ Many flags cause us to divert before compiling anything. Flags passed after
<span class="k">return</span> <span class="nx">forkNode</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span>
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</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">opts</span><span class="p">.</span><span class="nx">version</span>
<span class="nx">loadRequires</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">require</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">opts</span><span class="p">.</span><span class="nx">interactive</span>
<span class="k">return</span> <span class="nx">compileStdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">stdio</span>
<span class="k">return</span> <span class="nx">compileScript</span> <span class="kc">null</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">opts</span><span class="p">.</span><span class="nb">eval</span>
@@ -48,6 +48,8 @@ Many flags cause us to divert before compiling anything. Flags passed after
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">run</span>
<span class="nv">opts.literals = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
<span class="nv">process.ARGV = process.argv = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;coffee&#39;</span>
<span class="nv">process.execPath = </span><span class="nx">process</span><span class="p">.</span><span class="nx">mainModule</span><span class="p">.</span><span class="nx">filename</span>
<span class="nx">compileScripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
compile them. If a directory is passed, recursively compile all
'.coffee' extension source files in it and all subdirectories.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileScripts = </span><span class="o">-&gt;</span>
@@ -55,8 +57,9 @@ compile them. If a directory is passed, recursively compile all
<span class="nv">base = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span>
<span class="nv">compile = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">topLevel</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="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="k">if</span> <span class="nx">topLevel</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">exists</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</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">stats</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
<span class="k">if</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">isDirectory</span><span class="p">()</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">readdir</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">files</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span>
@@ -65,7 +68,7 @@ compile them. If a directory is passed, recursively compile all
<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="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
<span class="nx">contents</span><span class="p">[</span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">source</span><span class="p">]</span> <span class="o">=</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
<span class="nx">compileJoin</span><span class="p">()</span> <span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span><span class="p">(</span><span class="nx">contents</span><span class="p">).</span><span class="nx">length</span> <span class="o">is</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">compileJoin</span><span class="p">()</span> <span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span><span class="p">(</span><span class="nx">contents</span><span class="p">).</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="k">else</span>
<span class="nx">compileScript</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">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
@@ -74,8 +77,6 @@ requested options. 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">compileScript = </span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">o = </span><span class="nx">opts</span>
<span class="nv">options = </span><span class="nx">compileOptions</span> <span class="nx">file</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">require</span>
<span class="nx">require</span><span class="p">(</span><span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">starts</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="s1">&#39;.&#39;</span><span class="p">)</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="k">else</span> <span class="nx">req</span><span class="p">)</span> <span class="k">for</span> <span class="nx">req</span> <span class="k">in</span> <span class="nx">o</span><span class="p">.</span><span class="nx">require</span>
<span class="k">try</span>
<span class="nv">t = task = </span><span class="p">{</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">options</span><span class="p">}</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">&#39;compile&#39;</span><span class="p">,</span> <span class="nx">task</span>
@@ -103,14 +104,18 @@ and write them back to <strong>stdout</strong>.</p> </td>
<span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>After all of the source files are done being read, concatenate and compile
them together.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileJoin = </span><span class="o">-&gt;</span>
<span class="nv">code = </span><span class="nx">contents</span><span class="p">.</span><span class="nx">join</span> <span class="s1">&#39;\n&#39;</span>
<span class="nx">compileScript</span> <span class="s2">&quot;concatenation&quot;</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="s2">&quot;concatenation&quot;</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
<span class="nx">compileScript</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Load files that are to-be-required before compilation occurs.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">loadRequires = </span><span class="o">-&gt;</span>
<span class="nv">realFilename = </span><span class="nx">module</span><span class="p">.</span><span class="nx">filename</span>
<span class="nv">module.filename = </span><span class="s1">&#39;.&#39;</span>
<span class="nx">require</span> <span class="nx">req</span> <span class="k">for</span> <span class="nx">req</span> <span class="k">in</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">require</span>
<span class="nv">module.filename = </span><span class="nx">realFilename</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
time the file is 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 = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">base</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="nx">persistent</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">interval</span><span class="o">:</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">size</span> <span class="o">is</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">size</span> <span class="o">and</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="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
<span class="nx">compileScript</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">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
<span class="nx">compileScript</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">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</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">writeJs = </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="nx">base</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>
@@ -121,10 +126,12 @@ directory can be customized with <code>--output</code>.</p> </td>
<span class="nv">compile = </span><span class="o">-&gt;</span>
<span class="nv">js = </span><span class="s1">&#39; &#39;</span> <span class="k">if</span> <span class="nx">js</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;=</span> <span class="mi">0</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">err</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">util</span><span class="p">.</span><span class="nx">log</span> <span class="s2">&quot;compiled #{source}&quot;</span>
<span class="k">if</span> <span class="nx">err</span>
<span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">&quot;#{(new Date).toLocaleTimeString()} - compiled #{source}&quot;</span>
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">dir</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">if</span> <span class="nx">exists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s2">&quot;mkdir -p #{dir}&quot;</span><span class="p">,</span> <span class="nx">compile</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
<span class="k">if</span> <span class="nx">exists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s2">&quot;mkdir -p #{dir}&quot;</span><span class="p">,</span> <span class="nx">compile</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</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">file</span><span class="p">,</span> <span class="nx">js</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">printIt = </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">printLine</span> <span class="nx">file</span> <span class="o">+</span> <span class="s1">&#39;:\t&#39;</span> <span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span>
<span class="nv">conf = </span><span class="nx">__dirname</span> <span class="o">+</span> <span class="s1">&#39;/../extras/jsl.conf&#39;</span>
@@ -132,18 +139,18 @@ any errors or warnings that arise.</p> </td> <td class="
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">printIt</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">printIt</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</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">stdin</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTokens = </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTokens = </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">printLine</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-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
<span class="nx">printLine</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-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</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">parseOptions = </span><span class="o">-&gt;</span>
<span class="nv">optionParser = </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 = opts = </span><span class="nx">optionParser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">2</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or=</span> <span class="o">!!</span><span class="nx">o</span><span class="p">.</span><span class="nx">output</span>
<span class="nv">o.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">o.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">o</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</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">compileOptions = </span><span class="p">(</span><span class="nx">fileName</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nx">fileName</span><span class="p">,</span> <span class="nx">bare</span><span class="o">:</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
<span class="nv">sources = </span><span class="nx">o</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</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">compileOptions = </span><span class="p">(</span><span class="nx">filename</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="nx">filename</span><span class="p">,</span> <span class="nx">bare</span><span class="o">:</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
the <code>node</code> binary, preserving the other options.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">forkNode = </span><span class="o">-&gt;</span>
<span class="nv">nodeArgs = </span><span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span><span class="p">.</span><span class="nx">split</span> <span class="sr">/\s+/</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">1</span><span class="p">..]</span>
@@ -151,11 +158,9 @@ the <code>node</code> binary, preserving the other options.</p> </td
<span class="nx">spawn</span> <span class="nx">process</span><span class="p">.</span><span class="nx">execPath</span><span class="p">,</span> <span class="nx">nodeArgs</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">args</span><span class="p">),</span>
<span class="nx">cwd</span><span class="o">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
<span class="nx">env</span><span class="o">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span>
<span class="nx">customFds</span><span class="o">:</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="mi">2</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
<span class="nx">customFds</span><span class="o">:</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="mi">2</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
shown.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">usage = </span><span class="o">-&gt;</span>
<span class="nx">printLine</span> <span class="p">(</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="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-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</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">printLine</span> <span class="p">(</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="p">).</span><span class="nx">help</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</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">printLine</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

@@ -115,7 +115,7 @@ table td {
}
pre, tt, code {
font-size: 12px; line-height: 18px;
font-family: Monaco, Consolas, "Lucida Console", monospace;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}

View File

@@ -23,7 +23,7 @@ previous nonterminal.</p> </td> <td class="code">
<span class="k">return</span> <span class="p">[</span><span class="nx">patternString</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="nx">unwrap</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">action</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="nv">action = </span><span class="nx">action</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\bnew /g</span><span class="p">,</span> <span class="s1">&#39;$&amp;yy.&#39;</span>
<span class="nv">action = </span><span class="nx">action</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\b(?:Expressions\.wrap|extend)\b/g</span><span class="p">,</span> <span class="s1">&#39;yy.$&amp;&#39;</span>
<span class="nv">action = </span><span class="nx">action</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\b(?:Block\.wrap|extend)\b/g</span><span class="p">,</span> <span class="s1">&#39;yy.$&amp;&#39;</span>
<span class="p">[</span><span class="nx">patternString</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="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</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="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</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
@@ -36,14 +36,14 @@ their numeric position, so in this rule:</p>
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></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</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="nx">Root</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Expressions</span>
<span class="nx">o</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Block</span>
<span class="nx">o</span> <span class="s1">&#39;Body&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Block TERMINATOR&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>Any list of statements and expressions, separated by line breaks or semicolons.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Body</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Line&#39;</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="s1">&#39;Line&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">Block</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="s1">&#39;Body TERMINATOR Line&#39;</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="s1">&#39;Body TERMINATOR&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Expressions and statements, which make up a line in a body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Line</span><span class="o">:</span> <span class="p">[</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Block and statements, which make up a line in a body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Line</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Expression&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Statement&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Pure statements which cannot be expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Statement</span><span class="o">:</span> <span class="p">[</span>
@@ -53,7 +53,7 @@ all parsing must end here.</p> </td> <td class="code">
<span class="nx">o</span> <span class="s1">&#39;STATEMENT&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>All the different types of expressions in our language. The basic unit of
CoffeeScript is the <strong>Expression</strong> -- everything that can be an expression
is one. Expressions serve as the building blocks of many other rules, making
is one. Block serve as the building blocks of many other rules, making
them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Expression</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Value&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Invocation&#39;</span>
@@ -69,7 +69,7 @@ them somewhat circular.</p> </td> <td class="code">
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>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="nx">Block</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;INDENT OUTDENT&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Expressions</span>
<span class="nx">o</span> <span class="s1">&#39;INDENT OUTDENT&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Block</span>
<span class="nx">o</span> <span class="s1">&#39;INDENT Body OUTDENT&#39;</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-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>A literal identifier, a variable name or property.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Identifier</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
@@ -83,7 +83,9 @@ through and printed to JavaScript.</p> </td> <td class="
<span class="nx">o</span> <span class="s1">&#39;JS&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s1">&#39;BOOL&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
<span class="k">new</span> <span class="nx">Literal</span> <span class="k">if</span> <span class="nx">$1</span> <span class="o">is</span> <span class="s1">&#39;undefined&#39;</span> <span class="k">then</span> <span class="s1">&#39;void 0&#39;</span> <span class="k">else</span> <span class="nx">$1</span>
<span class="nv">val = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
<span class="nv">val.isUndefined = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">$1</span> <span class="o">is</span> <span class="s1">&#39;undefined&#39;</span>
<span class="nx">val</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Assignment of a variable, property, or index to a value.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Assign</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Assignable = Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s1">&#39;Assignable = INDENT Expression OUTDENT&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span>
@@ -106,7 +108,7 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>A block comment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Comment</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;HERECOMMENT&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Comment</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</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
of <strong>Block</strong> preceded by a function arrow, with an optional parameter
list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Code</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;PARAM_START ParamList PARAM_END FuncGlyph Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Code</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="s1">&#39;FuncGlyph Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Code</span> <span class="p">[],</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
@@ -158,11 +160,15 @@ or by array index or slice.</p> </td> <td class="code">
<span class="nx">o</span> <span class="s1">&#39;:: Identifier&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Access</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">&#39;proto&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;::&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;prototype&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Index&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Slice&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Slice</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">&#182;</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Index</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_START Expression INDEX_END&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Index</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_START IndexValue INDEX_END&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_SOAK Index&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">extend</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">soak</span> <span class="o">:</span> <span class="kc">yes</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_PROTO Index&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">extend</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">proto</span><span class="o">:</span> <span class="kc">yes</span>
<span class="p">]</span>
<span class="nx">IndexValue</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Index</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s1">&#39;Slice&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Slice</span> <span class="nx">$1</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">&#182;</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="s1">&#39;{ AssignList OptComma }&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Obj</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">generated</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">&#182;</a> </div> <p>Assignment of properties within an object literal can be separated by
@@ -207,9 +213,9 @@ and optional references to the superclass.</p> </td> <td
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">&#182;</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Range</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;[ Expression RangeDots Expression ]&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">&#182;</a> </div> <p>Array slice literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Slice</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_START Expression RangeDots Expression INDEX_END&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_START Expression RangeDots INDEX_END&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s1">&#39;INDEX_START RangeDots Expression INDEX_END&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;Expression RangeDots Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;Expression RangeDots&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;RangeDots Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Range</span> <span class="kc">null</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-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">&#182;</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="nx">ArgList</span><span class="o">:</span> <span class="p">[</span>
@@ -218,7 +224,7 @@ as well as the contents of an array literal
<span class="nx">o</span> <span class="s1">&#39;ArgList OptComma TERMINATOR Arg&#39;</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">$4</span>
<span class="nx">o</span> <span class="s1">&#39;INDENT ArgList OptComma OUTDENT&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;ArgList OptComma INDENT ArgList OptComma OUTDENT&#39;</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">$4</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">&#182;</a> </div> <p>Valid arguments are Expressions or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">&#182;</a> </div> <p>Valid arguments are Block or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Expression&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Splat&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">&#182;</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
@@ -249,14 +255,14 @@ the trick.</p> </td> <td class="code"> <di
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">&#182;</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="nx">While</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;WhileSource Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;Statement WhileSource&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">addBody</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="s1">&#39;Expression WhileSource&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">addBody</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="s1">&#39;Statement WhileSource&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">Block</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="s1">&#39;Expression WhileSource&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">Block</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="s1">&#39;Loop&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span>
<span class="p">]</span>
<span class="nx">Loop</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;LOOP Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;true&#39;</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;LOOP Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;true&#39;</span><span class="p">).</span><span class="nx">addBody</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="nx">o</span> <span class="s1">&#39;LOOP Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;true&#39;</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">Block</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-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">&#182;</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="nx">For</span><span class="o">:</span> <span class="p">[</span>
@@ -313,12 +319,12 @@ 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="nx">IfBlock</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;IF Expression Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$1</span>
<span class="nx">o</span> <span class="s1">&#39;IfBlock ELSE IF Expression Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s1">&#39;IfBlock ELSE Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">&#182;</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="nx">If</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;IfBlock&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Statement POST_IF Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">If</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="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s1">&#39;Expression POST_IF Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">If</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="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s1">&#39;IfBlock ELSE Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s1">&#39;Statement POST_IF Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Block</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">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s1">&#39;Expression POST_IF Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Block</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">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">&#182;</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

View File

@@ -19,6 +19,7 @@ it has consumed.</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="nx">tokenize</span><span class="o">:</span> <span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">opts = </span><span class="p">{})</span> <span class="o">-&gt;</span>
<span class="nv">code = </span><span class="s2">&quot;\n#{code}&quot;</span> <span class="k">if</span> <span class="nx">WHITESPACE</span><span class="p">.</span><span class="nx">test</span> <span class="nx">code</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="sr">/\r/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">replace</span> <span class="nx">TRAILING_SPACES</span><span class="p">,</span> <span class="s1">&#39;&#39;</span>
<span class="vi">@code = </span><span class="nx">code</span> <span class="c1"># The remainder of the source code.</span>
@@ -57,7 +58,8 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
<span class="nx">@token</span> <span class="s1">&#39;OWN&#39;</span><span class="p">,</span> <span class="nx">id</span>
<span class="k">return</span> <span class="nx">id</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">forcedIdentifier = </span><span class="nx">colon</span> <span class="o">or</span>
<span class="p">(</span><span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">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="k">in</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="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span><span class="p">)</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="k">in</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="o">or</span>
<span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">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;@&#39;</span><span class="p">)</span>
<span class="nv">tag = </span><span class="s1">&#39;IDENTIFIER&#39;</span>
<span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">JS_KEYWORDS</span> <span class="o">or</span>
@@ -90,7 +92,7 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
<span class="nx">@identifierError</span> <span class="nx">id</span>
<span class="nx">unless</span> <span class="nx">forcedIdentifier</span>
<span class="nv">id = </span><span class="nx">COFFEE_ALIASES</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">hasOwnProperty</span> <span class="nx">id</span>
<span class="nv">id = </span><span class="nx">COFFEE_ALIAS_MAP</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">COFFEE_ALIASES</span>
<span class="nv">tag = </span><span class="k">switch</span> <span class="nx">id</span>
<span class="k">when</span> <span class="s1">&#39;!&#39;</span> <span class="k">then</span> <span class="s1">&#39;UNARY&#39;</span>
<span class="k">when</span> <span class="s1">&#39;==&#39;</span><span class="p">,</span> <span class="s1">&#39;!=&#39;</span> <span class="k">then</span> <span class="s1">&#39;COMPARE&#39;</span>
@@ -135,11 +137,11 @@ preserve whitespace, but ignore indentation to the left.</p> </td>
<span class="nx">heredoc</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Matches and consumes comments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">commentToken</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="mi">0</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="nx">COMMENT</span>
<span class="p">[</span><span class="nx">comment</span><span class="p">,</span> <span class="nx">here</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span>
<span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">comment</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span>
<span class="k">if</span> <span class="nx">here</span>
<span class="nx">@token</span> <span class="s1">&#39;HERECOMMENT&#39;</span><span class="p">,</span> <span class="nx">@sanitizeHeredoc</span> <span class="nx">here</span><span class="p">,</span>
<span class="nx">herecomment</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">indent</span><span class="o">:</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">@indent</span> <span class="o">+</span> <span class="mi">1</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="nx">@token</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span>
<span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">comment</span><span class="p">,</span> <span class="s1">&#39;\n&#39;</span>
<span class="nx">comment</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">jsToken</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</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="nv">match = </span><span class="nx">JSTOKEN</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span>
<span class="nx">@token</span> <span class="s1">&#39;JS&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nv">script = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="nx">slice</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span>
@@ -276,8 +278,11 @@ parentheses that indicate a method call from regular parentheses, and so on.</p>
<span class="nx">value</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">&#182;</a> </div> <h2>Token Manipulators</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>Sanitize a heredoc or herecomment by
erasing all external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">sanitizeHeredoc</span><span class="o">:</span> <span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">{</span><span class="nx">indent</span><span class="p">,</span> <span class="nx">herecomment</span><span class="p">}</span> <span class="o">=</span> <span class="nx">options</span>
<span class="k">return</span> <span class="nx">doc</span> <span class="k">if</span> <span class="nx">herecomment</span> <span class="o">and</span> <span class="mi">0</span> <span class="o">&gt;</span> <span class="nx">doc</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;\n&#39;</span>
<span class="nx">unless</span> <span class="nx">herecomment</span>
<span class="k">if</span> <span class="nx">herecomment</span>
<span class="k">if</span> <span class="nx">HEREDOC_ILLEGAL</span><span class="p">.</span><span class="nx">test</span> <span class="nx">doc</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">&quot;block comment cannot contain \&quot;*/\&quot;, starting on line #{@line + 1}&quot;</span>
<span class="k">return</span> <span class="nx">doc</span> <span class="k">if</span> <span class="nx">doc</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">&lt;=</span> <span class="mi">0</span>
<span class="k">else</span>
<span class="k">while</span> <span class="nv">match = </span><span class="nx">HEREDOC_INDENT</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">doc</span>
<span class="nv">attempt = </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nv">indent = </span><span class="nx">attempt</span> <span class="k">if</span> <span class="nx">indent</span> <span class="o">is</span> <span class="kc">null</span> <span class="o">or</span> <span class="mi">0</span> <span class="o">&lt;</span> <span class="nx">attempt</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
@@ -297,7 +302,7 @@ parameters specially in order to make things easier for the parser.</p>
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nx">tok</span>
<span class="k">when</span> <span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="s1">&#39;CALL_START&#39;</span>
<span class="k">if</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="k">then</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="k">else</span>
<span class="k">else</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="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="k">return</span> <span class="k">this</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</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="nx">closeIndentation</span><span class="o">:</span> <span class="o">-&gt;</span>
@@ -354,10 +359,11 @@ token stream.</p> </td> <td class="code">
<span class="nv">nested = </span><span class="k">new</span> <span class="nx">Lexer</span><span class="p">().</span><span class="nx">tokenize</span> <span class="nx">inner</span><span class="p">,</span> <span class="nx">line</span><span class="o">:</span> <span class="nx">@line</span><span class="p">,</span> <span class="nx">rewrite</span><span class="o">:</span> <span class="kc">off</span>
<span class="nx">nested</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nx">nested</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span> <span class="k">if</span> <span class="nx">nested</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">?</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="k">if</span> <span class="nx">nested</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span>
<span class="nx">nested</span><span class="p">.</span><span class="nx">unshift</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">nested</span><span class="p">.</span><span class="nx">push</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;TOKENS&#39;</span><span class="p">,</span> <span class="nx">nested</span><span class="p">]</span>
<span class="k">if</span> <span class="nv">len = </span><span class="nx">nested</span><span class="p">.</span><span class="nx">length</span>
<span class="k">if</span> <span class="nx">len</span> <span class="o">&gt;</span> <span class="mi">1</span>
<span class="nx">nested</span><span class="p">.</span><span class="nx">unshift</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">nested</span><span class="p">.</span><span class="nx">push</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;TOKENS&#39;</span><span class="p">,</span> <span class="nx">nested</span><span class="p">]</span>
<span class="nx">i</span> <span class="o">+=</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">pi = </span><span class="nx">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;NEOSTRING&#39;</span><span class="p">,</span> <span class="nx">str</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">pi</span><span class="p">]</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">&gt;</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>
@@ -392,7 +398,8 @@ token stream.</p> </td> <td class="code">
<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;switch&#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;do&#39;</span><span class="p">,</span> <span class="s1">&#39;try&#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="s1">&#39;class&#39;</span><span class="p">,</span> <span class="s1">&#39;extends&#39;</span><span class="p">,</span> <span class="s1">&#39;super&#39;</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">&#182;</a> </div> <p>CoffeeScript-only keywords.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">COFFEE_KEYWORDS = </span><span class="p">[</span><span class="s1">&#39;undefined&#39;</span><span class="p">,</span> <span class="s1">&#39;then&#39;</span><span class="p">,</span> <span class="s1">&#39;unless&#39;</span><span class="p">,</span> <span class="s1">&#39;until&#39;</span><span class="p">,</span> <span class="s1">&#39;loop&#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;when&#39;</span><span class="p">]</span>
<span class="nx">COFFEE_KEYWORDS</span><span class="p">.</span><span class="nx">push</span> <span class="nx">op</span> <span class="k">for</span> <span class="nx">op</span> <span class="k">of</span> <span class="nv">COFFEE_ALIASES =</span>
<span class="nv">COFFEE_ALIAS_MAP =</span>
<span class="o">and</span> <span class="o">:</span> <span class="s1">&#39;&amp;&amp;&#39;</span>
<span class="o">or</span> <span class="o">:</span> <span class="s1">&#39;||&#39;</span>
<span class="o">is</span> <span class="o">:</span> <span class="s1">&#39;==&#39;</span>
@@ -401,7 +408,10 @@ token stream.</p> </td> <td class="code">
<span class="kc">yes</span> <span class="o">:</span> <span class="s1">&#39;true&#39;</span>
<span class="kc">no</span> <span class="o">:</span> <span class="s1">&#39;false&#39;</span>
<span class="kc">on</span> <span class="o">:</span> <span class="s1">&#39;true&#39;</span>
<span class="kc">off</span> <span class="o">:</span> <span class="s1">&#39;false&#39;</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">&#182;</a> </div> <p>The list of keywords that are reserved by JavaScript, but not used, or are
<span class="kc">off</span> <span class="o">:</span> <span class="s1">&#39;false&#39;</span>
<span class="nv">COFFEE_ALIASES = </span><span class="p">(</span><span class="nx">key</span> <span class="k">for</span> <span class="nx">key</span> <span class="k">of</span> <span class="nx">COFFEE_ALIAS_MAP</span><span class="p">)</span>
<span class="nv">COFFEE_KEYWORDS = </span><span class="nx">COFFEE_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">COFFEE_ALIASES</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">&#182;</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="s1">&#39;case&#39;</span><span class="p">,</span> <span class="s1">&#39;default&#39;</span><span class="p">,</span> <span class="s1">&#39;function&#39;</span><span class="p">,</span> <span class="s1">&#39;var&#39;</span><span class="p">,</span> <span class="s1">&#39;void&#39;</span><span class="p">,</span> <span class="s1">&#39;with&#39;</span>
@@ -411,7 +421,7 @@ to avoid having a JavaScript error at runtime.</p> </td>
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>
<span class="nv">exports.RESERVED = </span><span class="nx">RESERVED</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">JS_KEYWORDS</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">COFFEE_KEYWORDS</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">&#182;</a> </div> <p>Token matching regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER = </span><span class="err">/// ^</span>
<span class="p">(</span> <span class="p">[</span><span class="nx">$A</span><span class="o">-</span><span class="nx">Za</span><span class="o">-</span><span class="nx">z_</span><span class="p">][</span><span class="nx">$</span><span class="err">\</span><span class="nx">w</span><span class="p">]</span><span class="o">*</span> <span class="p">)</span>
<span class="p">(</span> <span class="p">[</span><span class="nx">$A</span><span class="o">-</span><span class="nx">Za</span><span class="o">-</span><span class="nx">z_</span><span class="err">\</span><span class="nx">x7f</span><span class="o">-</span><span class="err">\</span><span class="nx">uffff</span><span class="p">][</span><span class="nx">$</span><span class="err">\</span><span class="nx">w</span><span class="err">\</span><span class="nx">x7f</span><span class="o">-</span><span class="err">\</span><span class="nx">uffff</span><span class="p">]</span><span class="o">*</span> <span class="p">)</span>
<span class="p">(</span> <span class="p">[</span><span class="o">^</span><span class="err">\</span><span class="nx">n</span><span class="err">\</span><span class="nx">S</span><span class="p">]</span><span class="o">*</span> <span class="o">:</span> <span class="p">(</span><span class="o">?!:</span><span class="p">)</span> <span class="p">)</span><span class="o">?</span> <span class="c1"># Is this a property name?</span>
<span class="err">///</span>
@@ -443,7 +453,7 @@ be used as identifiers or properties.</p> </td> <td clas
<span class="nv">SIMPLESTR = </span><span class="sr">/^&#39;[^\\&#39;]*(?:\\.[^\\&#39;]*)*&#39;/</span>
<span class="nv">JSTOKEN = </span><span class="sr">/^`[^\\`]*(?:\\.[^\\`]*)*`/</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">&#182;</a> </div> <p>Regex-matching-regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REGEX = </span><span class="err">/// ^</span>
<span class="o">/</span> <span class="p">(</span><span class="o">?!</span> <span class="err">\</span><span class="nx">s</span> <span class="p">)</span> <span class="c1"># disallow leading whitespace</span>
<span class="o">/</span> <span class="p">(</span><span class="o">?!</span> <span class="p">[</span><span class="err">\</span><span class="nx">s</span><span class="o">=</span><span class="p">]</span> <span class="p">)</span> <span class="c1"># disallow leading whitespace or equals signs</span>
<span class="p">[</span><span class="o">^</span> <span class="p">[</span> <span class="err">/ \n \\ ]* # every other thing</span>
<span class="p">(</span><span class="o">?:</span>
<span class="p">(</span><span class="o">?:</span> <span class="err">\\</span><span class="p">[</span><span class="err">\</span><span class="nx">s</span><span class="err">\</span><span class="nx">S</span><span class="p">]</span> <span class="c1"># anything escaped</span>
@@ -462,9 +472,11 @@ be used as identifiers or properties.</p> </td> <td clas
<span class="nv">HEREDOC_INDENT = </span><span class="sr">/\n+([^\n\S]*)/g</span>
<span class="nv">ASSIGNED = </span><span class="sr">/^\s*@?([$A-Za-z_][$\w]*|[&#39;&quot;].*[&#39;&quot;])[^\n\S]*?[:=][^:=&gt;]/</span>
<span class="nv">HEREDOC_ILLEGAL = </span><span class="sr">/\*\//</span>
<span class="nv">LINE_CONTINUER = </span><span class="err">/// ^ \s* (?: , | \??\.(?!\.) | :: ) ///</span>
<span class="nv">ASSIGNED = </span><span class="sr">/^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|[&#39;&quot;].*[&#39;&quot;])[^\n\S]*?[:=][^:=&gt;]/</span>
<span class="nv">LINE_CONTINUER = </span><span class="err">/// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///</span>
<span class="nv">TRAILING_SPACES = </span><span class="sr">/\s+$/</span>

View File

@@ -29,7 +29,7 @@ return results).</p> </td> <td class="code">
<span class="k">else</span>
<span class="nx">node</span><span class="p">.</span><span class="nx">compileClosure</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</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="nx">compileClosure</span><span class="o">:</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">@jumps</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">@jumps</span><span class="p">()</span> <span class="o">or</span> <span class="k">this</span> <span class="k">instanceof</span> <span class="nx">Throw</span>
<span class="k">throw</span> <span class="nx">SyntaxError</span> <span class="s1">&#39;cannot use a pure statement in an expression.&#39;</span>
<span class="nv">o.sharedScope = </span><span class="kc">yes</span>
<span class="nx">Closure</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">compileNode</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>If the code generation wishes to use the result of a complex expression
@@ -94,9 +94,9 @@ will override these with custom logic, if needed.</p> </td>
<span class="nx">isAssignable</span> <span class="o">:</span> <span class="nx">NO</span>
<span class="nx">unwrap</span> <span class="o">:</span> <span class="nx">THIS</span>
<span class="nx">unfoldSoak</span> <span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Is this node used to assign a certain variable?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assigns</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</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="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>The expressions body is the list of expressions that forms the body of an
<span class="nx">unfoldSoak</span> <span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Is this node used to assign a certain variable?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assigns</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <h3>Block</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>The block 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">Base</span>
<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.Block = </span><span class="nx">class</span> <span class="nx">Block</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">nodes</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@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>
@@ -105,7 +105,7 @@ indented block of code -- the implementation of a function, a clause in an
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>Remove and return the last expression of this expression list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">pop</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>Add an expression at the beginning of this expression list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unshift</span><span class="o">:</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="nx">node</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>If this Expressions consists of just a single node, unwrap it by pulling
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>If this Block consists of just a single node, unwrap it by pulling
it back out.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unwrap</span><span class="o">:</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-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>Is this an empty block of code?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">isEmpty</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="o">not</span> <span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span>
@@ -117,16 +117,17 @@ it back out.</p> </td> <td class="code"> <
<span class="nx">jumps</span><span class="o">:</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">exp</span> <span class="k">in</span> <span class="nx">@expressions</span>
<span class="k">return</span> <span class="nx">exp</span> <span class="k">if</span> <span class="nx">exp</span><span class="p">.</span><span class="nx">jumps</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>An Expressions node does not return its entire body, rather it
<span class="k">return</span> <span class="nx">exp</span> <span class="k">if</span> <span class="nx">exp</span><span class="p">.</span><span class="nx">jumps</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>An Block 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="nx">makeReturn</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nv">len = </span><span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span>
<span class="k">while</span> <span class="nx">len</span><span class="o">--</span>
<span class="nv">expr = </span><span class="nx">@expressions</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">expr</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Comment</span>
<span class="nx">@expressions</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="o">=</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()</span>
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">len</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Return</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">expression</span>
<span class="k">break</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</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="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nv">o = </span><span class="p">{},</span> <span class="nx">level</span><span class="p">)</span> <span class="o">-&gt;</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="nx">o</span><span class="p">,</span> <span class="nx">level</span> <span class="k">else</span> <span class="nx">@compileRoot</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Compile all expressions within the <strong>Expressions</strong> body. If we need to
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>An <strong>Block</strong> is the only node that can serve as the root.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nv">o = </span><span class="p">{},</span> <span class="nx">level</span><span class="p">)</span> <span class="o">-&gt;</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="nx">o</span><span class="p">,</span> <span class="nx">level</span> <span class="k">else</span> <span class="nx">@compileRoot</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Compile all expressions within the <strong>Block</strong> 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="nx">compileNode</span><span class="o">:</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>
@@ -143,7 +144,7 @@ statement, ask the statement to do so.</p> </td> <td cla
<span class="nx">codes</span><span class="p">.</span><span class="nx">push</span> <span class="nx">node</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
<span class="k">return</span> <span class="nx">codes</span><span class="p">.</span><span class="nx">join</span> <span class="s1">&#39;\n&#39;</span> <span class="k">if</span> <span class="nx">top</span>
<span class="nv">code = </span><span class="nx">codes</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="o">or</span> <span class="s1">&#39;void 0&#39;</span>
<span class="k">if</span> <span class="nx">codes</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>If we happen to be the top-level <strong>Expressions</strong>, wrap everything in
<span class="k">if</span> <span class="nx">codes</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>If we happen to be the top-level <strong>Block</strong>, wrap everything in
a safety closure, unless requested not to.
It would be better not to generate them in the first place, but for now,
clean up obvious double-parentheses.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileRoot</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -151,7 +152,6 @@ clean up obvious double-parentheses.</p> </td> <td class
<span class="nv">o.scope = </span><span class="k">new</span> <span class="nx">Scope</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="nv">o.level = </span><span class="nx">LEVEL_TOP</span>
<span class="nv">code = </span><span class="nx">@compileWithDeclarations</span> <span class="nx">o</span>
<span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">TRAILING_WHITESPACE</span><span class="p">,</span> <span class="s1">&#39;&#39;</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">bare</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">&quot;(function() {\n#{code}\n}).call(this);\n&quot;</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">&#182;</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="nx">compileWithDeclarations</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">code = post = </span><span class="s1">&#39;&#39;</span>
@@ -166,14 +166,14 @@ declarations of all inner variables pushed up to the top.</p> </td>
<span class="nv">post = </span><span class="nx">@compileNode</span> <span class="nx">o</span>
<span class="p">{</span><span class="nx">scope</span><span class="p">}</span> <span class="o">=</span> <span class="nx">o</span>
<span class="k">if</span> <span class="nx">scope</span><span class="p">.</span><span class="nx">expressions</span> <span class="o">is</span> <span class="k">this</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">o</span><span class="p">.</span><span class="nx">globals</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">hasDeclarations</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="p">.</span><span class="nx">hasDeclarations</span><span class="p">()</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="s2">&quot;#{@tab}var #{ scope.declaredVariables().join(&#39;, &#39;) };\n&quot;</span>
<span class="k">if</span> <span class="nx">scope</span><span class="p">.</span><span class="nx">hasAssignments</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="s2">&quot;#{@tab}var #{ multident scope.assignedVariables().join(&#39;, &#39;), @tab };\n&quot;</span>
<span class="nx">code</span> <span class="o">+</span> <span class="nx">post</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>Wrap up the given nodes as an <strong>Expressions</strong>, unless it already happens
<span class="nx">code</span> <span class="o">+</span> <span class="nx">post</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>Wrap up the given nodes as an <strong>Block</strong>, unless it already happens
to be one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">@wrap</span><span class="o">:</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="nx">nodes</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">&#182;</a> </div> <h3>Literal</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">&#182;</a> </div> <p>Literals are static values that can be passed through directly into
<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">Block</span>
<span class="k">new</span> <span class="nx">Block</span> <span class="nx">nodes</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">&#182;</a> </div> <h3>Literal</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">&#182;</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.Literal = </span><span class="nx">class</span> <span class="nx">Literal</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@value</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -197,13 +197,19 @@ JavaScript without translation, such as: strings, numbers,
<span class="k">if</span> <span class="o">not</span> <span class="p">(</span><span class="nx">o</span> <span class="o">and</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">loop</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">block</span> <span class="o">and</span> <span class="p">(</span><span class="nx">@value</span> <span class="o">isnt</span> <span class="s1">&#39;continue&#39;</span><span class="p">)))</span> <span class="k">then</span> <span class="k">this</span> <span class="k">else</span> <span class="kc">no</span>
<span class="nx">compileNode</span><span class="o">:</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="k">if</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">reserved</span> <span class="k">then</span> <span class="s2">&quot;\&quot;#{@value}\&quot;&quot;</span> <span class="k">else</span> <span class="nx">@value</span>
<span class="nv">code = </span><span class="k">if</span> <span class="nx">@isUndefined</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_ACCESS</span> <span class="k">then</span> <span class="s1">&#39;(void 0)&#39;</span> <span class="k">else</span> <span class="s1">&#39;void 0&#39;</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">reserved</span>
<span class="s2">&quot;\&quot;#{@value}\&quot;&quot;</span>
<span class="k">else</span>
<span class="nx">@value</span>
<span class="k">if</span> <span class="nx">@isStatement</span><span class="p">()</span> <span class="k">then</span> <span class="s2">&quot;#{@tab}#{code};&quot;</span> <span class="k">else</span> <span class="nx">code</span>
<span class="nx">toString</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="s1">&#39; &quot;&#39;</span> <span class="o">+</span> <span class="nx">@value</span> <span class="o">+</span> <span class="s1">&#39;&quot;&#39;</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">&#182;</a> </div> <h3>Return</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">&#182;</a> </div> <p>A <code>return</code> is a <em>pureStatement</em> -- wrapping it in a closure wouldn't
make sense.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Return = </span><span class="nx">class</span> <span class="nx">Return</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@expression</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">expr</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@expression = </span><span class="nx">expr</span> <span class="k">if</span> <span class="nx">expr</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">().</span><span class="nx">isUndefined</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;expression&#39;</span><span class="p">]</span>
@@ -278,19 +284,22 @@ evaluate anything twice when building the soak chain.</p> </td>
<span class="nv">code = </span><span class="s2">&quot;(#{code})&quot;</span> <span class="k">if</span> <span class="nx">props</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">instanceof</span> <span class="nx">Access</span> <span class="o">and</span> <span class="nx">@isSimpleNumber</span><span class="p">()</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span> <span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">props</span>
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">&#182;</a> </div> <p>Unfold a soak into an <code>If</code>: <code>a?.b</code> -> <code>a.b if a?</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unfoldSoak</span><span class="o">:</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="nv">ifn = </span><span class="nx">@base</span><span class="p">.</span><span class="nx">unfoldSoak</span> <span class="nx">o</span>
<span class="nb">Array</span><span class="o">::</span><span class="nx">push</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">ifn</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">properties</span><span class="p">,</span> <span class="nx">@properties</span>
<span class="k">return</span> <span class="nx">ifn</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="k">when</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">soak</span>
<span class="nv">prop.soak = </span><span class="kc">off</span>
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">i</span>
<span class="nv">snd = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span>
<span class="k">if</span> <span class="nx">fst</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
<span class="nv">ref = </span><span class="k">new</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">freeVariable</span> <span class="s1">&#39;ref&#39;</span>
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">fst</span>
<span class="nv">snd.base = </span><span class="nx">ref</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">If</span> <span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">),</span> <span class="nx">snd</span><span class="p">,</span> <span class="nx">soak</span><span class="o">:</span> <span class="kc">on</span>
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">&#182;</a> </div> <h3>Comment</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">&#182;</a> </div> <p>CoffeeScript passes through block comments as JavaScript block comments
<span class="k">return</span> <span class="nx">@unfoldedSoak</span> <span class="k">if</span> <span class="nx">@unfoldedSoak</span><span class="o">?</span>
<span class="nv">result = </span><span class="nx">do</span> <span class="o">=&gt;</span>
<span class="k">if</span> <span class="nv">ifn = </span><span class="nx">@base</span><span class="p">.</span><span class="nx">unfoldSoak</span> <span class="nx">o</span>
<span class="nb">Array</span><span class="o">::</span><span class="nx">push</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">ifn</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">properties</span><span class="p">,</span> <span class="nx">@properties</span>
<span class="k">return</span> <span class="nx">ifn</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="k">when</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">soak</span>
<span class="nv">prop.soak = </span><span class="kc">off</span>
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">i</span>
<span class="nv">snd = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span>
<span class="k">if</span> <span class="nx">fst</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
<span class="nv">ref = </span><span class="k">new</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">freeVariable</span> <span class="s1">&#39;ref&#39;</span>
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">fst</span>
<span class="nv">snd.base = </span><span class="nx">ref</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">If</span> <span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">),</span> <span class="nx">snd</span><span class="p">,</span> <span class="nx">soak</span><span class="o">:</span> <span class="kc">on</span>
<span class="kc">null</span>
<span class="vi">@unfoldedSoak = </span><span class="nx">result</span> <span class="o">or</span> <span class="kc">no</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">&#182;</a> </div> <h3>Comment</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">&#182;</a> </div> <p>CoffeeScript passes through block comments as JavaScript block comments
at the same position.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Comment = </span><span class="nx">class</span> <span class="nx">Comment</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@comment</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -351,17 +360,33 @@ method.</p> </td> <td class="code"> <div c
<span class="k">else</span>
<span class="nv">call.variable.base = </span><span class="nx">ifn</span>
<span class="nv">ifn = </span><span class="nx">unfoldSoak</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">call</span><span class="p">,</span> <span class="s1">&#39;variable&#39;</span>
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">&#182;</a> </div> <p>Compile a vanilla function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">&#182;</a> </div> <p>Walk through the objects in the arguments, moving over simple values.
This allows syntax like <code>call a: b, c</code> into <code>call({a: b}, c);</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">filterImplicitObjects</span><span class="o">:</span> <span class="p">(</span><span class="nx">list</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">nodes = </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">list</span>
<span class="nx">unless</span> <span class="nx">node</span><span class="p">.</span><span class="nx">isObject</span><span class="o">?</span><span class="p">()</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">generated</span>
<span class="nx">nodes</span><span class="p">.</span><span class="nx">push</span> <span class="nx">node</span>
<span class="k">continue</span>
<span class="nv">obj = </span><span class="kc">null</span>
<span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">node</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">properties</span>
<span class="k">if</span> <span class="nx">prop</span> <span class="k">instanceof</span> <span class="nx">Assign</span>
<span class="nx">nodes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">obj = </span><span class="k">new</span> <span class="nx">Obj</span> <span class="nv">properties = </span><span class="p">[],</span> <span class="kc">true</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">obj</span>
<span class="nx">properties</span><span class="p">.</span><span class="nx">push</span> <span class="nx">prop</span>
<span class="k">else</span>
<span class="nx">nodes</span><span class="p">.</span><span class="nx">push</span> <span class="nx">prop</span>
<span class="nv">obj = </span><span class="kc">null</span>
<span class="nx">nodes</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">&#182;</a> </div> <p>Compile a vanilla function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@variable</span><span class="o">?</span><span class="p">.</span><span class="nv">front = </span><span class="nx">@front</span>
<span class="k">if</span> <span class="nv">code = </span><span class="nx">Splat</span><span class="p">.</span><span class="nx">compileSplattedArray</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">@args</span><span class="p">,</span> <span class="kc">true</span>
<span class="k">return</span> <span class="nx">@compileSplat</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">code</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="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</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="s1">&#39;, &#39;</span>
<span class="nv">args = </span><span class="nx">@filterImplicitObjects</span> <span class="nx">@args</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="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</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="s1">&#39;, &#39;</span>
<span class="k">if</span> <span class="nx">@isSuper</span>
<span class="nx">@superReference</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;.call(this#{ args and &#39;, &#39; + args })&quot;</span>
<span class="k">else</span>
<span class="p">(</span><span class="k">if</span> <span class="nx">@isNew</span> <span class="k">then</span> <span class="s1">&#39;new &#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="o">+</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="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;(#{args})&quot;</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">&#182;</a> </div> <p><code>super()</code> is converted into a call against the superclass's implementation
<span class="p">(</span><span class="k">if</span> <span class="nx">@isNew</span> <span class="k">then</span> <span class="s1">&#39;new &#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="o">+</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="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;(#{args})&quot;</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">&#182;</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="nx">compileSuper</span><span class="o">:</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="s2">&quot;#{@superReference(o)}.call(this#{ if args.length then &#39;, &#39; else &#39;&#39; }#{args})&quot;</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">&#182;</a> </div> <p>If you call a function with a splat, it's converted into a JavaScript
<span class="s2">&quot;#{@superReference(o)}.call(this#{ if args.length then &#39;, &#39; else &#39;&#39; }#{args})&quot;</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">&#182;</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.
If it's a constructor, then things get real tricky. We have to inject an
inner constructor in order to be able to pass the varargs.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSplat</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">splatArgs</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -369,11 +394,11 @@ inner constructor in order to be able to pass the varargs.</p> </td>
<span class="k">if</span> <span class="nx">@isNew</span>
<span class="nv">idt = </span><span class="nx">@tab</span> <span class="o">+</span> <span class="nx">TAB</span>
<span class="k">return</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> (function(func, args, ctor) {</span>
<span class="s2"> #{idt}ctor.prototype = func.prototype;</span>
<span class="s2"> #{idt}var child = new ctor, result = func.apply(child, args);</span>
<span class="s2"> #{idt}return typeof result === &quot;</span><span class="nx">object</span><span class="s2">&quot; ? result : child;</span>
<span class="s2"> #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})</span>
<span class="s2"> (function(func, args, ctor) {</span>
<span class="s2"> #{idt}ctor.prototype = func.prototype;</span>
<span class="s2"> #{idt}var child = new ctor, result = func.apply(child, args);</span>
<span class="s2"> #{idt}return typeof result === &quot;</span><span class="nx">object</span><span class="s2">&quot; ? result : child;</span>
<span class="s2"> #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})</span>
<span class="s2"> &quot;&quot;&quot;</span>
<span class="nv">base = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@variable</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">name = </span><span class="nx">base</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">pop</span><span class="p">())</span> <span class="o">and</span> <span class="nx">base</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
@@ -381,19 +406,20 @@ inner constructor in order to be able to pass the varargs.</p> </td>
<span class="nv">fun = </span><span class="s2">&quot;(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }&quot;</span>
<span class="k">else</span>
<span class="nv">fun = </span><span class="nx">base</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_ACCESS</span>
<span class="nv">fun = </span><span class="s2">&quot;(#{fun})&quot;</span> <span class="k">if</span> <span class="nx">SIMPLENUM</span><span class="p">.</span><span class="nx">test</span> <span class="nx">fun</span>
<span class="k">if</span> <span class="nx">name</span>
<span class="nv">ref = </span><span class="nx">fun</span>
<span class="nx">fun</span> <span class="o">+=</span> <span class="nx">name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="k">else</span>
<span class="nv">ref = </span><span class="s1">&#39;null&#39;</span>
<span class="s2">&quot;#{fun}.apply(#{ref}, #{splatArgs})&quot;</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">&#182;</a> </div> <h3>Extends</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">&#182;</a> </div> <p>Node to extend an object's prototype with an ancestor object.
<span class="s2">&quot;#{fun}.apply(#{ref}, #{splatArgs})&quot;</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">&#182;</a> </div> <h3>Extends</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">&#182;</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/closureGoogBase.js.html">Closure Library</a>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Extends = </span><span class="nx">class</span> <span class="nx">Extends</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;child&#39;</span><span class="p">,</span> <span class="s1">&#39;parent&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">&#182;</a> </div> <p>Hooks one constructor into another's prototype chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</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="s1">&#39;child&#39;</span><span class="p">,</span> <span class="s1">&#39;parent&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">&#182;</a> </div> <p>Hooks one constructor into another's prototype chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</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;hasProp&#39;</span>
<span class="k">new</span> <span class="nx">Call</span><span class="p">(</span><span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">utility</span> <span class="s1">&#39;extends&#39;</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-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">&#182;</a> </div> <h3>Access</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">&#182;</a> </div> <p>A <code>.</code> access into a property of a value, or the <code>::</code> shorthand for
<span class="k">new</span> <span class="nx">Call</span><span class="p">(</span><span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">utility</span> <span class="s1">&#39;extends&#39;</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="pilwrap"> <a class="pilcrow" href="#section-57">&#182;</a> </div> <h3>Access</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">&#182;</a> </div> <p>A <code>.</code> access into a property of a value, or the <code>::</code> shorthand for
an access into the object's prototype.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Access = </span><span class="nx">class</span> <span class="nx">Access</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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">@name.asKey = </span><span class="kc">yes</span>
@@ -406,7 +432,7 @@ an access into the object's prototype.</p> </td> <td cla
<span class="nv">name = </span><span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nx">@proto</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">IS_STRING</span><span class="p">.</span><span class="nx">test</span> <span class="nx">name</span> <span class="k">then</span> <span class="s2">&quot;[#{name}]&quot;</span> <span class="k">else</span> <span class="s2">&quot;.#{name}&quot;</span>
<span class="nx">isComplex</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">&#182;</a> </div> <h3>Index</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">&#182;</a> </div> <p>A <code>[ ... ]</code> indexed access into an array or object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Index = </span><span class="nx">class</span> <span class="nx">Index</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">isComplex</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">&#182;</a> </div> <h3>Index</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">&#182;</a> </div> <p>A <code>[ ... ]</code> indexed access into an array or object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Index = </span><span class="nx">class</span> <span class="nx">Index</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@index</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="s1">&#39;index&#39;</span><span class="p">]</span>
@@ -415,7 +441,7 @@ an access into the object's prototype.</p> </td> <td cla
<span class="p">(</span><span class="k">if</span> <span class="nx">@proto</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="p">)</span> <span class="o">+</span> <span class="s2">&quot;[#{ @index.compile o, LEVEL_PAREN }]&quot;</span>
<span class="nx">isComplex</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@index</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">&#182;</a> </div> <h3>Range</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">&#182;</a> </div> <p>A range literal. Ranges can be used to extract portions (slices) of arrays,
<span class="nx">@index</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">&#182;</a> </div> <h3>Range</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">&#182;</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.Range = </span><span class="nx">class</span> <span class="nx">Range</span> <span class="k">extends</span> <span class="nx">Base</span>
@@ -423,7 +449,7 @@ corresponding array of integers at runtime.</p> </td> <t
<span class="nx">constructor</span><span class="o">:</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">tag</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@exclusive = </span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;exclusive&#39;</span>
<span class="vi">@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></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">&#182;</a> </div> <p>Compiles the range's source variables -- where it starts and where it ends.
<span class="vi">@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></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">&#182;</a> </div> <p>Compiles the range's source variables -- where it starts and where it ends.
But only if they need to be cached to avoid double evaluation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileVariables</span><span class="o">:</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="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">top</span><span class="o">:</span> <span class="kc">true</span><span class="p">)</span>
<span class="p">[</span><span class="nx">@from</span><span class="p">,</span> <span class="nx">@fromVar</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@from</span><span class="p">.</span><span class="nx">cache</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
@@ -431,7 +457,7 @@ But only if they need to be cached to avoid double evaluation.</p> <
<span class="p">[</span><span class="nx">@fromNum</span><span class="p">,</span> <span class="nx">@toNum</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">@fromVar</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLENUM</span><span class="p">),</span> <span class="nx">@toVar</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLENUM</span><span class="p">)]</span>
<span class="nv">parts = </span><span class="p">[]</span>
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@from</span> <span class="k">if</span> <span class="nx">@from</span> <span class="o">isnt</span> <span class="nx">@fromVar</span>
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@to</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">&#182;</a> </div> <p>When compiled normally, the range returns the contents of the <em>for loop</em>
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@to</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">&#182;</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="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@compileVariables</span> <span class="nx">o</span>
<span class="k">return</span> <span class="nx">@compileArray</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>
@@ -439,11 +465,10 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
<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}&quot;</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span> <span class="k">then</span> <span class="s2">&quot;, #{@to}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">intro = </span><span class="s2">&quot;(#{@fromVar} &lt;= #{@toVar} ? #{idx}&quot;</span>
<span class="nv">compare = </span><span class="s2">&quot;#{intro} &lt;#{@equals} #{@toVar} : #{idx} &gt;#{@equals} #{@toVar})&quot;</span>
<span class="nv">stepPart = </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">incr = </span><span class="k">if</span> <span class="nx">step</span> <span class="k">then</span> <span class="s2">&quot;#{idx} += #{stepPart}&quot;</span> <span class="k">else</span> <span class="s2">&quot;#{intro} += #{stepPart} : #{idx} -= #{stepPart})&quot;</span>
<span class="s2">&quot;#{vars}; #{compare}; #{incr}&quot;</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">&#182;</a> </div> <p>Compile a simple range comprehension, with integers.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSimple</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">cond = </span><span class="s2">&quot;#{@fromVar} &lt;= #{@toVar}&quot;</span>
<span class="nv">compare = </span><span class="s2">&quot;#{cond} ? #{idx} &lt;#{@equals} #{@toVar} : #{idx} &gt;#{@equals} #{@toVar}&quot;</span>
<span class="nv">incr = </span><span class="k">if</span> <span class="nx">step</span> <span class="k">then</span> <span class="s2">&quot;#{idx} += #{step.compile(o)}&quot;</span> <span class="k">else</span> <span class="s2">&quot;#{cond} ? #{idx}++ : #{idx}--&quot;</span>
<span class="s2">&quot;#{vars}; #{compare}; #{incr}&quot;</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">&#182;</a> </div> <p>Compile a simple range comprehension, with integers.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSimple</span><span class="o">:</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">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="o">+</span><span class="nx">@fromNum</span><span class="p">,</span> <span class="o">+</span><span class="nx">@toNum</span><span class="p">]</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>
@@ -451,7 +476,7 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
<span class="k">if</span> <span class="nx">from</span> <span class="o">&lt;=</span> <span class="nx">to</span>
<span class="s2">&quot;#{idx} = #{from}; #{idx} &lt;#{@equals} #{to}; #{step or &quot;</span><span class="c1">#{idx}++&quot;}&quot;</span>
<span class="k">else</span>
<span class="s2">&quot;#{idx} = #{from}; #{idx} &gt;#{@equals} #{to}; #{step or &quot;</span><span class="c1">#{idx}--&quot;}&quot;</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">&#182;</a> </div> <p>When used as a value, expand the range into the equivalent array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileArray</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="s2">&quot;#{idx} = #{from}; #{idx} &gt;#{@equals} #{to}; #{step or &quot;</span><span class="c1">#{idx}--&quot;}&quot;</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">&#182;</a> </div> <p>When used as a value, expand the range into the equivalent array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileArray</span><span class="o">:</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">@fromNum</span> <span class="o">and</span> <span class="nx">@toNum</span> <span class="o">and</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">@fromNum</span> <span class="o">-</span> <span class="nx">@toNum</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">20</span>
<span class="nv">range = </span><span class="p">[</span><span class="o">+</span><span class="nx">@fromNum</span><span class="p">..</span><span class="o">+</span><span class="nx">@toNum</span><span class="p">]</span>
<span class="nx">range</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@exclusive</span>
@@ -462,20 +487,20 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
<span class="nv">pre = </span><span class="s2">&quot;\n#{idt}#{result} = [];&quot;</span>
<span class="k">if</span> <span class="nx">@fromNum</span> <span class="o">and</span> <span class="nx">@toNum</span>
<span class="nv">o.index = </span><span class="nx">i</span>
<span class="nv">body = </span><span class="nx">@compileSimple</span> <span class="nx">o</span>
<span class="nv">body = </span><span class="nx">@compileSimple</span> <span class="nx">o</span>
<span class="k">else</span>
<span class="nv">vars = </span><span class="s2">&quot;#{i} = #{@from}&quot;</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span> <span class="k">then</span> <span class="s2">&quot;, #{@to}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">clause = </span><span class="s2">&quot;#{@fromVar} &lt;= #{@toVar} ?&quot;</span>
<span class="nv">body = </span><span class="s2">&quot;var #{vars}; #{clause} #{i} &lt;#{@equals} #{@toVar} : #{i} &gt;#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1&quot;</span>
<span class="nv">vars = </span><span class="s2">&quot;#{i} = #{@from}&quot;</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span> <span class="k">then</span> <span class="s2">&quot;, #{@to}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">cond = </span><span class="s2">&quot;#{@fromVar} &lt;= #{@toVar}&quot;</span>
<span class="nv">body = </span><span class="s2">&quot;var #{vars}; #{cond} ? #{i} &lt;#{@equals} #{@toVar} : #{i} &gt;#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--&quot;</span>
<span class="nv">post = </span><span class="s2">&quot;{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}&quot;</span>
<span class="s2">&quot;(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)&quot;</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">&#182;</a> </div> <h3>Slice</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">&#182;</a> </div> <p>An array slice literal. Unlike JavaScript's <code>Array#slice</code>, the second parameter
<span class="s2">&quot;(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this, arguments)&quot;</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">&#182;</a> </div> <h3>Slice</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-68">&#182;</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.Slice = </span><span class="nx">class</span> <span class="nx">Slice</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;range&#39;</span><span class="p">]</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@range</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">super</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-68">&#182;</a> </div> <p>We have to be careful when trying to slice through the end of the array,
<span class="k">super</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-69">&#182;</a> </div> <p>We have to be careful when trying to slice through the end of the array,
<code>9e9</code> is used because not all implementations respect <code>undefined</code> or <code>1/0</code>.
<code>9e9</code> should be safe because <code>9e9</code> > <code>2**32</code>, the max array length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</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">to</span><span class="p">,</span> <span class="nx">from</span><span class="p">}</span> <span class="o">=</span> <span class="nx">@range</span>
@@ -488,7 +513,7 @@ is the index of the beginning.</p> </td> <td class="code
<span class="p">(</span><span class="o">+</span><span class="nx">compiled</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">toString</span><span class="p">()</span>
<span class="k">else</span>
<span class="s2">&quot;(#{compiled} + 1) || 9e9&quot;</span>
<span class="s2">&quot;.slice(#{ fromStr }#{ toStr or &#39;&#39; })&quot;</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-69">&#182;</a> </div> <h3>Obj</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-70">&#182;</a> </div> <p>An object literal, nothing fancy.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Obj = </span><span class="nx">class</span> <span class="nx">Obj</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="s2">&quot;.slice(#{ fromStr }#{ toStr or &#39;&#39; })&quot;</span></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-70">&#182;</a> </div> <h3>Obj</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-71">&#182;</a> </div> <p>An object literal, nothing fancy.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Obj = </span><span class="nx">class</span> <span class="nx">Obj</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">props</span><span class="p">,</span> <span class="vi">@generated = </span><span class="kc">false</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@objects = @properties = </span><span class="nx">props</span> <span class="o">or</span> <span class="p">[]</span>
@@ -497,6 +522,9 @@ is the index of the beginning.</p> </td> <td class="code
<span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">props = </span><span class="nx">@properties</span>
<span class="k">return</span> <span class="p">(</span><span class="k">if</span> <span class="nx">@front</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="p">)</span> <span class="nx">unless</span> <span class="nx">props</span><span class="p">.</span><span class="nx">length</span>
<span class="k">if</span> <span class="nx">@generated</span>
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">props</span> <span class="k">when</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Value</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s1">&#39;cannot have an implicit value in an implicit object&#39;</span>
<span class="nv">idt = </span><span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
<span class="nv">lastNoncom = </span><span class="nx">@lastNonComment</span> <span class="nx">@properties</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">props</span>
@@ -520,17 +548,20 @@ is the index of the beginning.</p> </td> <td class="code
<span class="nx">assigns</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</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="nx">prop</span><span class="p">.</span><span class="nx">assigns</span> <span class="nx">name</span> <span class="k">then</span> <span class="k">return</span> <span class="kc">yes</span>
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-71">&#182;</a> </div> <h3>Arr</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-72">&#182;</a> </div> <p>An array literal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Arr = </span><span class="nx">class</span> <span class="nx">Arr</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-72">&#182;</a> </div> <h3>Arr</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-73">&#182;</a> </div> <p>An array literal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Arr = </span><span class="nx">class</span> <span class="nx">Arr</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">objs</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@objects = </span><span class="nx">objs</span> <span class="o">or</span> <span class="p">[]</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;objects&#39;</span><span class="p">]</span>
<span class="nx">filterImplicitObjects</span><span class="o">:</span> <span class="nx">Call</span><span class="o">::</span><span class="nx">filterImplicitObjects</span>
<span class="nx">compileNode</span><span class="o">:</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="s1">&#39;[]&#39;</span> <span class="nx">unless</span> <span class="nx">@objects</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
<span class="k">return</span> <span class="nx">code</span> <span class="k">if</span> <span class="nv">code = </span><span class="nx">Splat</span><span class="p">.</span><span class="nx">compileSplattedArray</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">@objects</span>
<span class="nv">code = </span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">obj</span> <span class="k">in</span> <span class="nx">@objects</span><span class="p">).</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</span>
<span class="nv">objs = </span><span class="nx">@filterImplicitObjects</span> <span class="nx">@objects</span>
<span class="k">return</span> <span class="nx">code</span> <span class="k">if</span> <span class="nv">code = </span><span class="nx">Splat</span><span class="p">.</span><span class="nx">compileSplattedArray</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">objs</span>
<span class="nv">code = </span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">obj</span> <span class="k">in</span> <span class="nx">objs</span><span class="p">).</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</span>
<span class="k">if</span> <span class="nx">code</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="s2">&quot;[\n#{o.indent}#{code}\n#{@tab}]&quot;</span>
<span class="k">else</span>
@@ -538,20 +569,20 @@ is the index of the beginning.</p> </td> <td class="code
<span class="nx">assigns</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">obj</span> <span class="k">in</span> <span class="nx">@objects</span> <span class="k">when</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">assigns</span> <span class="nx">name</span> <span class="k">then</span> <span class="k">return</span> <span class="kc">yes</span>
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-73">&#182;</a> </div> <h3>Class</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-74"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-74">&#182;</a> </div> <p>The CoffeeScript class definition.
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-74"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-74">&#182;</a> </div> <h3>Class</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-75"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-75">&#182;</a> </div> <p>The CoffeeScript class definition.
Initialize a <strong>Class</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">exports.Class = </span><span class="nx">class</span> <span class="nx">Class</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="vi">@body = </span><span class="k">new</span> <span class="nx">Expressions</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">constructor</span><span class="o">:</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="vi">@body = </span><span class="k">new</span> <span class="nx">Block</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@boundFuncs = </span><span class="p">[]</span>
<span class="vi">@body.classBody = </span><span class="kc">yes</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;variable&#39;</span><span class="p">,</span> <span class="s1">&#39;parent&#39;</span><span class="p">,</span> <span class="s1">&#39;body&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-75"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-75">&#182;</a> </div> <p>Figure out the appropriate name for the constructor function of this class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">determineName</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;variable&#39;</span><span class="p">,</span> <span class="s1">&#39;parent&#39;</span><span class="p">,</span> <span class="s1">&#39;body&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-76"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-76">&#182;</a> </div> <p>Figure out the appropriate name for the constructor function of this class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">determineName</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">null</span> <span class="nx">unless</span> <span class="nx">@variable</span>
<span class="nv">decl = </span><span class="k">if</span> <span class="nv">tail = </span><span class="nx">last</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">properties</span>
<span class="nx">tail</span> <span class="k">instanceof</span> <span class="nx">Access</span> <span class="o">and</span> <span class="nx">tail</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">value</span>
<span class="k">else</span>
<span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">value</span>
<span class="nx">decl</span> <span class="o">and=</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">decl</span><span class="p">)</span> <span class="o">and</span> <span class="nx">decl</span></pre></div> </td> </tr> <tr id="section-76"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-76">&#182;</a> </div> <p>For all <code>this</code>-references and bound functions in the class definition,
<span class="nx">decl</span> <span class="o">and=</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">decl</span><span class="p">)</span> <span class="o">and</span> <span class="nx">decl</span></pre></div> </td> </tr> <tr id="section-77"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-77">&#182;</a> </div> <p>For all <code>this</code>-references and bound functions in the class definition,
<code>this</code> is the Class being constructed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">setContext</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@body</span><span class="p">.</span><span class="nx">traverseChildren</span> <span class="kc">false</span><span class="p">,</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">classBody</span>
@@ -559,12 +590,12 @@ list of prototype property assignments.</p> </td> <td cl
<span class="nv">node.value = </span><span class="nx">name</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Code</span>
<span class="nv">node.klass = </span><span class="nx">name</span>
<span class="nv">node.context = </span><span class="nx">name</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span></pre></div> </td> </tr> <tr id="section-77"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-77">&#182;</a> </div> <p>Ensure that all functions bound to the instance are proxied in the
<span class="nv">node.context = </span><span class="nx">name</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span></pre></div> </td> </tr> <tr id="section-78"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-78">&#182;</a> </div> <p>Ensure that all functions bound to the instance are proxied in the
constructor.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addBoundFunctions</span><span class="o">:</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">@boundFuncs</span><span class="p">.</span><span class="nx">length</span>
<span class="k">for</span> <span class="nx">bvar</span> <span class="k">in</span> <span class="nx">@boundFuncs</span>
<span class="nv">bname = </span><span class="nx">bvar</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nx">@ctor</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s2">&quot;this.#{bname} = #{utility &#39;bind&#39;}(this.#{bname}, this);&quot;</span></pre></div> </td> </tr> <tr id="section-78"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-78">&#182;</a> </div> <p>Merge the properties from a top-level object as prototypal properties
<span class="nx">@ctor</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s2">&quot;this.#{bname} = #{utility &#39;bind&#39;}(this.#{bname}, this);&quot;</span></pre></div> </td> </tr> <tr id="section-79"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-79">&#182;</a> </div> <p>Merge the properties from a top-level object as prototypal properties
on the class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addProperties</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">props = </span><span class="nx">node</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="nx">slice</span> <span class="mi">0</span>
<span class="k">while</span> <span class="nv">assign = </span><span class="nx">props</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span>
@@ -587,14 +618,14 @@ on the class.</p> </td> <td class="code">
<span class="k">if</span> <span class="nx">func</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">func</span><span class="p">.</span><span class="nx">bound</span>
<span class="nx">@boundFuncs</span><span class="p">.</span><span class="nx">push</span> <span class="nx">base</span>
<span class="nv">func.bound = </span><span class="kc">no</span>
<span class="nx">assign</span></pre></div> </td> </tr> <tr id="section-79"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-79">&#182;</a> </div> <p>Walk the body of the class, looking for prototype properties to be converted.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">walkBody</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">assign</span></pre></div> </td> </tr> <tr id="section-80"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-80">&#182;</a> </div> <p>Walk the body of the class, looking for prototype properties to be converted.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">walkBody</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@traverseChildren</span> <span class="kc">false</span><span class="p">,</span> <span class="p">(</span><span class="nx">child</span><span class="p">)</span> <span class="o">=&gt;</span>
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">child</span> <span class="k">instanceof</span> <span class="nx">Class</span>
<span class="k">if</span> <span class="nx">child</span> <span class="k">instanceof</span> <span class="nx">Expressions</span>
<span class="k">if</span> <span class="nx">child</span> <span class="k">instanceof</span> <span class="nx">Block</span>
<span class="k">for</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nv">exps = </span><span class="nx">child</span><span class="p">.</span><span class="nx">expressions</span>
<span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Value</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">isObject</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
<span class="nx">exps</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@addProperties</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">name</span>
<span class="nv">child.expressions = exps = </span><span class="nx">flatten</span> <span class="nx">exps</span></pre></div> </td> </tr> <tr id="section-80"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-80">&#182;</a> </div> <p>Make sure that a constructor is defined for the class, and properly
<span class="nv">child.expressions = exps = </span><span class="nx">flatten</span> <span class="nx">exps</span></pre></div> </td> </tr> <tr id="section-81"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-81">&#182;</a> </div> <p>Make sure that a constructor is defined for the class, and properly
configured.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ensureConstructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">@ctor</span>
<span class="vi">@ctor = </span><span class="k">new</span> <span class="nx">Code</span>
@@ -602,7 +633,7 @@ configured.</p> </td> <td class="code"> <d
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="nx">@ctor</span>
<span class="vi">@ctor.ctor = @ctor.name = </span><span class="nx">name</span>
<span class="vi">@ctor.klass = </span><span class="kc">null</span>
<span class="vi">@ctor.noReturn = </span><span class="kc">yes</span></pre></div> </td> </tr> <tr id="section-81"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-81">&#182;</a> </div> <p>Instead of generating the JavaScript string directly, we build up the
<span class="vi">@ctor.noReturn = </span><span class="kc">yes</span></pre></div> </td> </tr> <tr id="section-82"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-82">&#182;</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="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">decl = </span><span class="nx">@determineName</span><span class="p">()</span>
@@ -611,17 +642,17 @@ constructor, property assignments, and inheritance getting built out below.</p>
<span class="nx">@setContext</span> <span class="nx">name</span>
<span class="nx">@walkBody</span> <span class="nx">name</span>
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Extends</span> <span class="nx">lname</span><span class="p">,</span> <span class="nx">@parent</span> <span class="k">if</span> <span class="nx">@parent</span>
<span class="nx">@ensureConstructor</span> <span class="nx">name</span>
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">splice</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Extends</span><span class="p">(</span><span class="nx">lname</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@parent</span>
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">push</span> <span class="nx">lname</span>
<span class="nx">@addBoundFunctions</span> <span class="nx">o</span>
<span class="nv">klass = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">Closure</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="nv">klass = </span><span class="k">new</span> <span class="nx">Assign</span> <span class="nx">@variable</span><span class="p">,</span> <span class="nx">klass</span> <span class="k">if</span> <span class="nx">@variable</span>
<span class="nx">klass</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-82"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-82">&#182;</a> </div> <h3>Assign</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-83"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-83">&#182;</a> </div> <p>The <strong>Assign</strong> is used to assign a local variable to value, or to set the
<span class="nx">klass</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-83"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-83">&#182;</a> </div> <h3>Assign</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-84"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-84">&#182;</a> </div> <p>The <strong>Assign</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.Assign = </span><span class="nx">class</span> <span class="nx">Assign</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@param = </span><span class="nx">options</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">param</span></pre></div> </td> </tr> <tr id="section-84"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-84">&#182;</a> </div> <p>Matchers for detecting class/method names</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">METHOD_DEF</span><span class="o">:</span> <span class="sr">/^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/</span>
<span class="vi">@param = </span><span class="nx">options</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">param</span></pre></div> </td> </tr> <tr id="section-85"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-85">&#182;</a> </div> <p>Matchers for detecting class/method names</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">METHOD_DEF</span><span class="o">:</span> <span class="sr">/^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w\x7f-\uffff]*)$/</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;variable&#39;</span><span class="p">,</span> <span class="s1">&#39;value&#39;</span><span class="p">]</span>
@@ -629,7 +660,7 @@ property of an object -- including within object literals.</p> </td>
<span class="err">@</span><span class="p">[</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="k">then</span> <span class="s1">&#39;value&#39;</span> <span class="k">else</span> <span class="s1">&#39;variable&#39;</span><span class="p">].</span><span class="nx">assigns</span> <span class="nx">name</span>
<span class="nx">unfoldSoak</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">unfoldSoak</span> <span class="nx">o</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="s1">&#39;variable&#39;</span></pre></div> </td> </tr> <tr id="section-85"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-85">&#182;</a> </div> <p>Compile an assignment, delegating to <code>compilePatternMatch</code> or
<span class="nx">unfoldSoak</span> <span class="nx">o</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="s1">&#39;variable&#39;</span></pre></div> </td> </tr> <tr id="section-86"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-86">&#182;</a> </div> <p>Compile an assignment, delegating to <code>compilePatternMatch</code> or
<code>compileSplice</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="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -638,29 +669,31 @@ has not been seen yet within the current scope, declare it.</p> </td
<span class="k">return</span> <span class="nx">@compileSplice</span> <span class="nx">o</span> <span class="k">if</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">isSplice</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">@compileConditional</span> <span class="nx">o</span> <span class="k">if</span> <span class="nx">@context</span> <span class="k">in</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="nv">name = </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
<span class="k">if</span> <span class="nx">@value</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nv">match = </span><span class="nx">@METHOD_DEF</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">name</span>
<span class="vi">@value.name = </span><span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="vi">@value.klass = </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">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</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="p">,</span> <span class="nx">LEVEL_LIST</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">unless</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">isAssignable</span><span class="p">()</span>
<span class="nx">unless</span> <span class="nx">@context</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">isAssignable</span><span class="p">()</span>
<span class="k">throw</span> <span class="nx">SyntaxError</span> <span class="s2">&quot;\&quot;#{ @variable.compile o }\&quot; cannot be assigned.&quot;</span>
<span class="nx">unless</span> <span class="nx">@context</span> <span class="o">or</span> <span class="nx">isValue</span> <span class="o">and</span> <span class="p">(</span><span class="nx">@variable</span><span class="p">.</span><span class="nx">namespaced</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">hasProperties</span><span class="p">())</span>
<span class="k">if</span> <span class="nx">@param</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">&#39;var&#39;</span>
<span class="k">else</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="k">if</span> <span class="nx">@value</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nv">match = </span><span class="nx">@METHOD_DEF</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">name</span>
<span class="vi">@value.name = </span><span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="vi">@value.klass = </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">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</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="p">,</span> <span class="nx">LEVEL_LIST</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="nv">val = </span><span class="nx">name</span> <span class="o">+</span> <span class="s2">&quot; #{ @context or &#39;=&#39; } &quot;</span> <span class="o">+</span> <span class="nx">val</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;=</span> <span class="nx">LEVEL_LIST</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-86"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-86">&#182;</a> </div> <p>Brief implementation of recursive pattern matching, when assigning array or
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;=</span> <span class="nx">LEVEL_LIST</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-87"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-87">&#182;</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="nx">compilePatternMatch</span><span class="o">:</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">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">is</span> <span class="nx">LEVEL_TOP</span>
<span class="p">{</span><span class="nx">value</span><span class="p">}</span> <span class="o">=</span> <span class="k">this</span>
<span class="p">{</span><span class="nx">objects</span><span class="p">}</span> <span class="o">=</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span>
<span class="k">return</span> <span class="nx">value</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span> <span class="nx">unless</span> <span class="nv">olen = </span><span class="nx">objects</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">unless</span> <span class="nv">olen = </span><span class="nx">objects</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">code = </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="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_OP</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span>
<span class="nv">isObject = </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">isObject</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">top</span> <span class="o">and</span> <span class="nx">olen</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="p">(</span><span class="nv">obj = </span><span class="nx">objects</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Splat</span></pre></div> </td> </tr> <tr id="section-87"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-87">&#182;</a> </div> <p>Unroll simplest cases: <code>{v} = x</code> -> <code>v = x.v</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span>
<span class="k">if</span> <span class="nx">top</span> <span class="o">and</span> <span class="nx">olen</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="p">(</span><span class="nv">obj = </span><span class="nx">objects</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Splat</span></pre></div> </td> </tr> <tr id="section-88"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-88">&#182;</a> </div> <p>Unroll simplest cases: <code>{v} = x</code> -> <code>v = x.v</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span>
<span class="p">{</span><span class="nx">variable</span><span class="o">:</span> <span class="p">{</span><span class="nx">base</span><span class="o">:</span> <span class="nx">idx</span><span class="p">},</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">obj</span><span class="p">}</span> <span class="o">=</span> <span class="nx">obj</span>
<span class="k">else</span>
<span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">Parens</span>
@@ -680,10 +713,10 @@ for details.</p> </td> <td class="code"> <
<span class="k">if</span> <span class="o">not</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">vvar</span><span class="p">)</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">assigns</span><span class="p">(</span><span class="nx">vvar</span><span class="p">)</span>
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span> <span class="s2">&quot;#{ ref = o.scope.freeVariable &#39;ref&#39; } = #{vvar}&quot;</span>
<span class="nv">vvar = </span><span class="nx">ref</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></pre></div> </td> </tr> <tr id="section-88"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-88">&#182;</a> </div> <p>A regular array pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">idx = </span><span class="nx">i</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></pre></div> </td> </tr> <tr id="section-89"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-89">&#182;</a> </div> <p>A regular array pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">idx = </span><span class="nx">i</span>
<span class="k">if</span> <span class="nx">isObject</span>
<span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span></pre></div> </td> </tr> <tr id="section-89"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-89">&#182;</a> </div> <p>A regular object pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">{</span><span class="nx">variable</span><span class="o">:</span> <span class="p">{</span><span class="nx">base</span><span class="o">:</span> <span class="nx">idx</span><span class="p">},</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">obj</span><span class="p">}</span> <span class="o">=</span> <span class="nx">obj</span>
<span class="k">else</span></pre></div> </td> </tr> <tr id="section-90"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-90">&#182;</a> </div> <p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">Parens</span>
<span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span></pre></div> </td> </tr> <tr id="section-90"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-90">&#182;</a> </div> <p>A regular object pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">{</span><span class="nx">variable</span><span class="o">:</span> <span class="p">{</span><span class="nx">base</span><span class="o">:</span> <span class="nx">idx</span><span class="p">},</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">obj</span><span class="p">}</span> <span class="o">=</span> <span class="nx">obj</span>
<span class="k">else</span></pre></div> </td> </tr> <tr id="section-91"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-91">&#182;</a> </div> <p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">Parens</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="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">unwrapAll</span><span class="p">()).</span><span class="nx">cacheReference</span> <span class="nx">o</span>
<span class="k">else</span>
<span class="nv">idx = </span><span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="k">this</span> <span class="k">then</span> <span class="nx">obj</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="nx">name</span> <span class="k">else</span> <span class="nx">obj</span>
@@ -710,11 +743,11 @@ for details.</p> </td> <td class="code"> <
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Assign</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="kc">null</span><span class="p">,</span> <span class="nx">param</span><span class="o">:</span> <span class="nx">@param</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span>
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span> <span class="nx">vvar</span> <span class="nx">unless</span> <span class="nx">top</span>
<span class="nv">code = </span><span class="nx">assigns</span><span class="p">.</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;</span> <span class="nx">LEVEL_LIST</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-91"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-91">&#182;</a> </div> <p>When compiling a conditional assignment, take care to ensure that the
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;</span> <span class="nx">LEVEL_LIST</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-92"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-92">&#182;</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="nx">compileConditional</span><span class="o">:</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">left</span><span class="p">,</span> <span class="nx">rite</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">cacheReference</span> <span class="nx">o</span>
<span class="k">new</span> <span class="nx">Op</span><span class="p">(</span><span class="nx">@context</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="nx">left</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">rite</span><span class="p">,</span> <span class="nx">@value</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">)).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-92"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-92">&#182;</a> </div> <p>Compile the assignment from an array splice literal, using JavaScript's
<span class="k">new</span> <span class="nx">Op</span><span class="p">(</span><span class="nx">@context</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="nx">left</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">rite</span><span class="p">,</span> <span class="nx">@value</span><span class="p">,</span> <span class="s1">&#39;=&#39;</span><span class="p">)).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-93"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-93">&#182;</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="nx">compileSplice</span><span class="o">:</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">range</span><span class="o">:</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">=</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="nv">name = </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
@@ -730,12 +763,12 @@ more than once.</p> </td> <td class="code">
<span class="nv">to = </span><span class="s2">&quot;9e9&quot;</span>
<span class="p">[</span><span class="nx">valDef</span><span class="p">,</span> <span class="nx">valRef</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">cache</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
<span class="nv">code = </span><span class="s2">&quot;[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}&quot;</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;</span> <span class="nx">LEVEL_TOP</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-93"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-93">&#182;</a> </div> <h3>Code</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-94"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-94">&#182;</a> </div> <p>A function definition. This is the only node that creates a new Scope.
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;</span> <span class="nx">LEVEL_TOP</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-94"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-94">&#182;</a> </div> <h3>Code</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-95"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-95">&#182;</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 Code
has no <em>children</em> -- they're within the inner scope.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Code = </span><span class="nx">class</span> <span class="nx">Code</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="vi">@body = </span><span class="nx">body</span> <span class="o">or</span> <span class="k">new</span> <span class="nx">Block</span>
<span class="vi">@bound = </span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;boundfunc&#39;</span>
<span class="vi">@context = </span><span class="s1">&#39;this&#39;</span> <span class="k">if</span> <span class="nx">@bound</span>
@@ -743,7 +776,7 @@ has no <em>children</em> -- they're within the inner scope.</p> </td
<span class="nx">isStatement</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="o">!!</span><span class="nx">@ctor</span>
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-95"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-95">&#182;</a> </div> <p>Compilation creates a new scope unless explicitly asked to share with the
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-96"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-96">&#182;</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
@@ -752,10 +785,10 @@ a closure.</p> </td> <td class="code"> <di
<span class="nv">o.scope.shared = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;sharedScope&#39;</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
<span class="k">delete</span> <span class="nx">o</span><span class="p">.</span><span class="nx">bare</span>
<span class="k">delete</span> <span class="nx">o</span><span class="p">.</span><span class="nx">globals</span>
<span class="nv">vars = </span><span class="p">[]</span>
<span class="nv">exprs = </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">when</span> <span class="nx">param</span><span class="p">.</span><span class="nx">splat</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">add</span> <span class="nx">param</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="s1">&#39;var&#39;</span> <span class="k">if</span> <span class="nx">param</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">value</span>
<span class="nv">splats = </span><span class="k">new</span> <span class="nx">Assign</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Arr</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">asReference</span> <span class="nx">o</span> <span class="k">for</span> <span class="nx">p</span> <span class="k">in</span> <span class="nx">@params</span><span class="p">)),</span>
<span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;arguments&#39;</span>
<span class="k">break</span>
@@ -784,9 +817,9 @@ a closure.</p> </td> <td class="code"> <di
<span class="nx">code</span> <span class="o">+=</span> <span class="s1">&#39;}&#39;</span>
<span class="k">return</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="nx">code</span> <span class="k">if</span> <span class="nx">@ctor</span>
<span class="k">return</span> <span class="nx">utility</span><span class="p">(</span><span class="s1">&#39;bind&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;(#{code}, #{@context})&quot;</span> <span class="k">if</span> <span class="nx">@bound</span>
<span class="k">if</span> <span class="nx">@front</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-96"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-96">&#182;</a> </div> <p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope boundaries
<span class="k">if</span> <span class="nx">@front</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-97"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-97">&#182;</a> </div> <p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope boundaries
unless <code>crossScope</code> is <code>true</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">traverseChildren</span><span class="o">:</span> <span class="p">(</span><span class="nx">crossScope</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">super</span><span class="p">(</span><span class="nx">crossScope</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="k">if</span> <span class="nx">crossScope</span></pre></div> </td> </tr> <tr id="section-97"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-97">&#182;</a> </div> <h3>Param</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-98">&#182;</a> </div> <p>A parameter in a function definition. Beyond a typical Javascript parameter,
<span class="k">super</span><span class="p">(</span><span class="nx">crossScope</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="k">if</span> <span class="nx">crossScope</span></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-98">&#182;</a> </div> <h3>Param</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-99">&#182;</a> </div> <p>A parameter in a function definition. Beyond a typical Javascript parameter,
these parameters can also attach themselves to the context of the function,
as well as be a splat, gathering up a group of parameters into an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Param = </span><span class="nx">class</span> <span class="nx">Param</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="nx">@splat</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -809,7 +842,7 @@ as well as be a splat, gathering up a group of parameters into an array.</p>
<span class="vi">@reference = </span><span class="nx">node</span>
<span class="nx">isComplex</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@name</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-99">&#182;</a> </div> <h3>Splat</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-100">&#182;</a> </div> <p>A splat, either as a parameter to a function, an argument to a call,
<span class="nx">@name</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-100">&#182;</a> </div> <h3>Splat</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-101">&#182;</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.Splat = </span><span class="nx">class</span> <span class="nx">Splat</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span>
@@ -823,7 +856,7 @@ or as part of a destructuring assignment.</p> </td> <td
<span class="nx">@name</span><span class="p">.</span><span class="nx">assigns</span> <span class="nx">name</span>
<span class="nx">compile</span><span class="o">:</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">@compileParam</span> <span class="nx">o</span> <span class="k">else</span> <span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-101">&#182;</a> </div> <p>Utility function that converts arbitrary number of elements, mixed with
<span class="k">if</span> <span class="nx">@index</span><span class="o">?</span> <span class="k">then</span> <span class="nx">@compileParam</span> <span class="nx">o</span> <span class="k">else</span> <span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-102">&#182;</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="nx">@compileSplattedArray</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">list</span><span class="p">,</span> <span class="nx">apply</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">index = </span><span class="o">-</span><span class="mi">1</span>
<span class="k">continue</span> <span class="k">while</span> <span class="p">(</span><span class="nv">node = </span><span class="nx">list</span><span class="p">[</span><span class="o">++</span><span class="nx">index</span><span class="p">])</span> <span class="o">and</span> <span class="nx">node</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Splat</span>
@@ -840,7 +873,7 @@ splats, to a proper array.</p> </td> <td class="code">
<span class="k">else</span> <span class="s2">&quot;[#{code}]&quot;</span>
<span class="k">return</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot;.concat(#{ args.slice(1).join &#39;, &#39; })&quot;</span> <span class="k">if</span> <span class="nx">index</span> <span class="o">is</span> <span class="mi">0</span>
<span class="nv">base = </span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">list</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span>
<span class="s2">&quot;[#{ base.join &#39;, &#39; }].concat(#{ args.join &#39;, &#39; })&quot;</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-102">&#182;</a> </div> <h3>While</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-103"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-103">&#182;</a> </div> <p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From
<span class="s2">&quot;[#{ base.join &#39;, &#39; }].concat(#{ args.join &#39;, &#39; })&quot;</span></pre></div> </td> </tr> <tr id="section-103"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-103">&#182;</a> </div> <h3>While</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-104"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-104">&#182;</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.While = </span><span class="nx">class</span> <span class="nx">While</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">condition</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -863,7 +896,7 @@ flexibility or more speed than a comprehension can provide.</p> </td
<span class="k">return</span> <span class="kc">no</span> <span class="nx">unless</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">length</span>
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">expressions</span>
<span class="k">return</span> <span class="nx">node</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">jumps</span> <span class="nx">loop</span><span class="o">:</span> <span class="kc">yes</span>
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-104"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-104">&#182;</a> </div> <p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-105"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-105">&#182;</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="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
@@ -876,27 +909,30 @@ return an array containing the computed result of each iteration.</p>
<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">freeVariable</span> <span class="s1">&#39;results&#39;</span>
<span class="nv">set = </span><span class="s2">&quot;#{@tab}#{rvar} = [];\n&quot;</span>
<span class="nv">body = </span><span class="nx">Push</span><span class="p">.</span><span class="nx">wrap</span> <span class="nx">rvar</span><span class="p">,</span> <span class="nx">body</span> <span class="k">if</span> <span class="nx">body</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">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@guard</span>
<span class="nv">body = </span><span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="k">new</span> <span class="nx">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@guard</span>
<span class="nv">body = </span><span class="s2">&quot;\n#{ body.compile o, LEVEL_TOP }\n#{@tab}&quot;</span>
<span class="nv">code = </span><span class="nx">set</span> <span class="o">+</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="s2">&quot;while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}&quot;</span>
<span class="k">if</span> <span class="nx">@returns</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="s2">&quot;\n#{@tab}return #{rvar};&quot;</span>
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-105"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-105">&#182;</a> </div> <h3>Op</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-106"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-106">&#182;</a> </div> <p>Simple Arithmetic and logical operations. Performs some conversion from
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-106"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-106">&#182;</a> </div> <h3>Op</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-107"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-107">&#182;</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.Op = </span><span class="nx">class</span> <span class="nx">Op</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">op</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="k">return</span> <span class="k">new</span> <span class="nx">In</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">second</span> <span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">&#39;in&#39;</span>
<span class="k">return</span> <span class="k">new</span> <span class="nx">Call</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">first</span><span class="p">.</span><span class="nx">params</span> <span class="o">or</span> <span class="p">[]</span> <span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">&#39;do&#39;</span>
<span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">&#39;do&#39;</span>
<span class="nv">call = </span><span class="k">new</span> <span class="nx">Call</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">first</span><span class="p">.</span><span class="nx">params</span> <span class="o">or</span> <span class="p">[]</span>
<span class="nv">call.do = </span><span class="kc">yes</span>
<span class="k">return</span> <span class="nx">call</span>
<span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">&#39;new&#39;</span>
<span class="k">return</span> <span class="nx">first</span><span class="p">.</span><span class="nx">newInstance</span><span class="p">()</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Call</span>
<span class="nv">first = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">first</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">first</span><span class="p">.</span><span class="nx">bound</span>
<span class="k">return</span> <span class="nx">first</span><span class="p">.</span><span class="nx">newInstance</span><span class="p">()</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Call</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">first</span><span class="p">.</span><span class="nx">do</span>
<span class="nv">first = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">first</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">first</span><span class="p">.</span><span class="nx">bound</span> <span class="o">or</span> <span class="nx">first</span><span class="p">.</span><span class="nx">do</span>
<span class="vi">@operator = </span><span class="nx">CONVERSIONS</span><span class="p">[</span><span class="nx">op</span><span class="p">]</span> <span class="o">or</span> <span class="nx">op</span>
<span class="vi">@first = </span><span class="nx">first</span>
<span class="vi">@second = </span><span class="nx">second</span>
<span class="vi">@flip = </span><span class="o">!!</span><span class="nx">flip</span>
<span class="k">return</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-107"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-107">&#182;</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="k">return</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-108"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-108">&#182;</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="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="s1">&#39;of&#39;</span><span class="o">:</span> <span class="s1">&#39;in&#39;</span></pre></div> </td> </tr> <tr id="section-108"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-108">&#182;</a> </div> <p>The map of invertible operators.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">INVERSIONS =</span>
<span class="s1">&#39;of&#39;</span><span class="o">:</span> <span class="s1">&#39;in&#39;</span></pre></div> </td> </tr> <tr id="section-109"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-109">&#182;</a> </div> <p>The map of invertible operators.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">INVERSIONS =</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>
@@ -905,7 +941,7 @@ CoffeeScript operations into their JavaScript equivalents.</p> </td>
<span class="nx">isSimpleNumber</span><span class="o">:</span> <span class="nx">NO</span>
<span class="nx">isUnary</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="o">not</span> <span class="nx">@second</span></pre></div> </td> </tr> <tr id="section-109"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-109">&#182;</a> </div> <p>Am I capable of
<span class="o">not</span> <span class="nx">@second</span></pre></div> </td> </tr> <tr id="section-110"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-110">&#182;</a> </div> <p>Am I capable of
<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="nx">isChainable</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@operator</span> <span class="k">in</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>
@@ -946,7 +982,7 @@ CoffeeScript operations into their JavaScript equivalents.</p> </td>
<span class="vi">@first.front = </span><span class="nx">@front</span>
<span class="nv">code = </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">LEVEL_OP</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nx">@operator</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</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">LEVEL_OP</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;=</span> <span class="nx">LEVEL_OP</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-110"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-110">&#182;</a> </div> <p>Mimic Python's chained comparisons when multiple comparison operators are
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;=</span> <span class="nx">LEVEL_OP</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-111"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-111">&#182;</a> </div> <p>Mimic Python's chained comparisons when multiple comparison operators are
used sequentially. For example:</p>
<pre><code>bin/coffee -e 'console.log 50 &lt; 65 &gt; 10'
@@ -959,21 +995,22 @@ true
<span class="nx">compileExistence</span><span class="o">:</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">@first</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
<span class="nv">ref = </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">freeVariable</span> <span class="s1">&#39;ref&#39;</span>
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="nx">ref</span><span class="p">),</span> <span class="nx">@first</span>
<span class="nv">ref = </span><span class="k">new</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">freeVariable</span> <span class="s1">&#39;ref&#39;</span>
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">@first</span>
<span class="k">else</span>
<span class="nv">fst = </span><span class="nx">@first</span>
<span class="nv">ref = </span><span class="nx">fst</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</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="s2">&quot; ? #{ref} : #{ @second.compile o, LEVEL_LIST }&quot;</span></pre></div> </td> </tr> <tr id="section-111"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-111">&#182;</a> </div> <p>Compile a unary <strong>Op</strong>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileUnary</span><span class="o">:</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="nx">fst</span>
<span class="k">new</span> <span class="nx">If</span><span class="p">(</span><span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">),</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;if&#39;</span><span class="p">).</span><span class="nx">addElse</span><span class="p">(</span><span class="nx">@second</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-112"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-112">&#182;</a> </div> <p>Compile a unary <strong>Op</strong>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileUnary</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">parts = </span><span class="p">[</span><span class="nv">op = </span><span class="nx">@operator</span><span class="p">]</span>
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="s1">&#39; &#39;</span> <span class="k">if</span> <span class="nx">op</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;new&#39;</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="o">or</span>
<span class="nx">op</span> <span class="k">in</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">and</span> <span class="nx">@first</span> <span class="k">instanceof</span> <span class="nx">Op</span> <span class="o">and</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">operator</span> <span class="o">is</span> <span class="nx">op</span>
<span class="vi">@first = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">@first</span> <span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">&#39;new&#39;</span> <span class="o">and</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">isStatement</span> <span class="nx">o</span>
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</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="s1">&#39;&#39;</span>
<span class="nx">toString</span><span class="o">:</span> <span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nx">@operator</span></pre></div> </td> </tr> <tr id="section-112"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-112">&#182;</a> </div> <h3>In</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.In = </span><span class="nx">class</span> <span class="nx">In</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nx">@operator</span></pre></div> </td> </tr> <tr id="section-113"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-113">&#182;</a> </div> <h3>In</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.In = </span><span class="nx">class</span> <span class="nx">In</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@object</span><span class="p">,</span> <span class="nx">@array</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="s1">&#39;object&#39;</span><span class="p">,</span> <span class="s1">&#39;array&#39;</span><span class="p">]</span>
@@ -991,6 +1028,7 @@ true
<span class="p">[</span><span class="nx">cmp</span><span class="p">,</span> <span class="nx">cnj</span><span class="p">]</span> <span class="o">=</span> <span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</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="k">else</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">tests = </span><span class="k">for</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@array</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="k">if</span> <span class="nx">i</span> <span class="k">then</span> <span class="nx">ref</span> <span class="k">else</span> <span class="nx">sub</span><span class="p">)</span> <span class="o">+</span> <span class="nx">cmp</span> <span class="o">+</span> <span class="nx">item</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span>
<span class="k">return</span> <span class="s1">&#39;false&#39;</span> <span class="k">if</span> <span class="nx">tests</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">0</span>
<span class="nv">tests = </span><span class="nx">tests</span><span class="p">.</span><span class="nx">join</span> <span class="nx">cnj</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;</span> <span class="nx">LEVEL_OP</span> <span class="k">then</span> <span class="nx">tests</span> <span class="k">else</span> <span class="s2">&quot;(#{tests})&quot;</span>
@@ -1003,7 +1041,7 @@ true
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">&quot;(#{code})&quot;</span>
<span class="nx">toString</span><span class="o">:</span> <span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</span> <span class="s1">&#39;!&#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-113"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-113">&#182;</a> </div> <h3>Try</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-114"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-114">&#182;</a> </div> <p>A classic <em>try/catch/finally</em> block.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Try = </span><span class="nx">class</span> <span class="nx">Try</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</span> <span class="s1">&#39;!&#39;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-114"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-114">&#182;</a> </div> <h3>Try</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-115"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-115">&#182;</a> </div> <p>A classic <em>try/catch/finally</em> block.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Try = </span><span class="nx">class</span> <span class="nx">Try</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;attempt&#39;</span><span class="p">,</span> <span class="s1">&#39;recovery&#39;</span><span class="p">,</span> <span class="s1">&#39;ensure&#39;</span><span class="p">]</span>
@@ -1015,7 +1053,7 @@ true
<span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="vi">@attempt = </span><span class="nx">@attempt</span> <span class="p">.</span><span class="nx">makeReturn</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">makeReturn</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-115"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-115">&#182;</a> </div> <p>Compilation is more or less as you would expect -- the <em>finally</em> clause
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-116"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-116">&#182;</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="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
<span class="nv">errorPart = </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>
@@ -1027,16 +1065,16 @@ is optional, the <em>catch</em> is not.</p> </td> <td cl
<span class="s2"> #{@tab}try {</span>
<span class="s2"> #{ @attempt.compile o, LEVEL_TOP }</span>
<span class="s2"> #{@tab}}#{ catchPart or &#39;&#39; }</span>
<span class="s2"> &quot;&quot;&quot;</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@ensure</span> <span class="k">then</span> <span class="s2">&quot; finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-116"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-116">&#182;</a> </div> <h3>Throw</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-117"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-117">&#182;</a> </div> <p>Simple node to throw an exception.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Throw = </span><span class="nx">class</span> <span class="nx">Throw</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="s2"> &quot;&quot;&quot;</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@ensure</span> <span class="k">then</span> <span class="s2">&quot; finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-117"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-117">&#182;</a> </div> <h3>Throw</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-118"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-118">&#182;</a> </div> <p>Simple node to throw an exception.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Throw = </span><span class="nx">class</span> <span class="nx">Throw</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@expression</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="s1">&#39;expression&#39;</span><span class="p">]</span>
<span class="nx">isStatement</span><span class="o">:</span> <span class="nx">YES</span>
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-118"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-118">&#182;</a> </div> <p>A <strong>Throw</strong> is already a return, of sorts...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">makeReturn</span><span class="o">:</span> <span class="nx">THIS</span>
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-119"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-119">&#182;</a> </div> <p>A <strong>Throw</strong> is already a return, of sorts...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">makeReturn</span><span class="o">:</span> <span class="nx">THIS</span>
<span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">@tab</span> <span class="o">+</span> <span class="s2">&quot;throw #{ @expression.compile o };&quot;</span></pre></div> </td> </tr> <tr id="section-119"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-119">&#182;</a> </div> <h3>Existence</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-120"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-120">&#182;</a> </div> <p>Checks a variable for existence -- not <em>null</em> and not <em>undefined</em>. This is
<span class="nx">@tab</span> <span class="o">+</span> <span class="s2">&quot;throw #{ @expression.compile o };&quot;</span></pre></div> </td> </tr> <tr id="section-120"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-120">&#182;</a> </div> <h3>Existence</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-121"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-121">&#182;</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.Existence = </span><span class="nx">class</span> <span class="nx">Existence</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@expression</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -1049,13 +1087,13 @@ table.</p> </td> <td class="code"> <div cl
<span class="nv">code = </span><span class="nx">@expression</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span>
<span class="nv">code = </span><span class="k">if</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">check</span> <span class="nx">code</span>
<span class="k">if</span> <span class="nx">@negated</span>
<span class="s2">&quot;typeof #{code} == \&quot;undefined\&quot; || #{code} === null&quot;</span>
<span class="s2">&quot;typeof #{code} === \&quot;undefined\&quot; || #{code} === null&quot;</span>
<span class="k">else</span>
<span class="s2">&quot;typeof #{code} != \&quot;undefined\&quot; &amp;&amp; #{code} !== null&quot;</span>
<span class="s2">&quot;typeof #{code} !== \&quot;undefined\&quot; &amp;&amp; #{code} !== null&quot;</span>
<span class="k">else</span>
<span class="nv">sym = </span><span class="k">if</span> <span class="nx">@negated</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;#{code} #{sym} null&quot;</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;=</span> <span class="nx">LEVEL_COND</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-121"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-121">&#182;</a> </div> <h3>Parens</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-122"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-122">&#182;</a> </div> <p>An extra set of parentheses, specified explicitly in the source. At one time
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;=</span> <span class="nx">LEVEL_COND</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-122"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-122">&#182;</a> </div> <h3>Parens</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-123"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-123">&#182;</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>
@@ -1076,7 +1114,7 @@ parentheses, but no longer -- you can put in as many as you please.</p>
<span class="nv">code = </span><span class="nx">expr</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_PAREN</span>
<span class="nv">bare = </span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&lt;</span> <span class="nx">LEVEL_OP</span> <span class="o">and</span> <span class="p">(</span><span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Op</span> <span class="o">or</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Call</span> <span class="o">or</span>
<span class="p">(</span><span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">For</span> <span class="o">and</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">returns</span><span class="p">))</span>
<span class="k">if</span> <span class="nx">bare</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-123"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-123">&#182;</a> </div> <h3>For</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-124"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-124">&#182;</a> </div> <p>CoffeeScript's replacement for the <em>for</em> loop is our array and object
<span class="k">if</span> <span class="nx">bare</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-124"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-124">&#182;</a> </div> <h3>For</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-125"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-125">&#182;</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>
@@ -1085,7 +1123,7 @@ 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.For = </span><span class="nx">class</span> <span class="nx">For</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</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="o">-&gt;</span>
<span class="p">{</span><span class="nx">@source</span><span class="p">,</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">@step</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="nx">source</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="nx">body</span><span class="p">]</span>
<span class="vi">@body = </span><span class="nx">Block</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="vi">@own = </span><span class="o">!!</span><span class="nx">source</span><span class="p">.</span><span class="nx">own</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>
@@ -1104,11 +1142,11 @@ you can map and filter in a single pass.</p> </td> <td c
<span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="vi">@returns = </span><span class="kc">yes</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-125"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-125">&#182;</a> </div> <p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-126"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-126">&#182;</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="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</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="nv">body = </span><span class="nx">Block</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="nv">lastJumps = </span><span class="nx">last</span><span class="p">(</span><span class="nx">body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">)</span><span class="o">?</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span>
<span class="vi">@returns = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">lastJumps</span> <span class="o">and</span> <span class="nx">lastJumps</span> <span class="k">instanceof</span> <span class="nx">Return</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>
@@ -1142,7 +1180,7 @@ some cannot.</p> </td> <td class="code"> <
<span class="nv">returnResult = </span><span class="s2">&quot;\n#{@tab}return #{rvar};&quot;</span>
<span class="nv">body = </span><span class="nx">Push</span><span class="p">.</span><span class="nx">wrap</span> <span class="nx">rvar</span><span class="p">,</span> <span class="nx">body</span>
<span class="k">if</span> <span class="nx">@guard</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">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span>
<span class="nv">body = </span><span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="k">new</span> <span class="nx">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span>
<span class="k">if</span> <span class="nx">@pattern</span>
<span class="nx">body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">@name</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s2">&quot;#{svar}[#{ivar}]&quot;</span>
<span class="nx">defPart</span> <span class="o">+=</span> <span class="nx">@pluckDirectCall</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">body</span>
@@ -1175,7 +1213,7 @@ some cannot.</p> </td> <td class="code"> <
<span class="nx">args</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;this&#39;</span>
<span class="nx">body</span><span class="p">.</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="k">new</span> <span class="nx">Call</span> <span class="nx">base</span><span class="p">,</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">args</span>
<span class="nx">defs</span> <span class="o">+=</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">ref</span><span class="p">,</span> <span class="nx">fn</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">LEVEL_TOP</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;;\n&#39;</span>
<span class="nx">defs</span></pre></div> </td> </tr> <tr id="section-126"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-126">&#182;</a> </div> <h3>Switch</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-127"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-127">&#182;</a> </div> <p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Switch = </span><span class="nx">class</span> <span class="nx">Switch</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">defs</span></pre></div> </td> </tr> <tr id="section-127"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-127">&#182;</a> </div> <h3>Switch</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-128"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-128">&#182;</a> </div> <p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Switch = </span><span class="nx">class</span> <span class="nx">Switch</span> <span class="k">extends</span> <span class="nx">Base</span>
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@subject</span><span class="p">,</span> <span class="nx">@cases</span><span class="p">,</span> <span class="nx">@otherwise</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="s1">&#39;subject&#39;</span><span class="p">,</span> <span class="s1">&#39;cases&#39;</span><span class="p">,</span> <span class="s1">&#39;otherwise&#39;</span><span class="p">]</span>
@@ -1203,11 +1241,10 @@ some cannot.</p> </td> <td class="code"> <
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">body</span> <span class="o">+</span> <span class="s1">&#39;\n&#39;</span> <span class="k">if</span> <span class="nv">body = </span><span class="nx">block</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span>
<span class="k">break</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="nx">@cases</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@otherwise</span>
<span class="nv">expr = </span><span class="nx">@lastNonComment</span> <span class="nx">block</span><span class="p">.</span><span class="nx">expressions</span>
<span class="nv">jumper = </span><span class="nx">expr</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span>
<span class="k">if</span> <span class="o">not</span> <span class="nx">expr</span> <span class="o">or</span> <span class="o">not</span> <span class="nx">jumper</span> <span class="o">or</span> <span class="p">(</span><span class="nx">jumper</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">jumper</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;debugger&#39;</span><span class="p">)</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">idt2</span> <span class="o">+</span> <span class="s1">&#39;break;\n&#39;</span>
<span class="k">continue</span> <span class="k">if</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Return</span> <span class="o">or</span> <span class="p">(</span><span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span> <span class="o">and</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">value</span> <span class="o">isnt</span> <span class="s1">&#39;debugger&#39;</span><span class="p">)</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">idt2</span> <span class="o">+</span> <span class="s1">&#39;break;\n&#39;</span>
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">idt1</span> <span class="o">+</span> <span class="s2">&quot;default:\n#{ @otherwise.compile o, LEVEL_TOP }\n&quot;</span> <span class="k">if</span> <span class="nx">@otherwise</span> <span class="o">and</span> <span class="nx">@otherwise</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">code</span> <span class="o">+</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="s1">&#39;}&#39;</span></pre></div> </td> </tr> <tr id="section-128"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-128">&#182;</a> </div> <h3>If</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-129"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-129">&#182;</a> </div> <p><em>If/else</em> statements. Acts as an expression by pushing down requested returns
<span class="nx">code</span> <span class="o">+</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="s1">&#39;}&#39;</span></pre></div> </td> </tr> <tr id="section-129"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-129">&#182;</a> </div> <h3>If</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-130"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-130">&#182;</a> </div> <p><em>If/else</em> statements. Acts as an expression by pushing down requested returns
to the last line of each clause.</p>
<p>Single-expression <strong>Ifs</strong> are compiled into conditional operators if possible,
@@ -1221,13 +1258,13 @@ because ternaries are already proper expressions, and don't need conversion.</p>
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;condition&#39;</span><span class="p">,</span> <span class="s1">&#39;body&#39;</span><span class="p">,</span> <span class="s1">&#39;elseBody&#39;</span><span class="p">]</span>
<span class="nx">bodyNode</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="nx">@body</span><span class="o">?</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span>
<span class="nx">elseBodyNode</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="nx">@elseBody</span><span class="o">?</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-130"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-130">&#182;</a> </div> <p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addElse</span><span class="o">:</span> <span class="p">(</span><span class="nx">elseBody</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">elseBodyNode</span><span class="o">:</span> <span class="o">-&gt;</span> <span class="nx">@elseBody</span><span class="o">?</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-131"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-131">&#182;</a> </div> <p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addElse</span><span class="o">:</span> <span class="p">(</span><span class="nx">elseBody</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">@isChain</span>
<span class="nx">@elseBodyNode</span><span class="p">().</span><span class="nx">addElse</span> <span class="nx">elseBody</span>
<span class="k">else</span>
<span class="vi">@isChain = </span><span class="nx">elseBody</span> <span class="k">instanceof</span> <span class="nx">If</span>
<span class="vi">@elseBody = </span><span class="nx">@ensureExpressions</span> <span class="nx">elseBody</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-131"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-131">&#182;</a> </div> <p>The <strong>If</strong> only compiles into a statement if either of its bodies needs
<span class="vi">@elseBody = </span><span class="nx">@ensureBlock</span> <span class="nx">elseBody</span>
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-132"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-132">&#182;</a> </div> <p>The <strong>If</strong> only compiles into a statement if either of its bodies needs
to be a statement. Otherwise a conditional operator is safe.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">isStatement</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">o</span><span class="o">?</span><span class="p">.</span><span class="nx">level</span> <span class="o">is</span> <span class="nx">LEVEL_TOP</span> <span class="o">or</span>
<span class="nx">@bodyNode</span><span class="p">().</span><span class="nx">isStatement</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">or</span> <span class="nx">@elseBodyNode</span><span class="p">()</span><span class="o">?</span><span class="p">.</span><span class="nx">isStatement</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
@@ -1238,17 +1275,17 @@ to be a statement. Otherwise a conditional operator is safe.</p> </t
<span class="k">if</span> <span class="nx">@isStatement</span> <span class="nx">o</span> <span class="k">then</span> <span class="nx">@compileStatement</span> <span class="nx">o</span> <span class="k">else</span> <span class="nx">@compileExpression</span> <span class="nx">o</span>
<span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@body</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="nx">@body</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
<span class="nx">@elseBody</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="nx">@elseBody</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
<span class="nx">@body</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Block</span> <span class="p">[</span><span class="nx">@body</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
<span class="nx">@elseBody</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Block</span> <span class="p">[</span><span class="nx">@elseBody</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
<span class="k">this</span>
<span class="nx">ensureExpressions</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Expressions</span> <span class="k">then</span> <span class="nx">node</span> <span class="k">else</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="nx">node</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-132"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-132">&#182;</a> </div> <p>Compile the <strong>If</strong> as a regular <em>if-else</em> statement. Flattened chains
<span class="nx">ensureBlock</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Block</span> <span class="k">then</span> <span class="nx">node</span> <span class="k">else</span> <span class="k">new</span> <span class="nx">Block</span> <span class="p">[</span><span class="nx">node</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-133"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-133">&#182;</a> </div> <p>Compile the <strong>If</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="nx">compileStatement</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">child = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">&#39;chainChild&#39;</span>
<span class="nv">cond = </span><span class="nx">@condition</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_PAREN</span>
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
<span class="nv">body = </span><span class="nx">@ensureExpressions</span><span class="p">(</span><span class="nx">@body</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">body = </span><span class="nx">@ensureBlock</span><span class="p">(</span><span class="nx">@body</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span>
<span class="nv">body = </span><span class="s2">&quot;\n#{body}\n#{@tab}&quot;</span> <span class="k">if</span> <span class="nx">body</span>
<span class="nv">ifPart = </span><span class="s2">&quot;if (#{cond}) {#{body}}&quot;</span>
<span class="nv">ifPart = </span><span class="nx">@tab</span> <span class="o">+</span> <span class="nx">ifPart</span> <span class="nx">unless</span> <span class="nx">child</span>
@@ -1258,7 +1295,7 @@ force inner <em>else</em> bodies into statement form.</p> </td>
<span class="nv">o.chainChild = </span><span class="kc">yes</span>
<span class="nx">@elseBody</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">().</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span>
<span class="k">else</span>
<span class="s2">&quot;{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}&quot;</span></pre></div> </td> </tr> <tr id="section-133"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-133">&#182;</a> </div> <p>Compile the If as a conditional operator.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileExpression</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="s2">&quot;{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}&quot;</span></pre></div> </td> </tr> <tr id="section-134"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-134">&#182;</a> </div> <p>Compile the If as a conditional operator.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileExpression</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">cond = </span><span class="nx">@condition</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_COND</span>
<span class="nv">body = </span><span class="nx">@bodyNode</span><span class="p">().</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
<span class="nv">alt = </span><span class="k">if</span> <span class="nx">@elseBodyNode</span><span class="p">()</span> <span class="k">then</span> <span class="nx">@elseBodyNode</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">LEVEL_LIST</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;void 0&#39;</span>
@@ -1266,38 +1303,37 @@ force inner <em>else</em> bodies into statement form.</p> </td>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">&gt;=</span> <span class="nx">LEVEL_COND</span> <span class="k">then</span> <span class="s2">&quot;(#{code})&quot;</span> <span class="k">else</span> <span class="nx">code</span>
<span class="nx">unfoldSoak</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@soak</span> <span class="o">and</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-134"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-134">&#182;</a> </div> <h2>Faux-Nodes</h2>
<span class="nx">@soak</span> <span class="o">and</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-135"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-135">&#182;</a> </div> <h2>Faux-Nodes</h2>
<p>Faux-nodes are never created by the grammar, but are used during code
generation to generate other combinations of nodes.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-135"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-135">&#182;</a> </div> <h3>Push</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-136"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-136">&#182;</a> </div> <p>The <strong>Push</strong> creates the tree for <code>array.push(value)</code>,
generation to generate other combinations of nodes.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-136"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-136">&#182;</a> </div> <h3>Push</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-137"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-137">&#182;</a> </div> <p>The <strong>Push</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">Push =</span>
<span class="nx">wrap</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">exps</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="nx">exps</span> <span class="k">if</span> <span class="nx">exps</span><span class="p">.</span><span class="nx">isEmpty</span><span class="p">()</span> <span class="o">or</span> <span class="nx">last</span><span class="p">(</span><span class="nx">exps</span><span class="p">.</span><span class="nx">expressions</span><span class="p">).</span><span class="nx">jumps</span><span class="p">()</span>
<span class="nx">exps</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Call</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</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">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;push&#39;</span><span class="p">]),</span> <span class="p">[</span><span class="nx">exps</span><span class="p">.</span><span class="nx">pop</span><span class="p">()]</span></pre></div> </td> </tr> <tr id="section-137"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-137">&#182;</a> </div> <h3>Closure</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-138"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-138">&#182;</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">Closure =</span></pre></div> </td> </tr> <tr id="section-139"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-139">&#182;</a> </div> <p>Wrap the expressions body, unless it contains a pure statement,
<span class="nx">exps</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Call</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</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">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;push&#39;</span><span class="p">]),</span> <span class="p">[</span><span class="nx">exps</span><span class="p">.</span><span class="nx">pop</span><span class="p">()]</span></pre></div> </td> </tr> <tr id="section-138"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-138">&#182;</a> </div> <h3>Closure</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-139"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-139">&#182;</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">Closure =</span></pre></div> </td> </tr> <tr id="section-140"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-140">&#182;</a> </div> <p>Wrap the expressions body, unless it contains a pure statement,
in which case, no dice. If the body mentions <code>this</code> or <code>arguments</code>,
then make sure that the closure wrapper preserves the original values.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">wrap</span><span class="o">:</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="nx">noReturn</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">jumps</span><span class="p">()</span>
<span class="nv">func = </span><span class="k">new</span> <span class="nx">Code</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">func = </span><span class="k">new</span> <span class="nx">Code</span> <span class="p">[],</span> <span class="nx">Block</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">args = </span><span class="p">[]</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">mentionsArgs = </span><span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalArgs</span><span class="p">)</span> <span class="o">or</span>
<span class="p">(</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalThis</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">mentionsArgs = </span><span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalArgs</span><span class="p">)</span> <span class="o">or</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalThis</span>
<span class="nv">meth = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="k">if</span> <span class="nx">mentionsArgs</span> <span class="k">then</span> <span class="s1">&#39;apply&#39;</span> <span class="k">else</span> <span class="s1">&#39;call&#39;</span>
<span class="nv">args = </span><span class="p">[</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;this&#39;</span><span class="p">]</span>
<span class="nx">args</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;arguments&#39;</span> <span class="k">if</span> <span class="nx">mentionsArgs</span>
<span class="nv">func = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">func</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Access</span> <span class="nx">meth</span><span class="p">]</span>
<span class="nv">func.noReturn = </span><span class="nx">noReturn</span>
<span class="nv">call = </span><span class="k">new</span> <span class="nx">Call</span> <span class="nx">func</span><span class="p">,</span> <span class="nx">args</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="k">if</span> <span class="nx">statement</span> <span class="k">then</span> <span class="nx">Block</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="nx">literalArgs</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;arguments&#39;</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">node</span><span class="p">.</span><span class="nx">asKey</span>
<span class="nx">literalThis</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">&#39;this&#39;</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">node</span><span class="p">.</span><span class="nx">asKey</span><span class="p">)</span> <span class="o">or</span>
<span class="p">(</span><span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-140"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-140">&#182;</a> </div> <p>Unfold a node's child if soak, then tuck the node under created <code>If</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">unfoldSoak = </span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">parent</span><span class="p">,</span> <span class="nx">name</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-141"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-141">&#182;</a> </div> <p>Unfold a node's child if soak, then tuck the node under created <code>If</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">unfoldSoak = </span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">parent</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="nx">unless</span> <span class="nv">ifn = </span><span class="nx">parent</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nx">unfoldSoak</span> <span class="nx">o</span>
<span class="nx">parent</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">ifn</span><span class="p">.</span><span class="nx">body</span>
<span class="nv">ifn.body = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">parent</span>
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-141"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-141">&#182;</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre><span class="nv">UTILITIES =</span></pre></div> </td> </tr> <tr id="section-142"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-142">&#182;</a> </div> <p>Correctly set up a prototype chain for inheritance, including a reference
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-142"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-142">&#182;</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre><span class="nv">UTILITIES =</span></pre></div> </td> </tr> <tr id="section-143"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-143">&#182;</a> </div> <p>Correctly set up a prototype chain for inheritance, including a reference
to the superclass for <code>super()</code> calls, and copies of any static properties.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">extends</span><span class="o">:</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> function(child, parent) {</span>
<span class="s1"> for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }</span>
@@ -1307,26 +1343,25 @@ to the superclass for <code>super()</code> calls, and copies of any static prope
<span class="s1"> child.__super__ = parent.prototype;</span>
<span class="s1"> return child;</span>
<span class="s1"> }</span>
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-143"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-143">&#182;</a> </div> <p>Create a function bound to the current value of "this".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">bind</span><span class="o">:</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-144"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-144">&#182;</a> </div> <p>Create a function bound to the current value of "this".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">bind</span><span class="o">:</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> function(fn, me){ return function(){ return fn.apply(me, arguments); }; }</span>
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-144"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-144">&#182;</a> </div> <p>Discover if an item is in an array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">indexOf</span><span class="o">:</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-145"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-145">&#182;</a> </div> <p>Discover if an item is in an array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">indexOf</span><span class="o">:</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> Array.prototype.indexOf || function(item) {</span>
<span class="s1"> for (var i = 0, l = this.length; i &lt; l; i++) {</span>
<span class="s1"> if (this[i] === item) return i;</span>
<span class="s1"> }</span>
<span class="s1"> return -1;</span>
<span class="s1"> }</span>
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-145"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-145">&#182;</a> </div> <p>Shortcuts to speed up the lookup time for native functions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasProp</span><span class="o">:</span> <span class="s1">&#39;Object.prototype.hasOwnProperty&#39;</span>
<span class="nx">slice</span> <span class="o">:</span> <span class="s1">&#39;Array.prototype.slice&#39;</span></pre></div> </td> </tr> <tr id="section-146"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-146">&#182;</a> </div> <p>Levels indicates a node's position in the AST. Useful for knowing if
<span class="s1"> &#39;&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-146"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-146">&#182;</a> </div> <p>Shortcuts to speed up the lookup time for native functions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasProp</span><span class="o">:</span> <span class="s1">&#39;Object.prototype.hasOwnProperty&#39;</span>
<span class="nx">slice</span> <span class="o">:</span> <span class="s1">&#39;Array.prototype.slice&#39;</span></pre></div> </td> </tr> <tr id="section-147"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-147">&#182;</a> </div> <p>Levels indicates a node's position in the AST. Useful for knowing if
parens are necessary or superfluous.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LEVEL_TOP = </span><span class="mi">1</span> <span class="c1"># ...;</span>
<span class="nv">LEVEL_PAREN = </span><span class="mi">2</span> <span class="c1"># (...)</span>
<span class="nv">LEVEL_LIST = </span><span class="mi">3</span> <span class="c1"># [...]</span>
<span class="nv">LEVEL_COND = </span><span class="mi">4</span> <span class="c1"># ... ? x : y</span>
<span class="nv">LEVEL_OP = </span><span class="mi">5</span> <span class="c1"># !...</span>
<span class="nv">LEVEL_ACCESS = </span><span class="mi">6</span> <span class="c1"># ...[0]</span></pre></div> </td> </tr> <tr id="section-147"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-147">&#182;</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-148"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-148">&#182;</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">/[ \t]+$/gm</span>
<span class="nv">LEVEL_ACCESS = </span><span class="mi">6</span> <span class="c1"># ...[0]</span></pre></div> </td> </tr> <tr id="section-148"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-148">&#182;</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>
<span class="nv">IDENTIFIER = </span><span class="sr">/^[$A-Za-z_][$\w]*$/</span>
<span class="nv">IDENTIFIER = </span><span class="sr">/^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/</span>
<span class="nv">SIMPLENUM = </span><span class="sr">/^[+-]?\d+$/</span></pre></div> </td> </tr> <tr id="section-149"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-149">&#182;</a> </div> <p>Is a literal value a string?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IS_STRING = </span><span class="sr">/^[&#39;&quot;]/</span></pre></div> </td> </tr> <tr id="section-150"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-150">&#182;</a> </div> <h2>Utility Functions</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-151"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-151">&#182;</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">name</span><span class="p">]</span>

View File

@@ -39,7 +39,7 @@ for interpreting the options object.</p> </td> <td class
<span class="k">break</span>
<span class="nx">options</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</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="nx">help</span><span class="o">:</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="nv">lines = </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">longFlag</span><span class="p">.</span><span class="nx">length</span>

View File

@@ -4,20 +4,60 @@ Using it looks like this:</p>
<pre><code>coffee&gt; console.log "#{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="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</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="s1">&#39;./helpers&#39;</span>
<span class="nv">readline = </span><span class="nx">require</span> <span class="s1">&#39;readline&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>Start by opening up <strong>stdio</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdio = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Log an error.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">error = </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">stdio</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</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="o">+</span> <span class="s1">&#39;\n\n&#39;</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</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="nx">quit</span><span class="o">:</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></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
<span class="nv">readline = </span><span class="nx">require</span> <span class="s1">&#39;readline&#39;</span>
<span class="p">{</span><span class="nx">inspect</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;util&#39;</span>
<span class="p">{</span><span class="nx">Script</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;vm&#39;</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>REPL Setup</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Config</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">enableColours = </span><span class="kc">no</span>
<span class="nx">unless</span> <span class="nx">process</span><span class="p">.</span><span class="nx">platform</span> <span class="o">is</span> <span class="s1">&#39;win32&#39;</span>
<span class="nv">enableColours = </span><span class="o">not</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_DISABLE_COLORS</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Start by opening up <code>stdin</code> and <code>stdout</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdin = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
<span class="nv">stdout = </span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>Log an error.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">error = </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</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="o">+</span> <span class="s1">&#39;\n\n&#39;</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>The current backlog of multi-line code.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">backlog = </span><span class="s1">&#39;&#39;</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</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">buffer</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="nb">eval</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">bare</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">globals</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">fileName</span><span class="o">:</span> <span class="s1">&#39;repl&#39;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</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">error</span> <span class="nx">err</span>
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>Make sure that uncaught exceptions don't kill the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;uncaughtException&#39;</span><span class="p">,</span> <span class="nx">error</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdio</span>
of exiting.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">run = </span><span class="nx">do</span> <span class="o">-&gt;</span>
<span class="nv">sandbox =</span>
<span class="nx">require</span><span class="o">:</span> <span class="nx">require</span>
<span class="nx">module</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">exports</span><span class="o">:</span> <span class="p">{}</span> <span class="p">}</span>
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">of</span> <span class="nx">global</span>
<span class="nv">sandbox.global = </span><span class="nx">sandbox</span>
<span class="nv">sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = </span><span class="nx">sandbox</span>
<span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">code = </span><span class="nx">backlog</span> <span class="o">+=</span> <span class="s1">&#39;\n&#39;</span> <span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">code</span><span class="p">[</span><span class="nx">code</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="s1">&#39;\\&#39;</span>
<span class="k">return</span> <span class="nv">backlog = </span><span class="nx">backlog</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">backlog</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">backlog = </span><span class="s1">&#39;&#39;</span>
<span class="k">try</span>
<span class="nv">val = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="nx">code</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">sandbox</span><span class="p">,</span>
<span class="nx">bare</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span>
<span class="nx">filename</span><span class="o">:</span> <span class="s1">&#39;repl&#39;</span>
<span class="p">}</span>
<span class="nx">unless</span> <span class="nx">val</span> <span class="o">is</span> <span class="kc">undefined</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">inspect</span><span class="p">(</span><span class="nx">val</span><span class="p">,</span> <span class="kc">no</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">enableColours</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;\n&#39;</span>
<span class="k">catch</span> <span class="nx">err</span>
<span class="nx">error</span> <span class="nx">err</span>
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <h1>Autocompletion</h1> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Regexes to match complete-able bits of text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSOR = </span><span class="sr">/\s*([\w\.]+)(?:\.(\w*))$/</span>
<span class="nv">SIMPLEVAR = </span><span class="sr">/\s*(\w*)$/i</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Returns a list of completions, and the completed text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">autocomplete = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">completeAttribute</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">or</span> <span class="nx">completeVariable</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">or</span> <span class="p">[[],</span> <span class="nx">text</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Attempt to autocomplete a chained dotted attribute: <code>one.two.three</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">completeAttribute = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nv">match = </span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span> <span class="nx">ACCESSOR</span>
<span class="p">[</span><span class="nx">all</span><span class="p">,</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">prefix</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span>
<span class="k">try</span>
<span class="nv">val = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="nx">obj</span>
<span class="k">catch</span> <span class="nx">error</span>
<span class="k">return</span> <span class="p">[[],</span> <span class="nx">text</span><span class="p">]</span>
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">prefix</span><span class="p">,</span> <span class="nx">getPropertyNames</span> <span class="nx">val</span>
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">prefix</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Attempt to autocomplete an in-scope free variable: <code>one</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">completeVariable = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nv">free = </span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLEVAR</span><span class="p">)</span><span class="o">?</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nv">scope = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="s1">&#39;this&#39;</span>
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">free</span><span class="p">,</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">RESERVED</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">getPropertyNames</span> <span class="nx">scope</span><span class="p">)</span>
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">free</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Return elements of candidates for which <code>prefix</code> is a prefix.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">getCompletions = </span><span class="p">(</span><span class="nx">prefix</span><span class="p">,</span> <span class="nx">candidates</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">el</span> <span class="k">for</span> <span class="nx">el</span> <span class="k">in</span> <span class="nx">candidates</span> <span class="k">when</span> <span class="nx">el</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">prefix</span><span class="p">)</span> <span class="o">is</span> <span class="mi">0</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>Return all "own" properties of an object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">getPropertyNames = </span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="nx">name</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">name</span> <span class="k">of</span> <span class="nx">obj</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Make sure that uncaught exceptions don't kill the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;uncaughtException&#39;</span><span class="p">,</span> <span class="nx">error</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="mi">3</span>
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">autocomplete</span>
<span class="nx">stdin</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">repl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">buffer</span>
<span class="k">else</span>
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">stdout</span><span class="p">,</span> <span class="nx">autocomplete</span>
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="s1">&#39;coffee&gt; &#39;</span>
<span class="nx">stdio</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">repl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">buffer</span>
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">stdio</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">stdin</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;line&#39;</span><span class="p">,</span> <span class="nx">run</span>
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>

View File

@@ -78,7 +78,10 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
<span class="o">not</span> <span class="p">(</span><span class="nx">two</span><span class="o">?</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">or</span> <span class="nx">one</span><span class="o">?</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">three</span><span class="o">?</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="p">))</span> <span class="o">or</span>
<span class="p">(</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;,&#39;</span> <span class="o">and</span> <span class="nx">one</span> <span class="o">and</span>
<span class="nx">one</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">not</span> <span class="k">in</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;@&#39;</span><span class="p">,</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">])</span>
<span class="nv">action = </span><span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-&gt;</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;}&#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">action = </span><span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">tok = </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="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="nv">tok.generated = </span><span class="kc">yes</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">tok</span>
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">token</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="o">-&gt;</span>
<span class="k">if</span> <span class="p">(</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">in</span> <span class="nx">EXPRESSION_START</span>
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="p">[(</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">@tag</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">is</span> <span class="s1">&#39;{&#39;</span> <span class="k">then</span> <span class="s1">&#39;{&#39;</span> <span class="k">else</span> <span class="nx">tag</span><span class="p">),</span> <span class="nx">i</span><span class="p">]</span>
@@ -114,6 +117,7 @@ deal with them.</p> </td> <td class="code">
<span class="nv">seenSingle = </span><span class="kc">no</span>
<span class="nv">noCall = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">LINEBREAKS</span>
<span class="nv">token.call = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;?&#39;</span>
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">callObject</span> <span class="o">or</span>
<span class="nx">prev</span><span class="o">?</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">.</span><span class="nx">call</span> <span class="o">or</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="nx">IMPLICIT_FUNC</span><span class="p">)</span> <span class="o">and</span>
<span class="p">(</span><span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_CALL</span> <span class="o">or</span> <span class="o">not</span> <span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">or</span> <span class="nx">token</span><span class="p">.</span><span class="nx">newLine</span><span class="p">)</span> <span class="o">and</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_UNSPACED_CALL</span><span class="p">)</span>

View File

@@ -6,9 +6,9 @@ variables are new and need to be declared with <code>var</code>, and which are s
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="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>Import the helpers we plan to use.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">extend</span><span class="p">,</span> <span class="nx">last</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;./helpers&#39;</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="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>The top-level <strong>Scope</strong> object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">@root</span><span class="o">:</span> <span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</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
as well as a reference to the <strong>Block</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="nx">constructor</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="o">-&gt;</span>
it wraps.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">constructor</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="o">-&gt;</span>
<span class="vi">@variables = </span><span class="p">[{</span><span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;arguments&#39;</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">&#39;arguments&#39;</span><span class="p">}]</span>
<span class="vi">@positions = </span><span class="p">{}</span>
<span class="nv">Scope.root = </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">@parent</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Adds a new variable or overrides an existing one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">add</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">immediate</span><span class="p">)</span> <span class="o">-&gt;</span>
@@ -36,7 +36,7 @@ walks up to the root scope.</p> </td> <td class="code">
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>If we need to store an intermediate result, find an available name for a
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">freeVariable</span><span class="o">:</span> <span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">index = </span><span class="mi">0</span>
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">index</span><span class="p">),</span> <span class="kc">true</span><span class="p">)</span>
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">index</span><span class="p">))</span>
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">&#39;var&#39;</span><span class="p">,</span> <span class="kc">yes</span>
<span class="nx">temp</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</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="nx">assign</span><span class="o">:</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>

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html> <html> <head> <title>underscore.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> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> underscore.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p><strong>Underscore.coffee
(c) 2010 Jeremy Ashkenas, DocumentCloud Inc.</strong>
(c) 2011 Jeremy Ashkenas, DocumentCloud Inc.</strong>
Underscore is freely distributable under the terms of the
<a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a>.
Portions of Underscore are inspired by or borrowed from

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -80,10 +80,10 @@
<div class="screenshadow bl"></div>
<div class="screenshadow br"></div>
<div id="repl_source_wrap">
<textarea id="repl_source" rows="100">alert "Hello CoffeeScript!"</textarea>
<textarea id="repl_source" rows="100" spellcheck="false">alert "Hello CoffeeScript!"</textarea>
</div>
<div id="repl_results_wrap"><pre id="repl_results"></pre></div>
<div class="minibutton dark run">Run</div>
<div class="minibutton dark run" title="Ctrl-Enter">Run</div>
<br class="clear" />
</div>
</div>
@@ -131,7 +131,7 @@
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffee-script/tarball/1.0.0">1.0.0</a>
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.0">1.1.0</a>
</p>
<h2>
@@ -166,17 +166,21 @@
</p>
<pre>
npm install coffee-script</pre>
npm install -g coffee-script</pre>
<p>
If you'd prefer to install the latest master version of CoffeeScript, you
can clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
<p>
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
</p>
<p>
If you'd prefer to install the latest master version of CoffeeScript, you
can clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
<pre>
sudo bin/cake install</pre>
@@ -219,10 +223,11 @@ sudo bin/cake install</pre>
</td>
</tr>
<tr>
<td><code>-j, --join</code></td>
<td><code>-j, --join [FILE]</code></td>
<td>
Before compiling, concatenate all scripts together in the order they
were passed. Useful for building large projects.
were passed, and write them into the specified file.
Useful for building large projects.
</td>
</tr>
<tr>
@@ -326,7 +331,7 @@ Expressions
</li>
<li>
Concatenate a list of files into a single script:<br />
<tt>coffee -o lib/ --join --compile src/*.coffee</tt>
<tt>coffee --join project.js --compile src/*.coffee</tt>
</li>
<li>
Print out the compiled JS from a one-liner:<br />
@@ -479,11 +484,13 @@ Expressions
over arrays, objects, and ranges. Comprehensions replace (and compile into)
<b>for</b> loops, with optional guard clauses and the value of the current array index.
Unlike for loops, array comprehensions are expressions, and can be returned
and assigned. They should be able to handle most places where you otherwise
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
and assigned.
</p>
<%= code_for('array_comprehensions') %>
<p>
Comprehensions should be able to handle most places where you otherwise
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>:
<tt>shortNames = (name for name in list when name.length &lt; 5)</tt><br />
If you know the start and end of your loop, or would like to step through
in fixed-size increments, you can use a range to specify the start and
end of your comprehension.
@@ -540,7 +547,7 @@ Expressions
<b class="header">Array Slicing and Splicing with Ranges</b>
Ranges can also be used to extract slices of arrays.
With two dots (<tt>3..6</tt>), the range is inclusive (<tt>3, 4, 5, 6</tt>);
with three docs (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
with three dots (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
</p>
<%= code_for('slices', 'middle') %>
<p>
@@ -699,15 +706,15 @@ Expressions
in a single assignable expression.
</p>
<p>
Constructor functions are named, to better support reflection. In the
example below for the first class, <tt>this.constructor.name is "Animal"</tt>.
Constructor functions are named, to better support helpful stack traces.
</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>
helps with proper prototype setup, and can be used to create an inheritance
chain between any pair of constructor functions; <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()') %>
@@ -840,7 +847,7 @@ Expressions
<p>
Sometimes you'd like to pass a block comment through to the generated
JavaScript. For example, when you need to embed a licensing header at
the top of a file. Block comments, which mirror the synax for heredocs,
the top of a file. Block comments, which mirror the syntax for heredocs,
are preserved in the generated code.
</p>
<%= code_for('block_comment') %>
@@ -921,6 +928,10 @@ Expressions
</h2>
<ul>
<li>
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
a zero-configuration Rack server, with comprehensive annotated source.
</li>
<li>
<b>frank06</b>'s <a href="http://riakjs.org/">riak-js</a>, a Node.js client for
<a href="http://www.basho.com/Riak.html">Riak</a>, with support for HTTP
@@ -930,6 +941,10 @@ Expressions
<b>technoweenie</b>'s <a href="https://github.com/technoweenie/coffee-resque">Coffee-Resque</a>,
a port of <a href="https://github.com/defunkt/resque">Resque</a> for Node.js.
</li>
<li>
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
A headless, full-stack, faux-browser testing library for Node.js.
</li>
<li>
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
@@ -943,10 +958,6 @@ Expressions
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
<a href="http://rack.rubyforge.org/">Rack</a> server.
</li>
<li>
<b>sstephenson</b>'s <a href="http://sstephenson.github.com/strscan-js/">StringScanner</a>,
a simple tokenizer and lexical scanner for JavaScript strings.
</li>
</ul>
<h2>
@@ -969,103 +980,23 @@ Expressions
</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.
Bug reports, feature proposals, and ideas for changes to the language belong here.
</li>
<li>
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>.
<a href="https://groups.google.com/forum/#!forum/coffeescript">CoffeeScript Google Group</a><br />
If you'd like to ask a question, the mailing list is a good place to get help.
</li>
<li>
<b>satyr</b>'s <a href="http://github.com/satyr/coco">Coco</a>
&mdash; An avant-garde dialect of CoffeeScript that frequently pioneers
features and optimizations, some of which CoffeeScript later adopts.
Check out the <a href="https://github.com/satyr/coco/wiki/additions">list of additions</a>
to the language.
<a href="http://github.com/jashkenas/coffee-script/wiki">The CoffeeScript Wiki</a><br />
If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha &mdash; share it on the wiki.
The wiki also serves as a directory of handy
<a href="http://github.com/jashkenas/coffee-script/wiki/Text-editor-plugins">text editor extensions</a>,
<a href="http://github.com/jashkenas/coffee-script/wiki/Web-framework-plugins">web framework plugins</a>,
and general <a href="http://github.com/jashkenas/coffee-script/wiki/Build-tools">CoffeeScript build tools</a>.
</li>
<li>
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
&mdash; A Java Library that uses Rhino to compile CoffeeScript, allowing
compilation within Java projects or on systems that Node.js doesn't support.
</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>' <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>wavded</b>'s <a href="http://github.com/wavded/gedit-coffeescript">gedit-coffeescript</a>
&mdash; a CoffeeScript syntax highlighter for the gedit text editor.
</li>
<li>
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
&mdash; a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
</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>
<li>
<b>dsc</b>'s <a href="http://github.com/dsc/coffeecup">CoffeeCup</a>
&mdash; a Python WSGI middleware that compiles CoffeeScript to JavaScript
on-demand during development.
</li>
<li>
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
&mdash; a BistroCar alternative that integrates well with
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
</li>
<li>
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
&mdash; a custom filter for rendering CoffeeScript inline within
<a href="http://haml-lang.com/">HAML</a> templates.
</li>
<li>
<b>chrislloyd</b>'s <a href="http://github.com/chrislloyd/roast">Roast</a>
&mdash; a CoffeeScript compiler plug-in that allows you to include external
source files.
</li>
<li>
<b>andrzejsliwa</b>'s <a href="http://github.com/andrzejsliwa/coffeeapp">CoffeeApp</a>
&mdash; a CoffeeScript wrapper for CouchApps, web applications served
directly from CouchDB.
</li>
<li>
<b>sstephenson</b>'s <a href="http://github.com/sstephenson/eco">Eco</a>
&mdash; high-performance embedded CoffeeScript templates, after EJS and ERB.
</li>
<li>
<b>mauricemach</b>'s <a href="http://github.com/mauricemach/coffeekup">CoffeeKup</a>
&mdash; Markup as CoffeeScript. After _why's
<a href="http://markaby.github.com/">Markaby</a>.
</li>
<li>
<b>jashkenas</b>' <a href="http://jashkenas.github.com/docco/">Docco</a>
&mdash; a quick-and-dirty literate-programming-style documentation generator
for CoffeeScript. Used to produce the annotated source.
</li>
<li>
<b>naturalethic</b>'s <a href="http://github.com/naturalethic/coffee-mongo">coffee-mongo</a>
&mdash; an asynchronous MongoDB ORM, for use with Node.js and CoffeeScript.
</li>
<li>
<b>mauricemach</b>'s <a href="https://github.com/mauricemach/zappa">Zappa</a>
&mdash; a DSL for building web apps, built on top of Express and Socket.IO.
<a href="http://github.com/jashkenas/coffee-script/wiki/FAQ">The FAQ</a><br />
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
</li>
</ul>
@@ -1088,6 +1019,38 @@ Expressions
<span id="change_log" class="bookmark"></span>
Change Log
</h2>
<p>
<b class="header" style="margin-top: 20px;">1.1.0
<span class="timestamp"> &ndash; <small>May 1, 2011</small></span>
</b>
When running via <tt>coffee</tt> executable, <tt>process.argv</tt> and
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
The output in the REPL is now colorized, like Node's is.
Giving your concatenated CoffeeScripts a name when using <tt>--join</tt> is now mandatory.
Fix for lexing compound division <tt>/=</tt> as a regex accidentally.
All <tt>text/coffeescript</tt> tags should now execute in the order they're included.
Fixed an issue with extended subclasses using external constructor functions.
Fixed an edge-case infinite loop in <tt>addImplicitParentheses</tt>.
Fixed exponential slowdown with long chains of function calls.
Globals no longer leak into the CoffeeScript REPL.
Function calls can be used as default values for parameters.
Splatted parameters are declared local to the function.
</p>
<p>
<b class="header" style="margin-top: 20px;">1.0.1
<span class="timestamp"> &ndash; <small>Jan 31, 2011</small></span>
</b>
Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility
with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
Stopped requiring the core Node.js <tt>"util"</tt> module for
back-compatibility with Node.js 0.2.5. Fixed a case where a
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
statement. Optimized empty objects in destructuring assignment.
</p>
<p>
<b class="header" style="margin-top: 20px;">1.0.0
@@ -1562,7 +1525,7 @@ Expressions
$('#repl_source').keyup -> compileSource()
# Eval the compiled js.
$('.minibutton.run').click ->
evalJS = ->
try
eval window.compiledJS
catch error then alert error
@@ -1578,6 +1541,8 @@ Expressions
closeMenus = ->
$('.navigation.active').removeClass 'active'
$('.minibutton.run').click evalJS
# Bind navigation buttons to open the menus.
$('.navigation').click (e) ->
return if e.target.tagName.toLowerCase() is 'a'
@@ -1589,9 +1554,15 @@ Expressions
$(this).addClass 'active'
false
$(document.body).click (e) ->
return false if $(e.target).hasClass('minibutton')
closeMenus()
# Dismiss console if Escape pressed or click falls outside console
# Trigger Run button on Ctrl-Enter
$(document.body)
.keydown (e) ->
closeMenus() if e.which == 27
evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length
.click (e) ->
return false if $(e.target).hasClass('minibutton')
closeMenus()
$('#open_webchat').click ->
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')

View File

@@ -1,4 +1,4 @@
/*
CoffeeScript Compiler v1.0.0
CoffeeScript Compiler v1.1.0
Released under the MIT License
*/

View File

@@ -1,10 +1,10 @@
var fileName, _fn, _i, _len;
_fn = function(fileName) {
return fs.readFile(fileName, function(err, contents) {
return compile(fileName, contents.toString());
var filename, _fn, _i, _len;
_fn = function(filename) {
return fs.readFile(filename, function(err, contents) {
return compile(filename, contents.toString());
});
};
for (_i = 0, _len = list.length; _i < _len; _i++) {
fileName = list[_i];
_fn(fileName);
filename = list[_i];
_fn(filename);
}

View File

@@ -1,6 +1,10 @@
var footprints, solipsism;
if ((typeof mind != "undefined" && mind !== null) && !(typeof world != "undefined" && world !== null)) {
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
solipsism = true;
}
typeof speed != "undefined" && speed !== null ? speed : speed = 75;
footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";
if (typeof speed !== "undefined" && speed !== null) {
speed;
} else {
speed = 75;
};
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";

View File

@@ -21,7 +21,7 @@ race = function() {
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
return print(winner, runners);
};
if (typeof elvis != "undefined" && elvis !== null) {
if (typeof elvis !== "undefined" && elvis !== null) {
alert("I knew it!");
}
cubes = (function() {

View File

@@ -1,5 +1,5 @@
# **Underscore.coffee
# (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.**
# (c) 2011 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

File diff suppressed because one or more lines are too long

View File

@@ -58,10 +58,10 @@
<div class="screenshadow bl"></div>
<div class="screenshadow br"></div>
<div id="repl_source_wrap">
<textarea id="repl_source" rows="100">alert "Hello CoffeeScript!"</textarea>
<textarea id="repl_source" rows="100" spellcheck="false">alert "Hello CoffeeScript!"</textarea>
</div>
<div id="repl_results_wrap"><pre id="repl_results"></pre></div>
<div class="minibutton dark run">Run</div>
<div class="minibutton dark run" title="Ctrl-Enter">Run</div>
<br class="clear" />
</div>
</div>
@@ -109,7 +109,7 @@
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffee-script/tarball/1.0.0">1.0.0</a>
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.0">1.1.0</a>
</p>
<h2>
@@ -170,7 +170,7 @@ math <span class="Keyword">=</span> {
winner <span class="Keyword">=</span> arguments[<span class="Number">0</span>], runners <span class="Keyword">=</span> <span class="Number">2</span> <span class="Keyword">&lt;=</span> arguments.<span class="LibraryConstant">length</span> ? __slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">1</span>) : [];
<span class="Keyword">return</span> <span class="LibraryFunction">print</span>(winner, runners);
};
<span class="Keyword">if</span> (<span class="Keyword">typeof</span> elvis <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> elvis <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) {
<span class="Keyword">if</span> (<span class="Keyword">typeof</span> elvis <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> elvis <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) {
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">&quot;</span>I knew it!<span class="String">&quot;</span></span>);
}
cubes <span class="Keyword">=</span> (<span class="Storage">function</span>() {
@@ -205,7 +205,7 @@ race = function() {
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
return print(winner, runners);
};
if (typeof elvis != "undefined" && elvis !== null) {
if (typeof elvis !== "undefined" && elvis !== null) {
alert("I knew it!");
}
cubes = (function() {
@@ -241,17 +241,21 @@ cubes = (function() {
</p>
<pre>
npm install coffee-script</pre>
npm install -g coffee-script</pre>
<p>
If you'd prefer to install the latest master version of CoffeeScript, you
can clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
<p>
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
</p>
<p>
If you'd prefer to install the latest master version of CoffeeScript, you
can clone the CoffeeScript
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
from GitHub, or download
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
To install the CoffeeScript compiler system-wide
under <tt>/usr/local</tt>, open the directory and run:
</p>
<pre>
sudo bin/cake install</pre>
@@ -294,10 +298,11 @@ sudo bin/cake install</pre>
</td>
</tr>
<tr>
<td><code>-j, --join</code></td>
<td><code>-j, --join [FILE]</code></td>
<td>
Before compiling, concatenate all scripts together in the order they
were passed. Useful for building large projects.
were passed, and write them into the specified file.
Useful for building large projects.
</td>
</tr>
<tr>
@@ -401,7 +406,7 @@ Expressions
</li>
<li>
Concatenate a list of files into a single script:<br />
<tt>coffee -o lib/ --join --compile src/*.coffee</tt>
<tt>coffee --join project.js --compile src/*.coffee</tt>
</li>
<li>
Print out the compiled JS from a one-liner:<br />
@@ -752,8 +757,7 @@ alert("The Field: " + rest);;'>run</div><br class='clear' /></div>
over arrays, objects, and ranges. Comprehensions replace (and compile into)
<b>for</b> loops, with optional guard clauses and the value of the current array index.
Unlike for loops, array comprehensions are expressions, and can be returned
and assigned. They should be able to handle most places where you otherwise
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
and assigned.
</p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span>
eat food <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
@@ -765,6 +769,9 @@ _ref <span class="Keyword">=</span> [<span class="String"><span class="String">'
}
</pre><script>window.example9 = "# Eat lunch.\neat food for food in ['toast', 'cheese', 'wine']\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example9);'>load</div><br class='clear' /></div>
<p>
Comprehensions should be able to handle most places where you otherwise
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>:
<tt>shortNames = (name for name in list when name.length &lt; 5)</tt><br />
If you know the start and end of your loop, or would like to step through
in fixed-size increments, you can use a range to specify the start and
end of your comprehension.
@@ -911,28 +918,28 @@ lyrics = (function() {
provides the <tt>do</tt> keyword, which immediately invokes a passed function,
forwarding any arguments.
</p>
<div class='code'><pre class="idle"><span class="Keyword">for</span> fileName <span class="Keyword">in</span> list
<span class="Keyword">do</span> <span class="FunctionArgument">(fileName)</span> <span class="Storage">-&gt;</span>
fs.readFile fileName, <span class="FunctionArgument">(err, contents)</span> <span class="Storage">-&gt;</span>
compile fileName, contents.toString()
</pre><pre class="idle"><span class="Storage">var</span> fileName, _fn, _i, _len;
<span class="FunctionName">_fn</span> = <span class="Storage">function</span>(<span class="FunctionArgument">fileName</span>) {
<span class="Keyword">return</span> fs.readFile(fileName, <span class="Storage">function</span>(err, contents) {
<span class="Keyword">return</span> <span class="LibraryFunction">compile</span>(fileName, contents.<span class="LibraryFunction">toString</span>());
<div class='code'><pre class="idle"><span class="Keyword">for</span> filename <span class="Keyword">in</span> list
<span class="Keyword">do</span> <span class="FunctionArgument">(filename)</span> <span class="Storage">-&gt;</span>
fs.readFile filename, <span class="FunctionArgument">(err, contents)</span> <span class="Storage">-&gt;</span>
compile filename, contents.toString()
</pre><pre class="idle"><span class="Storage">var</span> filename, _fn, _i, _len;
<span class="FunctionName">_fn</span> = <span class="Storage">function</span>(<span class="FunctionArgument">filename</span>) {
<span class="Keyword">return</span> fs.readFile(filename, <span class="Storage">function</span>(err, contents) {
<span class="Keyword">return</span> <span class="LibraryFunction">compile</span>(filename, contents.<span class="LibraryFunction">toString</span>());
});
};
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> list.<span class="LibraryConstant">length</span>; _i <span class="Keyword">&lt;</span> _len; _i<span class="Keyword">++</span>) {
fileName <span class="Keyword">=</span> list[_i];
_fn(fileName);
filename <span class="Keyword">=</span> list[_i];
_fn(filename);
}
</pre><script>window.example13 = "for fileName in list\n do (fileName) ->\n fs.readFile fileName, (err, contents) ->\n compile fileName, contents.toString()"</script><div class='minibutton load' onclick='javascript: loadConsole(example13);'>load</div><br class='clear' /></div>
</pre><script>window.example13 = "for filename in list\n do (filename) ->\n fs.readFile filename, (err, contents) ->\n compile filename, contents.toString()"</script><div class='minibutton load' onclick='javascript: loadConsole(example13);'>load</div><br class='clear' /></div>
<p>
<span id="slices" class="bookmark"></span>
<b class="header">Array Slicing and Splicing with Ranges</b>
Ranges can also be used to extract slices of arrays.
With two dots (<tt>3..6</tt>), the range is inclusive (<tt>3, 4, 5, 6</tt>);
with three docs (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
with three dots (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
</p>
<div class='code'><pre class="idle">numbers <span class="Keyword">=</span> [<span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>, <span class="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>]
@@ -1199,17 +1206,25 @@ footprints <span class="Keyword">=</span> yeti <span class="Keyword">?</span> <s
</pre><pre class="idle"><span class="Storage">var</span> footprints, solipsism;
<span class="Keyword">if</span> ((<span class="Keyword">typeof</span> mind <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> <span class="Keyword">!</span>(<span class="Keyword">typeof</span> world <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>)) {
<span class="Keyword">if</span> ((<span class="Keyword">typeof</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> <span class="Keyword">!</span>(<span class="Keyword">typeof</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>)) {
solipsism <span class="Keyword">=</span> <span class="BuiltInConstant">true</span>;
}
<span class="Keyword">typeof</span> speed <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> speed <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span> ? speed : speed <span class="Keyword">=</span> <span class="Number">75</span>;
footprints <span class="Keyword">=</span> <span class="Keyword">typeof</span> yeti <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span> ? yeti : <span class="String"><span class="String">&quot;</span>bear<span class="String">&quot;</span></span>;
<span class="Keyword">if</span> (<span class="Keyword">typeof</span> speed <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> speed <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) {
speed;
} <span class="Keyword">else</span> {
speed <span class="Keyword">=</span> <span class="Number">75</span>;
};
footprints <span class="Keyword">=</span> <span class="Keyword">typeof</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">&quot;</span>undefined<span class="String">&quot;</span></span> <span class="Keyword">&amp;</span><span class="Keyword">&amp;</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span> ? yeti : <span class="String"><span class="String">&quot;</span>bear<span class="String">&quot;</span></span>;
</pre><script>window.example21 = "solipsism = true if mind? and not world?\n\nspeed ?= 75\n\nfootprints = yeti ? \"bear\"\n\nalert footprints"</script><div class='minibutton load' onclick='javascript: loadConsole(example21);'>load</div><div class='minibutton ok' onclick='javascript: var footprints, solipsism;
if ((typeof mind != "undefined" && mind !== null) && !(typeof world != "undefined" && world !== null)) {
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
solipsism = true;
}
typeof speed != "undefined" && speed !== null ? speed : speed = 75;
footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";;alert(footprints);'>run: footprints</div><br class='clear' /></div>
if (typeof speed !== "undefined" && speed !== null) {
speed;
} else {
speed = 75;
};
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";;alert(footprints);'>run: footprints</div><br class='clear' /></div>
<p>
The accessor variant of the existential operator <tt>?.</tt> can be used to soak
up null references in a chain of properties. Use it instead
@@ -1251,8 +1266,7 @@ zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.d
in a single assignable expression.
</p>
<p>
Constructor functions are named, to better support reflection. In the
example below for the first class, <tt>this.constructor.name is "Animal"</tt>.
Constructor functions are named, to better support helpful stack traces.
</p>
<div class='code'><pre class="idle"><span class="Storage">class</span> <span class="TypeName">Animal</span>
<span class="FunctionName">constructor</span><span class="Keyword">:</span> <span class="FunctionArgument">(@name)</span> <span class="Storage">-&gt;</span>
@@ -1370,8 +1384,9 @@ tom.move();;'>run</div><br class='clear' /></div>
<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>
helps with proper prototype setup, and can be used to create an inheritance
chain between any pair of constructor functions; <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>
<div class='code'><pre class="idle"><span class="FunctionName">String::dasherize </span><span class="Keyword">=</span> <span class="Keyword">-</span><span class="Keyword">&gt;</span>
@@ -1706,20 +1721,20 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
<p>
Sometimes you'd like to pass a block comment through to the generated
JavaScript. For example, when you need to embed a licensing header at
the top of a file. Block comments, which mirror the synax for heredocs,
the top of a file. Block comments, which mirror the syntax for heredocs,
are preserved in the generated code.
</p>
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">###</span></span>
<span class="Comment">CoffeeScript Compiler v1.0.0</span>
<span class="Comment">CoffeeScript Compiler v1.1.0</span>
<span class="Comment">Released under the MIT License</span>
<span class="Comment"><span class="Comment">###</span></span>
</pre><pre class="idle"><span class="Comment"><span class="Comment">/*</span></span>
<span class="Comment">CoffeeScript Compiler v1.0.0</span>
<span class="Comment">CoffeeScript Compiler v1.1.0</span>
<span class="Comment">Released under the MIT License</span>
<span class="Comment"><span class="Comment">*/</span></span>
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.0.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.1.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
<p>
<span id="regexes" class="bookmark"></span>
@@ -1829,6 +1844,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
</h2>
<ul>
<li>
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
a zero-configuration Rack server, with comprehensive annotated source.
</li>
<li>
<b>frank06</b>'s <a href="http://riakjs.org/">riak-js</a>, a Node.js client for
<a href="http://www.basho.com/Riak.html">Riak</a>, with support for HTTP
@@ -1838,6 +1857,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
<b>technoweenie</b>'s <a href="https://github.com/technoweenie/coffee-resque">Coffee-Resque</a>,
a port of <a href="https://github.com/defunkt/resque">Resque</a> for Node.js.
</li>
<li>
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
A headless, full-stack, faux-browser testing library for Node.js.
</li>
<li>
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
@@ -1851,10 +1874,6 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
<a href="http://rack.rubyforge.org/">Rack</a> server.
</li>
<li>
<b>sstephenson</b>'s <a href="http://sstephenson.github.com/strscan-js/">StringScanner</a>,
a simple tokenizer and lexical scanner for JavaScript strings.
</li>
</ul>
<h2>
@@ -1877,103 +1896,23 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
</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.
Bug reports, feature proposals, and ideas for changes to the language belong here.
</li>
<li>
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>.
<a href="https://groups.google.com/forum/#!forum/coffeescript">CoffeeScript Google Group</a><br />
If you'd like to ask a question, the mailing list is a good place to get help.
</li>
<li>
<b>satyr</b>'s <a href="http://github.com/satyr/coco">Coco</a>
&mdash; An avant-garde dialect of CoffeeScript that frequently pioneers
features and optimizations, some of which CoffeeScript later adopts.
Check out the <a href="https://github.com/satyr/coco/wiki/additions">list of additions</a>
to the language.
<a href="http://github.com/jashkenas/coffee-script/wiki">The CoffeeScript Wiki</a><br />
If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha &mdash; share it on the wiki.
The wiki also serves as a directory of handy
<a href="http://github.com/jashkenas/coffee-script/wiki/Text-editor-plugins">text editor extensions</a>,
<a href="http://github.com/jashkenas/coffee-script/wiki/Web-framework-plugins">web framework plugins</a>,
and general <a href="http://github.com/jashkenas/coffee-script/wiki/Build-tools">CoffeeScript build tools</a>.
</li>
<li>
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
&mdash; A Java Library that uses Rhino to compile CoffeeScript, allowing
compilation within Java projects or on systems that Node.js doesn't support.
</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>' <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>wavded</b>'s <a href="http://github.com/wavded/gedit-coffeescript">gedit-coffeescript</a>
&mdash; a CoffeeScript syntax highlighter for the gedit text editor.
</li>
<li>
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
&mdash; a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
</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>
<li>
<b>dsc</b>'s <a href="http://github.com/dsc/coffeecup">CoffeeCup</a>
&mdash; a Python WSGI middleware that compiles CoffeeScript to JavaScript
on-demand during development.
</li>
<li>
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
&mdash; a BistroCar alternative that integrates well with
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
</li>
<li>
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
&mdash; a custom filter for rendering CoffeeScript inline within
<a href="http://haml-lang.com/">HAML</a> templates.
</li>
<li>
<b>chrislloyd</b>'s <a href="http://github.com/chrislloyd/roast">Roast</a>
&mdash; a CoffeeScript compiler plug-in that allows you to include external
source files.
</li>
<li>
<b>andrzejsliwa</b>'s <a href="http://github.com/andrzejsliwa/coffeeapp">CoffeeApp</a>
&mdash; a CoffeeScript wrapper for CouchApps, web applications served
directly from CouchDB.
</li>
<li>
<b>sstephenson</b>'s <a href="http://github.com/sstephenson/eco">Eco</a>
&mdash; high-performance embedded CoffeeScript templates, after EJS and ERB.
</li>
<li>
<b>mauricemach</b>'s <a href="http://github.com/mauricemach/coffeekup">CoffeeKup</a>
&mdash; Markup as CoffeeScript. After _why's
<a href="http://markaby.github.com/">Markaby</a>.
</li>
<li>
<b>jashkenas</b>' <a href="http://jashkenas.github.com/docco/">Docco</a>
&mdash; a quick-and-dirty literate-programming-style documentation generator
for CoffeeScript. Used to produce the annotated source.
</li>
<li>
<b>naturalethic</b>'s <a href="http://github.com/naturalethic/coffee-mongo">coffee-mongo</a>
&mdash; an asynchronous MongoDB ORM, for use with Node.js and CoffeeScript.
</li>
<li>
<b>mauricemach</b>'s <a href="https://github.com/mauricemach/zappa">Zappa</a>
&mdash; a DSL for building web apps, built on top of Express and Socket.IO.
<a href="http://github.com/jashkenas/coffee-script/wiki/FAQ">The FAQ</a><br />
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
</li>
</ul>
@@ -1996,6 +1935,38 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
<span id="change_log" class="bookmark"></span>
Change Log
</h2>
<p>
<b class="header" style="margin-top: 20px;">1.1.0
<span class="timestamp"> &ndash; <small>May 1, 2011</small></span>
</b>
When running via <tt>coffee</tt> executable, <tt>process.argv</tt> and
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
The output in the REPL is now colorized, like Node's is.
Giving your concatenated CoffeeScripts a name when using <tt>--join</tt> is now mandatory.
Fix for lexing compound division <tt>/=</tt> as a regex accidentally.
All <tt>text/coffeescript</tt> tags should now execute in the order they're included.
Fixed an issue with extended subclasses using external constructor functions.
Fixed an edge-case infinite loop in <tt>addImplicitParentheses</tt>.
Fixed exponential slowdown with long chains of function calls.
Globals no longer leak into the CoffeeScript REPL.
Function calls can be used as default values for parameters.
Splatted parameters are declared local to the function.
</p>
<p>
<b class="header" style="margin-top: 20px;">1.0.1
<span class="timestamp"> &ndash; <small>Jan 31, 2011</small></span>
</b>
Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility
with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
Stopped requiring the core Node.js <tt>"util"</tt> module for
back-compatibility with Node.js 0.2.5. Fixed a case where a
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
statement. Optimized empty objects in destructuring assignment.
</p>
<p>
<b class="header" style="margin-top: 20px;">1.0.0
@@ -2470,7 +2441,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
$('#repl_source').keyup -> compileSource()
# Eval the compiled js.
$('.minibutton.run').click ->
evalJS = ->
try
eval window.compiledJS
catch error then alert error
@@ -2486,6 +2457,8 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
closeMenus = ->
$('.navigation.active').removeClass 'active'
$('.minibutton.run').click evalJS
# Bind navigation buttons to open the menus.
$('.navigation').click (e) ->
return if e.target.tagName.toLowerCase() is 'a'
@@ -2497,9 +2470,15 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
$(this).addClass 'active'
false
$(document.body).click (e) ->
return false if $(e.target).hasClass('minibutton')
closeMenus()
# Dismiss console if Escape pressed or click falls outside console
# Trigger Run button on Ctrl-Enter
$(document.body)
.keydown (e) ->
closeMenus() if e.which == 27
evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length
.click (e) ->
return false if $(e.target).hasClass('minibutton')
closeMenus()
$('#open_webchat').click ->
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')

View File

@@ -12,10 +12,10 @@
options.bare = true;
return Function(CoffeeScript.compile(code, options))();
};
if (typeof window == "undefined" || window === null) {
if (typeof window === "undefined" || window === null) {
return;
}
CoffeeScript.load = function(url, options) {
CoffeeScript.load = function(url, callback) {
var xhr;
xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP');
xhr.open('GET', url, true);
@@ -23,25 +23,48 @@
xhr.overrideMimeType('text/plain');
}
xhr.onreadystatechange = function() {
var _ref;
if (xhr.readyState === 4) {
return CoffeeScript.run(xhr.responseText, options);
if ((_ref = xhr.status) === 0 || _ref === 200) {
CoffeeScript.run(xhr.responseText);
} else {
throw new Error("Could not load " + url);
}
if (callback) {
return callback();
}
}
};
return xhr.send(null);
};
runScripts = function() {
var script, _i, _len, _ref;
_ref = document.getElementsByTagName('script');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
script = _ref[_i];
if (script.type === 'text/coffeescript') {
if (script.src) {
CoffeeScript.load(script.src);
} else {
CoffeeScript.run(script.innerHTML);
var coffees, execute, index, length, s, scripts;
scripts = document.getElementsByTagName('script');
coffees = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
s = scripts[_i];
if (s.type === 'text/coffeescript') {
_results.push(s);
}
}
}
return _results;
})();
index = 0;
length = coffees.length;
(execute = function() {
var script;
script = coffees[index++];
if ((script != null ? script.type : void 0) === 'text/coffeescript') {
if (script.src) {
return CoffeeScript.load(script.src, execute);
} else {
CoffeeScript.run(script.innerHTML);
return execute();
}
}
})();
return null;
};
if (window.addEventListener) {

View File

@@ -39,7 +39,7 @@
}
args = process.argv.slice(2);
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
fileName: 'Cakefile'
filename: 'Cakefile'
});
oparse = new optparse.OptionParser(switches);
if (!args.length) {

View File

@@ -1,13 +1,16 @@
(function() {
var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref;
var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref;
fs = require('fs');
path = require('path');
vm = require('vm');
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
parser = require('./parser').parser;
if (require.extensions) {
require.extensions['.coffee'] = function(module, filename) {
var content;
content = compile(fs.readFileSync(filename, 'utf8'));
content = compile(fs.readFileSync(filename, 'utf8'), {
filename: filename
});
return module._compile(content, filename);
};
} else if (require.registerExtension) {
@@ -15,7 +18,7 @@
return compile(content);
});
}
exports.VERSION = '1.0.0';
exports.VERSION = '1.1.0';
exports.RESERVED = RESERVED;
exports.helpers = require('./helpers');
exports.compile = compile = function(code, options) {
@@ -25,8 +28,8 @@
try {
return (parser.parse(lexer.tokenize(code))).compile(options);
} catch (err) {
if (options.fileName) {
err.message = "In " + options.fileName + ", " + err.message;
if (options.filename) {
err.message = "In " + options.filename + ", " + err.message;
}
throw err;
}
@@ -42,15 +45,19 @@
}
};
exports.run = function(code, options) {
var root;
var Module, root;
root = module;
while (root.parent) {
root = root.parent;
}
root.filename = fs.realpathSync(options.fileName || '.');
root.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
if (root.moduleCache) {
root.moduleCache = {};
}
if (process.binding('natives').module) {
Module = require('module').Module;
root.paths = Module._nodeModulePaths(path.dirname(options.filename));
}
if (path.extname(root.filename) !== '.coffee' || require.extensions) {
return root._compile(compile(code, options), root.filename);
} else {
@@ -58,16 +65,34 @@
}
};
exports.eval = function(code, options) {
var __dirname, __filename;
__filename = options.fileName;
__dirname = path.dirname(__filename);
return eval(compile(code, options));
var g, js, sandbox;
if (options == null) {
options = {};
}
sandbox = options.sandbox;
if (!sandbox) {
sandbox = {
require: require,
module: {
exports: {}
}
};
for (g in global) {
sandbox[g] = global[g];
}
sandbox.global = sandbox;
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox;
}
sandbox.__filename = options.filename || 'eval';
sandbox.__dirname = path.dirname(sandbox.__filename);
js = compile("_=(" + (code.trim()) + ")", options);
return vm.runInNewContext(js, sandbox, sandbox.__filename);
};
lexer = new Lexer;
parser.lexer = {
lex: function() {
var tag, _ref;
_ref = this.tokens[this.pos++] || [''], tag = _ref[0], this.yytext = _ref[1], this.yylineno = _ref[2];
var tag, _ref2;
_ref2 = this.tokens[this.pos++] || [''], tag = _ref2[0], this.yytext = _ref2[1], this.yylineno = _ref2[2];
return tag;
},
setInput: function(tokens) {

View File

@@ -1,8 +1,7 @@
(function() {
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, util, version, watch, writeJs, _ref;
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, loadRequires, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, version, watch, writeJs, _ref;
fs = require('fs');
path = require('path');
util = require('util');
helpers = require('./helpers');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
@@ -16,7 +15,7 @@
return process.binding('stdio').writeError(line + '\n');
};
BANNER = 'Usage: coffee [options] path/to/script.coffee';
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'], ['-j', '--join', 'concatenate the scripts before compiling'], ['-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'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', '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'], ['--nodejs [ARGS]', 'pass options through to the "node" binary'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
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'], ['-j', '--join [FILE]', 'concatenate the scripts before compiling'], ['-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'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', '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'], ['--nodejs [ARGS]', 'pass options through to the "node" binary'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
opts = {};
sources = [];
contents = [];
@@ -32,6 +31,9 @@
if (opts.version) {
return version();
}
if (opts.require) {
loadRequires();
}
if (opts.interactive) {
return require('./repl');
}
@@ -48,6 +50,8 @@
opts.literals = sources.splice(1).concat(opts.literals);
}
process.ARGV = process.argv = process.argv.slice(0, 2).concat(opts.literals);
process.argv[0] = 'coffee';
process.execPath = process.mainModule.filename;
return compileScripts();
};
compileScripts = function() {
@@ -58,25 +62,28 @@
base = path.join(source);
compile = function(source, topLevel) {
return path.exists(source, function(exists) {
if (!exists) {
if (topLevel && !exists) {
throw new Error("File not found: " + source);
}
return fs.stat(source, function(err, stats) {
if (err) {
throw err;
}
if (stats.isDirectory()) {
return fs.readdir(source, function(err, files) {
var file, _i, _len, _results;
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
_results.push(compile(path.join(source, file)));
var file, _j, _len2, _results2;
_results2 = [];
for (_j = 0, _len2 = files.length; _j < _len2; _j++) {
file = files[_j];
_results2.push(compile(path.join(source, file)));
}
return _results;
return _results2;
});
} else if (topLevel || path.extname(source) === '.coffee') {
fs.readFile(source, function(err, code) {
if (opts.join) {
contents[sources.indexOf(source)] = code.toString();
if (helpers.compact(contents).length === sources.length) {
if (helpers.compact(contents).length > 0) {
return compileJoin();
}
} else {
@@ -95,16 +102,9 @@
return _results;
};
compileScript = function(file, input, base) {
var o, options, req, t, task, _i, _len, _ref;
var o, options, t, task;
o = opts;
options = compileOptions(file);
if (o.require) {
_ref = o.require;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
req = _ref[_i];
require(helpers.starts(req, '.') ? fs.realpathSync(req) : req);
}
}
try {
t = task = {
file: file,
@@ -157,7 +157,18 @@
compileJoin = function() {
var code;
code = contents.join('\n');
return compileScript("concatenation", code, "concatenation");
return compileScript(opts.join, code, opts.join);
};
loadRequires = function() {
var realFilename, req, _i, _len, _ref2;
realFilename = module.filename;
module.filename = '.';
_ref2 = opts.require;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
req = _ref2[_i];
require(req);
}
return module.filename = realFilename;
};
watch = function(source, base) {
return fs.watchFile(source, {
@@ -190,7 +201,7 @@
if (err) {
return printLine(err.message);
} else if (opts.compile && opts.watch) {
return util.log("compiled " + source);
return console.log("" + ((new Date).toLocaleTimeString()) + " - compiled " + source);
}
});
};
@@ -217,11 +228,11 @@
printTokens = function(tokens) {
var strings, tag, token, value;
strings = (function() {
var _i, _len, _ref, _results;
var _i, _len, _ref2, _results;
_results = [];
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
token = tokens[_i];
_ref = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref[0], value = _ref[1];
_ref2 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref2[0], value = _ref2[1];
_results.push("[" + tag + " " + value + "]");
}
return _results;
@@ -237,9 +248,9 @@
o.print = !!(o.print || (o.eval || o.stdio && o.compile));
return sources = o.arguments;
};
compileOptions = function(fileName) {
compileOptions = function(filename) {
return {
fileName: fileName,
filename: filename,
bare: opts.bare
};
};
@@ -255,11 +266,9 @@
});
};
usage = function() {
printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
return process.exit(0);
return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
};
version = function() {
printLine("CoffeeScript version " + CoffeeScript.VERSION);
return process.exit(0);
return printLine("CoffeeScript version " + CoffeeScript.VERSION);
};
}).call(this);

View File

@@ -10,18 +10,18 @@
}
action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
action = action.replace(/\bnew /g, '$&yy.');
action = action.replace(/\b(?:Expressions\.wrap|extend)\b/g, 'yy.$&');
action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
return [patternString, "$$ = " + action + ";", options];
};
grammar = {
Root: [
o('', function() {
return new Expressions;
return new Block;
}), o('Body'), o('Block TERMINATOR')
],
Body: [
o('Line', function() {
return Expressions.wrap([$1]);
return Block.wrap([$1]);
}), o('Body TERMINATOR Line', function() {
return $1.push($3);
}), o('Body TERMINATOR')
@@ -35,7 +35,7 @@
Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class')],
Block: [
o('INDENT OUTDENT', function() {
return new Expressions;
return new Block;
}), o('INDENT Body OUTDENT', function() {
return $2;
})
@@ -58,7 +58,12 @@
}), o('REGEX', function() {
return new Literal($1);
}), o('BOOL', function() {
return new Literal($1 === 'undefined' ? 'void 0' : $1);
var val;
val = new Literal($1);
if ($1 === 'undefined') {
val.isUndefined = true;
}
return val;
})
],
Assign: [
@@ -164,13 +169,11 @@
return new Access($2, 'proto');
}), o('::', function() {
return new Access(new Literal('prototype'));
}), o('Index'), o('Slice', function() {
return new Slice($1);
})
}), o('Index')
],
Index: [
o('INDEX_START Expression INDEX_END', function() {
return new Index($2);
o('INDEX_START IndexValue INDEX_END', function() {
return $2;
}), o('INDEX_SOAK Index', function() {
return extend($2, {
soak: true
@@ -181,6 +184,13 @@
});
})
],
IndexValue: [
o('Expression', function() {
return new Index($1);
}), o('Slice', function() {
return new Slice($1);
})
],
Object: [
o('{ AssignList OptComma }', function() {
return new Obj($2, $1.generated);
@@ -275,12 +285,12 @@
})
],
Slice: [
o('INDEX_START Expression RangeDots Expression INDEX_END', function() {
return new Range($2, $4, $3);
}), o('INDEX_START Expression RangeDots INDEX_END', function() {
return new Range($2, null, $3);
}), o('INDEX_START RangeDots Expression INDEX_END', function() {
return new Range(null, $3, $2);
o('Expression RangeDots Expression', function() {
return new Range($1, $3, $2);
}), o('Expression RangeDots', function() {
return new Range($1, null, $2);
}), o('RangeDots Expression', function() {
return new Range(null, $2, $1);
})
],
ArgList: [
@@ -352,9 +362,9 @@
o('WhileSource Block', function() {
return $1.addBody($2);
}), o('Statement WhileSource', function() {
return $2.addBody(Expressions.wrap([$1]));
return $2.addBody(Block.wrap([$1]));
}), o('Expression WhileSource', function() {
return $2.addBody(Expressions.wrap([$1]));
return $2.addBody(Block.wrap([$1]));
}), o('Loop', function() {
return $1;
})
@@ -363,7 +373,7 @@
o('LOOP Block', function() {
return new While(new Literal('true')).addBody($2);
}), o('LOOP Expression', function() {
return new While(new Literal('true')).addBody(Expressions.wrap([$2]));
return new While(new Literal('true')).addBody(Block.wrap([$2]));
})
],
For: [
@@ -481,18 +491,18 @@
return $1.addElse(new If($4, $5, {
type: $3
}));
}), o('IfBlock ELSE Block', function() {
return $1.addElse($3);
})
],
If: [
o('IfBlock'), o('Statement POST_IF Expression', function() {
return new If($3, Expressions.wrap([$1]), {
o('IfBlock'), o('IfBlock ELSE Block', function() {
return $1.addElse($3);
}), o('Statement POST_IF Expression', function() {
return new If($3, Block.wrap([$1]), {
type: $2,
statement: true
});
}), o('Expression POST_IF Expression', function() {
return new If($3, Expressions.wrap([$1]), {
return new If($3, Block.wrap([$1]), {
type: $2,
statement: true
});

View File

@@ -1,5 +1,5 @@
(function() {
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, last, op, starts, _ref;
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref;
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
@@ -15,6 +15,9 @@
if (opts == null) {
opts = {};
}
if (WHITESPACE.test(code)) {
code = "\n" + code;
}
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
this.code = code;
this.line = opts.line || 0;
@@ -34,7 +37,7 @@
return (new Rewriter).rewrite(this.tokens);
};
Lexer.prototype.identifierToken = function() {
var colon, forcedIdentifier, id, input, match, prev, tag, _ref, _ref2;
var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return 0;
}
@@ -43,11 +46,11 @@
this.token('OWN', id);
return id.length;
}
forcedIdentifier = colon || (prev = last(this.tokens)) && !prev.spaced && ((_ref = prev[0]) === '.' || _ref === '?.' || _ref === '@' || _ref === '::');
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
tag = 'IDENTIFIER';
if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) {
tag = id.toUpperCase();
if (tag === 'WHEN' && (_ref2 = this.tag(), __indexOf.call(LINE_BREAK, _ref2) >= 0)) {
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
@@ -78,8 +81,8 @@
}
}
if (!forcedIdentifier) {
if (COFFEE_ALIASES.hasOwnProperty(id)) {
id = COFFEE_ALIASES[id];
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
id = COFFEE_ALIAS_MAP[id];
}
tag = (function() {
switch (id) {
@@ -172,7 +175,6 @@
return 0;
}
comment = match[0], here = match[1];
this.line += count(comment, '\n');
if (here) {
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
herecomment: true,
@@ -180,6 +182,7 @@
}));
this.token('TERMINATOR', '\n');
}
this.line += count(comment, '\n');
return comment.length;
};
Lexer.prototype.jsToken = function() {
@@ -191,7 +194,7 @@
return script.length;
};
Lexer.prototype.regexToken = function() {
var match, prev, regex, _ref;
var match, prev, regex, _ref2;
if (this.chunk.charAt(0) !== '/') {
return 0;
}
@@ -199,7 +202,7 @@
return this.heregexToken(match);
}
prev = last(this.tokens);
if (prev && (_ref = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref) >= 0)) {
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
return 0;
}
if (!(match = REGEX.exec(this.chunk))) {
@@ -210,7 +213,7 @@
return regex.length;
};
Lexer.prototype.heregexToken = function(match) {
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _ref4;
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
heregex = match[0], body = match[1], flags = match[2];
if (0 > body.indexOf('#{')) {
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
@@ -220,11 +223,11 @@
this.token('IDENTIFIER', 'RegExp');
this.tokens.push(['CALL_START', '(']);
tokens = [];
_ref = this.interpolateString(body, {
_ref2 = this.interpolateString(body, {
regex: true
});
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
_ref2 = _ref[_i], tag = _ref2[0], value = _ref2[1];
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
_ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
if (tag === 'TOKENS') {
tokens.push.apply(tokens, value);
} else {
@@ -237,10 +240,10 @@
tokens.push(['+', '+']);
}
tokens.pop();
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') {
if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
this.tokens.push(['STRING', '""'], ['+', '+']);
}
(_ref4 = this.tokens).push.apply(_ref4, tokens);
(_ref5 = this.tokens).push.apply(_ref5, tokens);
if (flags) {
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
}
@@ -337,7 +340,7 @@
return this;
};
Lexer.prototype.literalToken = function() {
var match, prev, tag, value, _ref, _ref2, _ref3, _ref4;
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
if (match = OPERATOR.exec(this.chunk)) {
value = match[0];
if (CODE.test(value)) {
@@ -349,10 +352,10 @@
tag = value;
prev = last(this.tokens);
if (value === '=' && prev) {
if (!prev[1].reserved && (_ref = prev[1], __indexOf.call(JS_FORBIDDEN, _ref) >= 0)) {
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
this.assignmentError();
}
if ((_ref2 = prev[1]) === '||' || _ref2 === '&&') {
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
prev[0] = 'COMPOUND_ASSIGN';
prev[1] += '=';
return value.length;
@@ -373,12 +376,12 @@
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
tag = 'LOGIC';
} else if (prev && !prev.spaced) {
if (value === '(' && (_ref3 = prev[0], __indexOf.call(CALLABLE, _ref3) >= 0)) {
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
tag = 'CALL_START';
} else if (value === '[' && (_ref4 = prev[0], __indexOf.call(INDEXABLE, _ref4) >= 0)) {
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
tag = 'INDEX_START';
switch (prev[0]) {
case '?':
@@ -393,15 +396,19 @@
return value.length;
};
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
var attempt, herecomment, indent, match, _ref;
var attempt, herecomment, indent, match, _ref2;
indent = options.indent, herecomment = options.herecomment;
if (herecomment && 0 > doc.indexOf('\n')) {
return doc;
}
if (!herecomment) {
if (herecomment) {
if (HEREDOC_ILLEGAL.test(doc)) {
throw new Error("block comment cannot contain \"*/\", starting on line " + (this.line + 1));
}
if (doc.indexOf('\n') <= 0) {
return doc;
}
} else {
while (match = HEREDOC_INDENT.exec(doc)) {
attempt = match[1];
if (indent === null || (0 < (_ref = attempt.length) && _ref < indent.length)) {
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
indent = attempt;
}
}
@@ -432,7 +439,7 @@
case 'CALL_START':
if (stack.length) {
stack.pop();
} else {
} else if (tok[0] === '(') {
tok[0] = 'PARAM_START';
return this;
}
@@ -450,9 +457,9 @@
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
};
Lexer.prototype.balancedString = function(str, end) {
var i, letter, prev, stack, _ref;
var i, letter, prev, stack, _ref2;
stack = [end];
for (i = 1, _ref = str.length; (1 <= _ref ? i < _ref : i > _ref); (1 <= _ref ? i += 1 : i -= 1)) {
for (i = 1, _ref2 = str.length; 1 <= _ref2 ? i < _ref2 : i > _ref2; 1 <= _ref2 ? i++ : i--) {
switch (letter = str.charAt(i)) {
case '\\':
i++;
@@ -477,7 +484,7 @@
throw new Error("missing " + (stack.pop()) + ", starting on line " + (this.line + 1));
};
Lexer.prototype.interpolateString = function(str, options) {
var expr, heredoc, i, inner, interpolated, letter, nested, pi, regex, tag, tokens, value, _len, _ref, _ref2, _ref3;
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref2, _ref3, _ref4;
if (options == null) {
options = {};
}
@@ -503,14 +510,16 @@
rewrite: false
});
nested.pop();
if (((_ref = nested[0]) != null ? _ref[0] : void 0) === 'TERMINATOR') {
if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
nested.shift();
}
if (nested.length > 1) {
nested.unshift(['(', '(']);
nested.push([')', ')']);
if (len = nested.length) {
if (len > 1) {
nested.unshift(['(', '(']);
nested.push([')', ')']);
}
tokens.push(['TOKENS', nested]);
}
tokens.push(['TOKENS', nested]);
}
i += expr.length;
pi = i + 1;
@@ -531,12 +540,12 @@
this.token('(', '(');
}
for (i = 0, _len = tokens.length; i < _len; i++) {
_ref2 = tokens[i], tag = _ref2[0], value = _ref2[1];
_ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
if (i) {
this.token('+', '+');
}
if (tag === 'TOKENS') {
(_ref3 = this.tokens).push.apply(_ref3, value);
(_ref4 = this.tokens).push.apply(_ref4, value);
} else {
this.token('STRING', this.makeString(value, '"', heredoc));
}
@@ -582,7 +591,7 @@
})();
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
for (op in COFFEE_ALIASES = {
COFFEE_ALIAS_MAP = {
and: '&&',
or: '||',
is: '==',
@@ -592,13 +601,20 @@
no: 'false',
on: 'true',
off: 'false'
}) {
COFFEE_KEYWORDS.push(op);
}
};
COFFEE_ALIASES = (function() {
var _results;
_results = [];
for (key in COFFEE_ALIAS_MAP) {
_results.push(key);
}
return _results;
})();
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf'];
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS);
IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
@@ -608,13 +624,14 @@
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
REGEX = /^\/(?!\s)[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
REGEX = /^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
HEREGEX_OMIT = /\s+(?:#.*)?/g;
MULTILINER = /\n/g;
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
LINE_CONTINUER = /^\s*(?:,|\??\.(?!\.)|::)/;
HEREDOC_ILLEGAL = /\*\//;
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
TRAILING_SPACES = /\s+$/;
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@
};
OptionParser.prototype.help = function() {
var letPart, lines, rule, spaces, _i, _len, _ref;
lines = ['Available options:'];
lines = [];
if (this.banner) {
lines.unshift("" + this.banner + "\n");
}

File diff suppressed because one or more lines are too long

View File

@@ -1,41 +1,113 @@
(function() {
var CoffeeScript, error, helpers, readline, repl, run, stdio;
var ACCESSOR, CoffeeScript, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, getPropertyNames, inspect, readline, repl, run, stdin, stdout;
var __hasProp = Object.prototype.hasOwnProperty;
CoffeeScript = require('./coffee-script');
helpers = require('./helpers');
readline = require('readline');
stdio = process.openStdin();
inspect = require('util').inspect;
Script = require('vm').Script;
enableColours = false;
if (process.platform !== 'win32') {
enableColours = !process.env.NODE_DISABLE_COLORS;
}
stdin = process.openStdin();
stdout = process.stdout;
error = function(err) {
return stdio.write((err.stack || err.toString()) + '\n\n');
return stdout.write((err.stack || err.toString()) + '\n\n');
};
helpers.extend(global, {
quit: function() {
return process.exit(0);
}
});
run = function(buffer) {
var val;
try {
val = CoffeeScript.eval(buffer.toString(), {
bare: true,
globals: true,
fileName: 'repl'
});
if (val !== void 0) {
console.log(val);
backlog = '';
run = (function() {
var g, sandbox;
sandbox = {
require: require,
module: {
exports: {}
}
} catch (err) {
error(err);
};
for (g in global) {
sandbox[g] = global[g];
}
return repl.prompt();
sandbox.global = sandbox;
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox;
return function(buffer) {
var code, val;
code = backlog += '\n' + buffer.toString();
if (code[code.length - 1] === '\\') {
return backlog = backlog.slice(0, backlog.length - 1);
}
backlog = '';
try {
val = CoffeeScript.eval(code, {
sandbox: sandbox,
bare: true,
filename: 'repl'
});
if (val !== void 0) {
process.stdout.write(inspect(val, false, 2, enableColours) + '\n');
}
} catch (err) {
error(err);
}
return repl.prompt();
};
})();
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
SIMPLEVAR = /\s*(\w*)$/i;
autocomplete = function(text) {
return completeAttribute(text) || completeVariable(text) || [[], text];
};
completeAttribute = function(text) {
var all, completions, match, obj, prefix, val;
if (match = text.match(ACCESSOR)) {
all = match[0], obj = match[1], prefix = match[2];
try {
val = Script.runInThisContext(obj);
} catch (error) {
return [[], text];
}
completions = getCompletions(prefix, getPropertyNames(val));
return [completions, prefix];
}
};
completeVariable = function(text) {
var completions, free, scope, _ref;
if (free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0) {
scope = Script.runInThisContext('this');
completions = getCompletions(free, CoffeeScript.RESERVED.concat(getPropertyNames(scope)));
return [completions, free];
}
};
getCompletions = function(prefix, candidates) {
var el, _i, _len, _results;
_results = [];
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
el = candidates[_i];
if (el.indexOf(prefix) === 0) {
_results.push(el);
}
}
return _results;
};
getPropertyNames = function(obj) {
var name, _results;
_results = [];
for (name in obj) {
if (!__hasProp.call(obj, name)) continue;
_results.push(name);
}
return _results;
};
process.on('uncaughtException', error);
repl = readline.createInterface(stdio);
if (readline.createInterface.length < 3) {
repl = readline.createInterface(stdin, autocomplete);
stdin.on('data', function(buffer) {
return repl.write(buffer);
});
} else {
repl = readline.createInterface(stdin, stdout, autocomplete);
}
repl.setPrompt('coffee> ');
stdio.on('data', function(buffer) {
return repl.write(buffer);
});
repl.on('close', function() {
return stdio.destroy();
return stdin.destroy();
});
repl.on('line', run);
repl.prompt();

View File

@@ -121,7 +121,10 @@
return ((tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':')) || (tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT'));
};
action = function(token, i) {
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
var tok;
tok = ['}', '}', token[2]];
tok.generated = true;
return this.tokens.splice(i, 0, tok);
};
return this.scanTokens(function(token, i, tokens) {
var ago, idx, tag, tok, value, _ref, _ref2;
@@ -173,12 +176,15 @@
if (prev && !prev.spaced && tag === '?') {
token.call = true;
}
if (token.fromThen) {
return 1;
}
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref3 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref3) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
return 1;
}
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
this.detectEnd(i + 1, function(token, i) {
var post, _ref;
var post, _ref4;
tag = token[0];
if (!seenSingle && token.fromThen) {
return true;
@@ -189,7 +195,7 @@
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref4 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref4) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
}, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
@@ -222,8 +228,8 @@
indent.generated = outdent.generated = true;
tokens.splice(i + 1, 0, indent);
condition = function(token, i) {
var _ref;
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
var _ref3;
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
};
action = function(token, i) {
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);

View File

@@ -46,12 +46,12 @@
return this.add(name, 'param');
};
Scope.prototype.check = function(name, immediate) {
var found, _ref;
var found, _ref2;
found = !!this.type(name);
if (found || immediate) {
return found;
}
return !!((_ref = this.parent) != null ? _ref.check(name) : void 0);
return !!((_ref2 = this.parent) != null ? _ref2.check(name) : void 0);
};
Scope.prototype.temporary = function(name, index) {
if (name.length > 1) {
@@ -61,10 +61,10 @@
}
};
Scope.prototype.type = function(name) {
var v, _i, _len, _ref;
_ref = this.variables;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
v = _ref[_i];
var v, _i, _len, _ref2;
_ref2 = this.variables;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
v = _ref2[_i];
if (v.name === name) {
return v.type;
}
@@ -74,7 +74,7 @@
Scope.prototype.freeVariable = function(type) {
var index, temp;
index = 0;
while (this.check((temp = this.temporary(type, index)), true)) {
while (this.check((temp = this.temporary(type, index)))) {
index++;
}
this.add(temp, 'var', true);
@@ -91,12 +91,12 @@
return !!this.declaredVariables().length;
};
Scope.prototype.declaredVariables = function() {
var realVars, tempVars, v, _i, _len, _ref;
var realVars, tempVars, v, _i, _len, _ref2;
realVars = [];
tempVars = [];
_ref = this.variables;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
v = _ref[_i];
_ref2 = this.variables;
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
v = _ref2[_i];
if (v.type === 'var') {
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
}
@@ -104,11 +104,11 @@
return realVars.sort().concat(tempVars.sort());
};
Scope.prototype.assignedVariables = function() {
var v, _i, _len, _ref, _results;
_ref = this.variables;
var v, _i, _len, _ref2, _results;
_ref2 = this.variables;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
v = _ref[_i];
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
v = _ref2[_i];
if (v.type.assigned) {
_results.push("" + v.name + " = " + v.type.value);
}

View File

@@ -1,22 +1,27 @@
{
"name": "coffee-script",
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language", "coffeescript", "compiler"],
"author": "Jeremy Ashkenas",
"version": "1.0.0",
"licenses": [{
"type": "MIT",
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
}],
"engines": {
"node": ">=0.2.5"
},
"directories" : {
"lib" : "./lib"
},
"main" : "./lib/coffee-script",
"bin": {
"coffee": "./bin/coffee",
"cake": "./bin/cake"
}
"name": "coffee-script",
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language", "coffeescript", "compiler"],
"author": "Jeremy Ashkenas",
"version": "1.1.0",
"licenses": [{
"type": "MIT",
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
}],
"engines": {
"node": ">=0.2.5"
},
"directories" : {
"lib" : "./lib"
},
"main" : "./lib/coffee-script",
"bin": {
"coffee": "./bin/coffee",
"cake": "./bin/cake"
},
"homepage": "http://coffeescript.org",
"repository": {
"type": "git",
"url": "git://github.com/jashkenas/coffee-script.git"
}
}

View File

@@ -16,24 +16,35 @@ CoffeeScript.run = (code, options = {}) ->
return unless window?
# Load a remote script from the current domain via XHR.
CoffeeScript.load = (url, options) ->
CoffeeScript.load = (url, callback) ->
xhr = new (window.ActiveXObject or XMLHttpRequest)('Microsoft.XMLHTTP')
xhr.open 'GET', url, true
xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr
xhr.onreadystatechange = ->
CoffeeScript.run xhr.responseText, options if xhr.readyState is 4
if xhr.readyState is 4
if xhr.status in [0, 200]
CoffeeScript.run xhr.responseText
else
throw new Error "Could not load #{url}"
callback() if callback
xhr.send null
# 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.
runScripts = ->
for script in document.getElementsByTagName 'script'
if script.type is 'text/coffeescript'
scripts = document.getElementsByTagName 'script'
coffees = (s for s in scripts when s.type is 'text/coffeescript')
index = 0
length = coffees.length
do execute = ->
script = coffees[index++]
if script?.type is 'text/coffeescript'
if script.src
CoffeeScript.load script.src
CoffeeScript.load script.src, execute
else
CoffeeScript.run script.innerHTML
execute()
null
# Listen for window load, both in browsers and in IE.

View File

@@ -47,7 +47,7 @@ exports.run = ->
path.exists 'Cakefile', (exists) ->
throw new Error("Cakefile not found in #{process.cwd()}") unless exists
args = process.argv.slice 2
CoffeeScript.run fs.readFileSync('Cakefile').toString(), fileName: 'Cakefile'
CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
oparse = new optparse.OptionParser switches
return printTasks() unless args.length
options = oparse.parse(args)

View File

@@ -8,19 +8,20 @@
fs = require 'fs'
path = require 'path'
vm = require 'vm'
{Lexer,RESERVED} = require './lexer'
{parser} = require './parser'
# TODO: Remove registerExtension when fully deprecated.
if require.extensions
require.extensions['.coffee'] = (module, filename) ->
content = compile fs.readFileSync filename, 'utf8'
content = compile fs.readFileSync(filename, 'utf8'), {filename}
module._compile content, filename
else if require.registerExtension
require.registerExtension '.coffee', (content) -> compile content
# The current CoffeeScript version number.
exports.VERSION = '1.0.0'
exports.VERSION = '1.1.0'
# Words that cannot be used as identifiers in CoffeeScript code
exports.RESERVED = RESERVED
@@ -34,7 +35,7 @@ exports.compile = compile = (code, options = {}) ->
try
(parser.parse lexer.tokenize code).compile options
catch err
err.message = "In #{options.fileName}, #{err.message}" if options.fileName
err.message = "In #{options.filename}, #{err.message}" if options.filename
throw err
# Tokenize a string of CoffeeScript code, and return the array of tokens.
@@ -57,10 +58,19 @@ exports.run = (code, options) ->
root = module
while root.parent
root = root.parent
# Set the filename.
root.filename = fs.realpathSync options.fileName or '.'
root.filename = process.argv[1] =
if options.filename then fs.realpathSync(options.filename) else '.'
# Clear the module cache.
root.moduleCache = {} if root.moduleCache
# Assign paths for node_modules loading
if process.binding('natives').module
{Module} = require 'module'
root.paths = Module._nodeModulePaths path.dirname options.filename
# Compile.
if path.extname(root.filename) isnt '.coffee' or require.extensions
root._compile compile(code, options), root.filename
@@ -69,10 +79,19 @@ exports.run = (code, options) ->
# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
# The CoffeeScript REPL uses this to run the input.
exports.eval = (code, options) ->
__filename = options.fileName
__dirname = path.dirname __filename
eval compile code, options
exports.eval = (code, options = {}) ->
sandbox = options.sandbox
unless sandbox
sandbox =
require: require
module : { exports: {} }
sandbox[g] = global[g] for g of global
sandbox.global = sandbox
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
sandbox.__filename = options.filename || 'eval'
sandbox.__dirname = path.dirname sandbox.__filename
js = compile "_=(#{code.trim()})", options
vm.runInNewContext js, sandbox, sandbox.__filename
# Instantiate a Lexer for our use here.
lexer = new Lexer

View File

@@ -7,7 +7,6 @@
# External dependencies.
fs = require 'fs'
path = require 'path'
util = require 'util'
helpers = require './helpers'
optparse = require './optparse'
CoffeeScript = require './coffee-script'
@@ -30,7 +29,7 @@ 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']
['-j', '--join', 'concatenate the scripts before compiling']
['-j', '--join [FILE]', 'concatenate the scripts before compiling']
['-w', '--watch', 'watch scripts for changes, and recompile']
['-p', '--print', 'print the compiled JavaScript to stdout']
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
@@ -59,6 +58,7 @@ exports.run = ->
return forkNode() if opts.nodejs
return usage() if opts.help
return version() if opts.version
loadRequires() if opts.require
return require './repl' if opts.interactive
return compileStdio() if opts.stdio
return compileScript null, sources[0] if opts.eval
@@ -66,6 +66,8 @@ exports.run = ->
if opts.run
opts.literals = sources.splice(1).concat opts.literals
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
process.argv[0] = 'coffee'
process.execPath = process.mainModule.filename
compileScripts()
# Asynchronously read in each CoffeeScript in a list of source files and
@@ -76,8 +78,9 @@ compileScripts = ->
base = path.join(source)
compile = (source, topLevel) ->
path.exists source, (exists) ->
throw new Error "File not found: #{source}" unless exists
throw new Error "File not found: #{source}" if topLevel and not exists
fs.stat source, (err, stats) ->
throw err if err
if stats.isDirectory()
fs.readdir source, (err, files) ->
for file in files
@@ -86,7 +89,7 @@ compileScripts = ->
fs.readFile source, (err, code) ->
if opts.join
contents[sources.indexOf source] = code.toString()
compileJoin() if helpers.compact(contents).length is sources.length
compileJoin() if helpers.compact(contents).length > 0
else
compileScript(source, code.toString(), base)
watch source, base if opts.watch and not opts.join
@@ -98,8 +101,6 @@ compileScripts = ->
compileScript = (file, input, base) ->
o = opts
options = compileOptions file
if o.require
require(if helpers.starts(req, '.') then fs.realpathSync(req) else req) for req in o.require
try
t = task = {file, input, options}
CoffeeScript.emit 'compile', task
@@ -133,7 +134,14 @@ compileStdio = ->
# them together.
compileJoin = ->
code = contents.join '\n'
compileScript "concatenation", code, "concatenation"
compileScript opts.join, code, opts.join
# Load files that are to-be-required before compilation occurs.
loadRequires = ->
realFilename = module.filename
module.filename = '.'
require req for req in opts.require
module.filename = realFilename
# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
# time the file is updated. May be used in combination with other options,
@@ -157,8 +165,10 @@ writeJs = (source, js, base) ->
compile = ->
js = ' ' if js.length <= 0
fs.writeFile jsPath, js, (err) ->
if err then printLine err.message
else if opts.compile and opts.watch then util.log "compiled #{source}"
if err
printLine err.message
else if opts.compile and opts.watch
console.log "#{(new Date).toLocaleTimeString()} - compiled #{source}"
path.exists dir, (exists) ->
if exists then compile() else exec "mkdir -p #{dir}", compile
@@ -191,7 +201,7 @@ parseOptions = ->
sources = o.arguments
# The compile-time options to pass to the CoffeeScript compiler.
compileOptions = (fileName) -> {fileName, bare: opts.bare}
compileOptions = (filename) -> {filename, bare: opts.bare}
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
# the `node` binary, preserving the other options.
@@ -208,9 +218,7 @@ forkNode = ->
# shown.
usage = ->
printLine (new optparse.OptionParser SWITCHES, BANNER).help()
process.exit 0
# Print the `--version` message and exit.
version = ->
printLine "CoffeeScript version #{CoffeeScript.VERSION}"
process.exit 0

View File

@@ -35,7 +35,7 @@ o = (patternString, action, options) ->
return [patternString, '$$ = $1;', options] unless action
action = if match = unwrap.exec action then match[1] else "(#{action}())"
action = action.replace /\bnew /g, '$&yy.'
action = action.replace /\b(?:Expressions\.wrap|extend)\b/g, 'yy.$&'
action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
[patternString, "$$ = #{action};", options]
# Grammatical Rules
@@ -56,19 +56,19 @@ grammar =
# 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 '', -> new Block
o 'Body'
o 'Block TERMINATOR'
]
# Any list of statements and expressions, separated by line breaks or semicolons.
Body: [
o 'Line', -> Expressions.wrap [$1]
o 'Line', -> Block.wrap [$1]
o 'Body TERMINATOR Line', -> $1.push $3
o 'Body TERMINATOR'
]
# Expressions and statements, which make up a line in a body.
# Block and statements, which make up a line in a body.
Line: [
o 'Expression'
o 'Statement'
@@ -84,7 +84,7 @@ grammar =
# All the different types of expressions in our language. The basic unit of
# CoffeeScript is the **Expression** -- everything that can be an expression
# is one. Expressions serve as the building blocks of many other rules, making
# is one. Block serve as the building blocks of many other rules, making
# them somewhat circular.
Expression: [
o 'Value'
@@ -104,7 +104,7 @@ grammar =
# will convert some postfix forms into blocks for us, by adjusting the
# token stream.
Block: [
o 'INDENT OUTDENT', -> new Expressions
o 'INDENT OUTDENT', -> new Block
o 'INDENT Body OUTDENT', -> $2
]
@@ -127,7 +127,9 @@ grammar =
o 'JS', -> new Literal $1
o 'REGEX', -> new Literal $1
o 'BOOL', ->
new Literal if $1 is 'undefined' then 'void 0' else $1
val = new Literal $1
val.isUndefined = yes if $1 is 'undefined'
val
]
# Assignment of a variable, property, or index to a value.
@@ -164,7 +166,7 @@ grammar =
]
# 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
# of **Block** preceded by a function arrow, with an optional parameter
# list.
Code: [
o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4
@@ -244,15 +246,19 @@ grammar =
o ':: Identifier', -> new Access $2, 'proto'
o '::', -> new Access new Literal 'prototype'
o 'Index'
o 'Slice', -> new Slice $1
]
# Indexing into an object or array using bracket notation.
Index: [
o 'INDEX_START Expression INDEX_END', -> new Index $2
o 'INDEX_START IndexValue INDEX_END', -> $2
o 'INDEX_SOAK Index', -> extend $2, soak : yes
o 'INDEX_PROTO Index', -> extend $2, proto: yes
]
IndexValue: [
o 'Expression', -> new Index $1
o 'Slice', -> new Slice $1
]
# In CoffeeScript, an object literal is simply a list of assignments.
Object: [
@@ -332,9 +338,9 @@ grammar =
# Array slice literals.
Slice: [
o 'INDEX_START Expression RangeDots Expression INDEX_END', -> new Range $2, $4, $3
o 'INDEX_START Expression RangeDots INDEX_END', -> new Range $2, null, $3
o 'INDEX_START RangeDots Expression INDEX_END', -> new Range null, $3, $2
o 'Expression RangeDots Expression', -> new Range $1, $3, $2
o 'Expression RangeDots', -> new Range $1, null, $2
o 'RangeDots Expression', -> new Range null, $2, $1
]
# The **ArgList** is both the list of objects passed into a function call,
@@ -348,7 +354,7 @@ grammar =
o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
]
# Valid arguments are Expressions or Splats.
# Valid arguments are Block or Splats.
Arg: [
o 'Expression'
o 'Splat'
@@ -401,14 +407,14 @@ grammar =
# or postfix, with a single expression. There is no do..while.
While: [
o 'WhileSource Block', -> $1.addBody $2
o 'Statement WhileSource', -> $2.addBody Expressions.wrap [$1]
o 'Expression WhileSource', -> $2.addBody Expressions.wrap [$1]
o 'Statement WhileSource', -> $2.addBody Block.wrap [$1]
o 'Expression WhileSource', -> $2.addBody Block.wrap [$1]
o 'Loop', -> $1
]
Loop: [
o 'LOOP Block', -> new While(new Literal 'true').addBody $2
o 'LOOP Expression', -> new While(new Literal 'true').addBody Expressions.wrap [$2]
o 'LOOP Expression', -> new While(new Literal 'true').addBody Block.wrap [$2]
]
# Array, object, and range comprehensions, at the most generic level.
@@ -483,15 +489,15 @@ grammar =
IfBlock: [
o 'IF Expression Block', -> new If $2, $3, type: $1
o 'IfBlock ELSE IF Expression Block', -> $1.addElse new If $4, $5, type: $3
o 'IfBlock ELSE Block', -> $1.addElse $3
]
# The full complement of *if* expressions, including postfix one-liner
# *if* and *unless*.
If: [
o 'IfBlock'
o 'Statement POST_IF Expression', -> new If $3, Expressions.wrap([$1]), type: $2, statement: true
o 'Expression POST_IF Expression', -> new If $3, Expressions.wrap([$1]), type: $2, statement: true
o 'IfBlock ELSE Block', -> $1.addElse $3
o 'Statement POST_IF Expression', -> new If $3, Block.wrap([$1]), type: $2, statement: true
o 'Expression POST_IF Expression', -> new If $3, Block.wrap([$1]), type: $2, statement: true
]
# Arithmetic and logical operators, working on one or more operands.

View File

@@ -32,6 +32,7 @@ exports.Lexer = class Lexer
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
# unless explicitly asked not to.
tokenize: (code, opts = {}) ->
code = "\n#{code}" if WHITESPACE.test code
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
@code = code # The remainder of the source code.
@@ -79,7 +80,8 @@ exports.Lexer = class Lexer
@token 'OWN', id
return id.length
forcedIdentifier = colon or
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
(prev = last @tokens) and (prev[0] in ['.', '?.', '::'] or
not prev.spaced and prev[0] is '@')
tag = 'IDENTIFIER'
if id in JS_KEYWORDS or
@@ -112,7 +114,7 @@ exports.Lexer = class Lexer
@identifierError id
unless forcedIdentifier
id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id
id = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
tag = switch id
when '!' then 'UNARY'
when '==', '!=' then 'COMPARE'
@@ -169,11 +171,11 @@ exports.Lexer = class Lexer
commentToken: ->
return 0 unless match = @chunk.match COMMENT
[comment, here] = match
@line += count comment, '\n'
if here
@token 'HERECOMMENT', @sanitizeHeredoc here,
herecomment: true, indent: Array(@indent + 1).join(' ')
@token 'TERMINATOR', '\n'
@line += count comment, '\n'
comment.length
# Matches JavaScript interpolated directly into the source via backticks.
@@ -342,8 +344,11 @@ exports.Lexer = class Lexer
# erasing all external indentation on the left-hand side.
sanitizeHeredoc: (doc, options) ->
{indent, herecomment} = options
return doc if herecomment and 0 > doc.indexOf '\n'
unless herecomment
if herecomment
if HEREDOC_ILLEGAL.test doc
throw new Error "block comment cannot contain \"*/\", starting on line #{@line + 1}"
return doc if doc.indexOf('\n') <= 0
else
while match = HEREDOC_INDENT.exec doc
attempt = match[1]
indent = attempt if indent is null or 0 < attempt.length < indent.length
@@ -366,7 +371,7 @@ exports.Lexer = class Lexer
stack.push tok
when '(', 'CALL_START'
if stack.length then stack.pop()
else
else if tok[0] is '('
tok[0] = 'PARAM_START'
return this
this
@@ -438,10 +443,11 @@ exports.Lexer = class Lexer
nested = new Lexer().tokenize inner, line: @line, rewrite: off
nested.pop()
nested.shift() if nested[0]?[0] is 'TERMINATOR'
if nested.length > 1
nested.unshift ['(', '(']
nested.push [')', ')']
tokens.push ['TOKENS', nested]
if len = nested.length
if len > 1
nested.unshift ['(', '(']
nested.push [')', ')']
tokens.push ['TOKENS', nested]
i += expr.length
pi = i + 1
tokens.push ['NEOSTRING', str.slice pi] if i > pi < str.length
@@ -506,7 +512,8 @@ JS_KEYWORDS = [
# CoffeeScript-only keywords.
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']
COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
COFFEE_ALIAS_MAP =
and : '&&'
or : '||'
is : '=='
@@ -516,6 +523,9 @@ COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
no : 'false'
on : 'true'
off : 'false'
COFFEE_ALIASES = (key for key of COFFEE_ALIAS_MAP)
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES
# 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,
@@ -534,7 +544,7 @@ exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
# Token matching regexes.
IDENTIFIER = /// ^
( [$A-Za-z_][$\w]* )
( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
( [^\n\S]* : (?!:) )? # Is this a property name?
///
@@ -569,7 +579,7 @@ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/
# Regex-matching-regexes.
REGEX = /// ^
/ (?! \s ) # disallow leading whitespace
/ (?! [\s=] ) # disallow leading whitespace or equals signs
[^ [ / \n \\ ]* # every other thing
(?:
(?: \\[\s\S] # anything escaped
@@ -591,9 +601,11 @@ MULTILINER = /\n/g
HEREDOC_INDENT = /\n+([^\n\S]*)/g
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
HEREDOC_ILLEGAL = /\*\//
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?!\.) | :: ) ///
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
TRAILING_SPACES = /\s+$/

View File

@@ -48,7 +48,7 @@ exports.Base = class Base
# Statements converted into expressions via closure-wrapping share a scope
# object with their parent closure, to preserve the expected lexical scope.
compileClosure: (o) ->
if @jumps()
if @jumps() or this instanceof Throw
throw SyntaxError 'cannot use a pure statement in an expression.'
o.sharedScope = yes
Closure.wrap(this).compileNode o
@@ -145,12 +145,12 @@ exports.Base = class Base
# Is this node used to assign a certain variable?
assigns: NO
#### Expressions
#### Block
# The expressions body is the list of expressions that forms the body of an
# The block is the list of expressions that forms the body of an
# indented block of code -- the implementation of a function, a clause in an
# `if`, `switch`, or `try`, and so on...
exports.Expressions = class Expressions extends Base
exports.Block = class Block extends Base
constructor: (nodes) ->
@expressions = compact flatten nodes or []
@@ -170,7 +170,7 @@ exports.Expressions = class Expressions extends Base
@expressions.unshift node
this
# If this Expressions consists of just a single node, unwrap it by pulling
# If this Block consists of just a single node, unwrap it by pulling
# it back out.
unwrap: ->
if @expressions.length is 1 then @expressions[0] else this
@@ -188,7 +188,7 @@ exports.Expressions = class Expressions extends Base
for exp in @expressions
return exp if exp.jumps o
# An Expressions node does not return its entire body, rather it
# An Block node does not return its entire body, rather it
# ensures that the final expression is returned.
makeReturn: ->
len = @expressions.length
@@ -196,14 +196,15 @@ exports.Expressions = class Expressions extends Base
expr = @expressions[len]
if expr not instanceof Comment
@expressions[len] = expr.makeReturn()
@expressions.splice(len, 1) if expr instanceof Return and not expr.expression
break
this
# An **Expressions** is the only node that can serve as the root.
# An **Block** is the only node that can serve as the root.
compile: (o = {}, level) ->
if o.scope then super o, level else @compileRoot o
# Compile all expressions within the **Expressions** body. If we need to
# Compile all expressions within the **Block** 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.
compileNode: (o) ->
@@ -223,7 +224,7 @@ exports.Expressions = class Expressions extends Base
code = codes.join(', ') or 'void 0'
if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code
# If we happen to be the top-level **Expressions**, wrap everything in
# If we happen to be the top-level **Block**, wrap everything in
# a safety closure, unless requested not to.
# It would be better not to generate them in the first place, but for now,
# clean up obvious double-parentheses.
@@ -232,7 +233,6 @@ exports.Expressions = class Expressions extends Base
o.scope = new Scope null, this, null
o.level = LEVEL_TOP
code = @compileWithDeclarations o
code = code.replace TRAILING_WHITESPACE, ''
if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
# Compile the expressions body for the contents of a function, with
@@ -250,17 +250,17 @@ exports.Expressions = class Expressions extends Base
post = @compileNode o
{scope} = o
if scope.expressions is this
if not o.globals and o.scope.hasDeclarations()
if o.scope.hasDeclarations()
code += "#{@tab}var #{ scope.declaredVariables().join(', ') };\n"
if scope.hasAssignments
code += "#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"
code + post
# Wrap up the given nodes as an **Expressions**, unless it already happens
# Wrap up the given nodes as an **Block**, unless it already happens
# to be one.
@wrap: (nodes) ->
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
new Expressions nodes
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block
new Block nodes
#### Literal
@@ -289,7 +289,12 @@ exports.Literal = class Literal extends Base
if not (o and (o.loop or o.block and (@value isnt 'continue'))) then this else no
compileNode: (o) ->
code = if @value.reserved then "\"#{@value}\"" else @value
code = if @isUndefined
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
else if @value.reserved
"\"#{@value}\""
else
@value
if @isStatement() then "#{@tab}#{code};" else code
toString: ->
@@ -300,7 +305,8 @@ exports.Literal = class Literal extends Base
# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't
# make sense.
exports.Return = class Return extends Base
constructor: (@expression) ->
constructor: (expr) ->
@expression = expr if expr and not expr.unwrap().isUndefined
children: ['expression']
@@ -398,19 +404,22 @@ exports.Value = class Value extends Base
# Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
unfoldSoak: (o) ->
if ifn = @base.unfoldSoak o
Array::push.apply ifn.body.properties, @properties
return ifn
for prop, i in @properties when prop.soak
prop.soak = off
fst = new Value @base, @properties.slice 0, i
snd = new Value @base, @properties.slice i
if fst.isComplex()
ref = new Literal o.scope.freeVariable 'ref'
fst = new Parens new Assign ref, fst
snd.base = ref
return new If new Existence(fst), snd, soak: on
null
return @unfoldedSoak if @unfoldedSoak?
result = do =>
if ifn = @base.unfoldSoak o
Array::push.apply ifn.body.properties, @properties
return ifn
for prop, i in @properties when prop.soak
prop.soak = off
fst = new Value @base, @properties.slice 0, i
snd = new Value @base, @properties.slice i
if fst.isComplex()
ref = new Literal o.scope.freeVariable 'ref'
fst = new Parens new Assign ref, fst
snd.base = ref
return new If new Existence(fst), snd, soak: on
null
@unfoldedSoak = result or no
#### Comment
@@ -492,12 +501,31 @@ exports.Call = class Call extends Base
ifn = unfoldSoak o, call, 'variable'
ifn
# Walk through the objects in the arguments, moving over simple values.
# This allows syntax like `call a: b, c` into `call({a: b}, c);`
filterImplicitObjects: (list) ->
nodes = []
for node in list
unless node.isObject?() and node.base.generated
nodes.push node
continue
obj = null
for prop in node.base.properties
if prop instanceof Assign
nodes.push obj = new Obj properties = [], true if not obj
properties.push prop
else
nodes.push prop
obj = null
nodes
# Compile a vanilla function call.
compileNode: (o) ->
@variable?.front = @front
if code = Splat.compileSplattedArray o, @args, true
return @compileSplat o, code
args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
args = @filterImplicitObjects @args
args = (arg.compile o, LEVEL_LIST for arg in args).join ', '
if @isSuper
@superReference(o) + ".call(this#{ args and ', ' + args })"
else
@@ -517,11 +545,11 @@ exports.Call = class Call extends Base
if @isNew
idt = @tab + TAB
return """
(function(func, args, ctor) {
#{idt}ctor.prototype = func.prototype;
#{idt}var child = new ctor, result = func.apply(child, args);
#{idt}return typeof result === "object" ? result : child;
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
(function(func, args, ctor) {
#{idt}ctor.prototype = func.prototype;
#{idt}var child = new ctor, result = func.apply(child, args);
#{idt}return typeof result === "object" ? result : child;
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
"""
base = new Value @variable
if (name = base.properties.pop()) and base.isComplex()
@@ -529,6 +557,7 @@ exports.Call = class Call extends Base
fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
else
fun = base.compile o, LEVEL_ACCESS
fun = "(#{fun})" if SIMPLENUM.test fun
if name
ref = fun
fun += name.compile o
@@ -616,10 +645,9 @@ exports.Range = class Range extends Base
idx = del o, 'index'
step = del o, 'step'
vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
intro = "(#{@fromVar} <= #{@toVar} ? #{idx}"
compare = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})"
stepPart = if step then step.compile(o) else '1'
incr = if step then "#{idx} += #{stepPart}" else "#{intro} += #{stepPart} : #{idx} -= #{stepPart})"
cond = "#{@fromVar} <= #{@toVar}"
compare = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
incr = if step then "#{idx} += #{step.compile(o)}" else "#{cond} ? #{idx}++ : #{idx}--"
"#{vars}; #{compare}; #{incr}"
# Compile a simple range comprehension, with integers.
@@ -645,13 +673,13 @@ exports.Range = class Range extends Base
pre = "\n#{idt}#{result} = [];"
if @fromNum and @toNum
o.index = i
body = @compileSimple o
body = @compileSimple o
else
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
clause = "#{@fromVar} <= #{@toVar} ?"
body = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
cond = "#{@fromVar} <= #{@toVar}"
body = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--"
post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)"
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this, arguments)"
#### Slice
@@ -693,6 +721,9 @@ exports.Obj = class Obj extends Base
compileNode: (o) ->
props = @properties
return (if @front then '({})' else '{}') unless props.length
if @generated
for node in props when node instanceof Value
throw new Error 'cannot have an implicit value in an implicit object'
idt = o.indent += TAB
lastNoncom = @lastNonComment @properties
props = for prop, i in props
@@ -727,11 +758,14 @@ exports.Arr = class Arr extends Base
children: ['objects']
filterImplicitObjects: Call::filterImplicitObjects
compileNode: (o) ->
return '[]' unless @objects.length
o.indent += TAB
return code if code = Splat.compileSplattedArray o, @objects
code = (obj.compile o, LEVEL_LIST for obj in @objects).join ', '
objs = @filterImplicitObjects @objects
return code if code = Splat.compileSplattedArray o, objs
code = (obj.compile o, LEVEL_LIST for obj in objs).join ', '
if code.indexOf('\n') >= 0
"[\n#{o.indent}#{code}\n#{@tab}]"
else
@@ -747,7 +781,7 @@ exports.Arr = class Arr extends Base
# Initialize a **Class** with its name, an optional superclass, and a
# list of prototype property assignments.
exports.Class = class Class extends Base
constructor: (@variable, @parent, @body = new Expressions) ->
constructor: (@variable, @parent, @body = new Block) ->
@boundFuncs = []
@body.classBody = yes
@@ -811,7 +845,7 @@ exports.Class = class Class extends Base
walkBody: (name) ->
@traverseChildren false, (child) =>
return false if child instanceof Class
if child instanceof Expressions
if child instanceof Block
for node, i in exps = child.expressions
if node instanceof Value and node.isObject(true)
exps[i] = @addProperties node, name
@@ -838,8 +872,8 @@ exports.Class = class Class extends Base
@setContext name
@walkBody name
@body.expressions.unshift new Extends lname, @parent if @parent
@ensureConstructor name
@body.expressions.splice 1, 0, new Extends(lname, @parent) if @parent
@body.expressions.push lname
@addBoundFunctions o
@@ -856,7 +890,7 @@ exports.Assign = class Assign extends Base
@param = options and options.param
# Matchers for detecting class/method names
METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/
METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w\x7f-\uffff]*)$/
children: ['variable', 'value']
@@ -876,18 +910,18 @@ exports.Assign = class Assign extends Base
return @compileSplice o if @variable.isSplice()
return @compileConditional o if @context in ['||=', '&&=', '?=']
name = @variable.compile o, LEVEL_LIST
if @value instanceof Code and match = @METHOD_DEF.exec name
@value.name = match[2]
@value.klass = match[1] if match[1]
val = @value.compile o, LEVEL_LIST
return "#{name}: #{val}" if @context is 'object'
unless @variable.isAssignable()
unless @context or @variable.isAssignable()
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
if @param
o.scope.add name, 'var'
else
o.scope.find name
if @value instanceof Code and match = @METHOD_DEF.exec name
@value.name = match[2]
@value.klass = match[1] if match[1]
val = @value.compile o, LEVEL_LIST
return "#{name}: #{val}" if @context is 'object'
val = name + " #{ @context or '=' } " + val
if o.level <= LEVEL_LIST then val else "(#{val})"
@@ -899,7 +933,9 @@ exports.Assign = class Assign extends Base
top = o.level is LEVEL_TOP
{value} = this
{objects} = @variable.base
return value.compile o unless olen = objects.length
unless olen = objects.length
code = value.compile o
return if o.level >= LEVEL_OP then "(#{code})" else code
isObject = @variable.isObject()
if top and olen is 1 and (obj = objects[0]) not instanceof Splat
# Unroll simplest cases: `{v} = x` -> `v = x.v`
@@ -995,7 +1031,7 @@ exports.Assign = class Assign extends Base
exports.Code = class Code extends Base
constructor: (params, body, tag) ->
@params = params or []
@body = body or new Expressions
@body = body or new Block
@bound = tag is 'boundfunc'
@context = 'this' if @bound
@@ -1015,10 +1051,10 @@ exports.Code = class Code extends Base
o.scope.shared = del o, 'sharedScope'
o.indent += TAB
delete o.bare
delete o.globals
vars = []
exprs = []
for param in @params when param.splat
o.scope.add param.name.value, 'var' if param.name.value
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
new Value new Literal 'arguments'
break
@@ -1163,7 +1199,7 @@ exports.While = class While extends Base
rvar = o.scope.freeVariable 'results'
set = "#{@tab}#{rvar} = [];\n"
body = Push.wrap rvar, body if body
body = Expressions.wrap [new If @guard, body] if @guard
body = Block.wrap [new If @guard, body] if @guard
body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
if @returns
@@ -1177,10 +1213,13 @@ exports.While = class While extends Base
exports.Op = class Op extends Base
constructor: (op, first, second, flip) ->
return new In first, second if op is 'in'
return new Call first, first.params or [] if op is 'do'
if op is 'do'
call = new Call first, first.params or []
call.do = yes
return call
if op is 'new'
return first.newInstance() if first instanceof Call
first = new Parens first if first instanceof Code and first.bound
return first.newInstance() if first instanceof Call and not first.do
first = new Parens first if first instanceof Code and first.bound or first.do
@operator = CONVERSIONS[op] or op
@first = first
@second = second
@@ -1262,18 +1301,19 @@ exports.Op = class Op extends Base
compileExistence: (o) ->
if @first.isComplex()
ref = o.scope.freeVariable 'ref'
fst = new Parens new Assign new Literal(ref), @first
ref = new Literal o.scope.freeVariable 'ref'
fst = new Parens new Assign ref, @first
else
fst = @first
ref = fst.compile o
new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL_LIST }"
ref = fst
new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o
# Compile a unary **Op**.
compileUnary: (o) ->
parts = [op = @operator]
parts.push ' ' if op in ['new', 'typeof', 'delete'] or
op in ['+', '-'] and @first instanceof Op and @first.operator is op
@first = new Parens @first if op is 'new' and @first.isStatement o
parts.push @first.compile o, LEVEL_OP
parts.reverse() if @flip
parts.join ''
@@ -1300,6 +1340,7 @@ exports.In = class In extends Base
[cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
tests = for item, i in @array.base.objects
(if i then ref else sub) + cmp + item.compile o, LEVEL_OP
return 'false' if tests.length is 0
tests = tests.join cnj
if o.level < LEVEL_OP then tests else "(#{tests})"
@@ -1379,9 +1420,9 @@ exports.Existence = class Existence extends Base
code = @expression.compile o, LEVEL_OP
code = if IDENTIFIER.test(code) and not o.scope.check code
if @negated
"typeof #{code} == \"undefined\" || #{code} === null"
"typeof #{code} === \"undefined\" || #{code} === null"
else
"typeof #{code} != \"undefined\" && #{code} !== null"
"typeof #{code} !== \"undefined\" && #{code} !== null"
else
sym = if @negated then '==' else '!='
"#{code} #{sym} null"
@@ -1425,7 +1466,7 @@ exports.Parens = class Parens extends Base
exports.For = class For extends Base
constructor: (body, source) ->
{@source, @guard, @step, @name, @index} = source
@body = Expressions.wrap [body]
@body = Block.wrap [body]
@own = !!source.own
@object = !!source.object
[@name, @index] = [@index, @name] if @object
@@ -1451,7 +1492,7 @@ exports.For = class For extends Base
# comprehensions. Some of the generated code can be shared in common, and
# some cannot.
compileNode: (o) ->
body = Expressions.wrap [@body]
body = Block.wrap [@body]
lastJumps = last(body.expressions)?.jumps()
@returns = no if lastJumps and lastJumps instanceof Return
source = if @range then @source.base else @source
@@ -1485,7 +1526,7 @@ exports.For = class For extends Base
returnResult = "\n#{@tab}return #{rvar};"
body = Push.wrap rvar, body
if @guard
body = Expressions.wrap [new If @guard, body]
body = Block.wrap [new If @guard, body]
if @pattern
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
defPart += @pluckDirectCall o, body
@@ -1551,9 +1592,8 @@ exports.Switch = class Switch extends Base
code += body + '\n' if body = block.compile o, LEVEL_TOP
break if i is @cases.length - 1 and not @otherwise
expr = @lastNonComment block.expressions
jumper = expr.jumps()
if not expr or not jumper or (jumper instanceof Literal and jumper.value is 'debugger')
code += idt2 + 'break;\n'
continue if expr instanceof Return or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger')
code += idt2 + 'break;\n'
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
code + @tab + '}'
@@ -1582,7 +1622,7 @@ exports.If = class If extends Base
@elseBodyNode().addElse elseBody
else
@isChain = elseBody instanceof If
@elseBody = @ensureExpressions elseBody
@elseBody = @ensureBlock elseBody
this
# The **If** only compiles into a statement if either of its bodies needs
@@ -1597,12 +1637,12 @@ exports.If = class If extends Base
if @isStatement o then @compileStatement o else @compileExpression o
makeReturn: ->
@body and= new Expressions [@body.makeReturn()]
@elseBody and= new Expressions [@elseBody.makeReturn()]
@body and= new Block [@body.makeReturn()]
@elseBody and= new Block [@elseBody.makeReturn()]
this
ensureExpressions: (node) ->
if node instanceof Expressions then node else new Expressions [node]
ensureBlock: (node) ->
if node instanceof Block then node else new Block [node]
# Compile the **If** as a regular *if-else* statement. Flattened chains
# force inner *else* bodies into statement form.
@@ -1610,7 +1650,7 @@ exports.If = class If extends Base
child = del o, 'chainChild'
cond = @condition.compile o, LEVEL_PAREN
o.indent += TAB
body = @ensureExpressions(@body).compile o
body = @ensureBlock(@body).compile o
body = "\n#{body}\n#{@tab}" if body
ifPart = "if (#{cond}) {#{body}}"
ifPart = @tab + ifPart unless child
@@ -1657,17 +1697,16 @@ Closure =
# then make sure that the closure wrapper preserves the original values.
wrap: (expressions, statement, noReturn) ->
return expressions if expressions.jumps()
func = new Code [], Expressions.wrap [expressions]
func = new Code [], Block.wrap [expressions]
args = []
if (mentionsArgs = expressions.contains @literalArgs) or
( expressions.contains @literalThis)
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
meth = new Literal if mentionsArgs then 'apply' else 'call'
args = [new Literal 'this']
args.push new Literal 'arguments' if mentionsArgs
func = new Value func, [new Access meth]
func.noReturn = noReturn
call = new Call func, args
if statement then Expressions.wrap [call] else call
if statement then Block.wrap [call] else call
literalArgs: (node) ->
node instanceof Literal and node.value is 'arguments' and not node.asKey
@@ -1731,11 +1770,7 @@ LEVEL_ACCESS = 6 # ...[0]
# Tabs are two spaces for pretty printing.
TAB = ' '
# Trim out all trailing whitespace, so that the generated code plays nice
# with Git.
TRAILING_WHITESPACE = /[ \t]+$/gm
IDENTIFIER = /^[$A-Za-z_][$\w]*$/
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/
SIMPLENUM = /^[+-]?\d+$/
# Is a literal value a string?

View File

@@ -47,7 +47,7 @@ exports.OptionParser = class OptionParser
# Return the help text for this **OptionParser**, listing and describing all
# of the valid options, for `--help` and such.
help: ->
lines = ['Available options:']
lines = []
lines.unshift "#{@banner}\n" if @banner
for rule in @rules
spaces = 15 - rule.longFlag.length

View File

@@ -6,37 +6,102 @@
# Require the **coffee-script** module to get access to the compiler.
CoffeeScript = require './coffee-script'
helpers = require './helpers'
readline = require 'readline'
{inspect} = require 'util'
{Script} = require 'vm'
# Start by opening up **stdio**.
stdio = process.openStdin()
# REPL Setup
# Config
enableColours = no
unless process.platform is 'win32'
enableColours = not process.env.NODE_DISABLE_COLORS
# Start by opening up `stdin` and `stdout`.
stdin = process.openStdin()
stdout = process.stdout
# Log an error.
error = (err) ->
stdio.write (err.stack or err.toString()) + '\n\n'
stdout.write (err.stack or err.toString()) + '\n\n'
# Quick alias for quitting the REPL.
helpers.extend global, quit: -> process.exit(0)
# The current backlog of multi-line code.
backlog = ''
# 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 = (buffer) ->
try
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
console.log val if val isnt undefined
catch err
error err
repl.prompt()
run = do ->
sandbox =
require: require
module : { exports: {} }
sandbox[g] = global[g] for g of global
sandbox.global = sandbox
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
(buffer) ->
code = backlog += '\n' + buffer.toString()
if code[code.length - 1] is '\\'
return backlog = backlog[0...backlog.length - 1]
backlog = ''
try
val = CoffeeScript.eval code, {
sandbox,
bare: on,
filename: 'repl'
}
unless val is undefined
process.stdout.write inspect(val, no, 2, enableColours) + '\n'
catch err
error err
repl.prompt()
## Autocompletion
# Regexes to match complete-able bits of text.
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/
SIMPLEVAR = /\s*(\w*)$/i
# Returns a list of completions, and the completed text.
autocomplete = (text) ->
completeAttribute(text) or completeVariable(text) or [[], text]
# Attempt to autocomplete a chained dotted attribute: `one.two.three`.
completeAttribute = (text) ->
if match = text.match ACCESSOR
[all, obj, prefix] = match
try
val = Script.runInThisContext obj
catch error
return [[], text]
completions = getCompletions prefix, getPropertyNames val
[completions, prefix]
# Attempt to autocomplete an in-scope free variable: `one`.
completeVariable = (text) ->
if free = text.match(SIMPLEVAR)?[1]
scope = Script.runInThisContext 'this'
completions = getCompletions free, CoffeeScript.RESERVED.concat(getPropertyNames scope)
[completions, free]
# Return elements of candidates for which `prefix` is a prefix.
getCompletions = (prefix, candidates) ->
(el for el in candidates when el.indexOf(prefix) is 0)
# Return all "own" properties of an object.
getPropertyNames = (obj) ->
(name for own name of obj)
# Make sure that uncaught exceptions don't kill the REPL.
process.on 'uncaughtException', error
# Create the REPL by listening to **stdin**.
repl = readline.createInterface stdio
if readline.createInterface.length < 3
repl = readline.createInterface stdin, autocomplete
stdin.on 'data', (buffer) -> repl.write buffer
else
repl = readline.createInterface stdin, stdout, autocomplete
repl.setPrompt 'coffee> '
stdio.on 'data', (buffer) -> repl.write buffer
repl.on 'close', -> stdio.destroy()
repl.on 'close', -> stdin.destroy()
repl.on 'line', run
repl.prompt()

View File

@@ -104,7 +104,10 @@ class exports.Rewriter
not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':')) or
(tag is ',' and one and
one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
action = (token, i) ->
tok = ['}', '}', token[2]]
tok.generated = yes
@tokens.splice i, 0, tok
@scanTokens (token, i, tokens) ->
if (tag = token[0]) in EXPRESSION_START
stack.push [(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag), i]
@@ -143,6 +146,7 @@ class exports.Rewriter
seenSingle = no
noCall = no if tag in LINEBREAKS
token.call = yes if prev and not prev.spaced and tag is '?'
return 1 if token.fromThen
return 1 unless callObject or
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
(tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)

View File

@@ -14,10 +14,10 @@ exports.Scope = class 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
# as well as a reference to the **Block** 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) ->
constructor: (@parent, @expressions, @method) ->
@variables = [{name: 'arguments', type: 'arguments'}]
@positions = {}
Scope.root = this unless @parent
@@ -66,7 +66,7 @@ exports.Scope = class Scope
# compiler-generated variable. `_var`, `_var2`, and so on...
freeVariable: (type) ->
index = 0
index++ while @check((temp = @temporary type, index), true)
index++ while @check((temp = @temporary type, index))
@add temp, 'var', yes
temp

77
test/arrays.coffee Normal file
View File

@@ -0,0 +1,77 @@
# Array Literals
# --------------
# * Array Literals
# * Splats in Array Literals
# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()
test "trailing commas", ->
trailingComma = [1, 2, 3,]
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
trailingComma = [
1, 2, 3,
4, 5, 6
7, 8, 9,
]
(sum = (sum or 0) + n) for n in trailingComma
a = [((x) -> x), ((x) -> x * x)]
ok a.length is 2
test "incorrect indentation without commas", ->
result = [['a']
{b: 'c'}]
ok result[0][0] is 'a'
ok result[1]['b'] is 'c'
# Splats in Array Literals
test "array splat expansions with assignments", ->
nums = [1, 2, 3]
list = [a = 0, nums..., b = 4]
eq 0, a
eq 4, b
arrayEq [0,1,2,3,4], list
test "mixed shorthand objects in array lists", ->
arr = [
a:1
'b'
c:1
]
ok arr.length is 3
ok arr[2].c is 1
arr = [b: 1, a: 2, 100]
eq arr[1], 100
arr = [a:0, b:1, (1 + 1)]
eq arr[1], 2
arr = [a:1, 'a', b:1, 'b']
eq arr.length, 4
eq arr[2].b, 1
eq arr[3], 'b'
test "array splats with nested arrays", ->
nonce = {}
a = [nonce]
list = [1, 2, a...]
eq list[0], 1
eq list[2], nonce
a = [[nonce]]
list = [1, 2, a...]
arrayEq list, [1, 2, [nonce]]
test "#1274: `[] = a()` compiles to `false` instead of `a()`", ->
a = false
fn = -> a = true
[] = fn()
ok a

View File

@@ -1,6 +1,12 @@
# Assignment
# ----------
# * Assignment
# * Compound Assignment
# * Destructuring Assignment
# * Context Property (@) Assignment
# * Existential Assignment (?=)
test "context property assignment (using @)", ->
nonce = {}
addMethod = ->
@@ -19,44 +25,80 @@ test "compound assignments should not declare", ->
eq Math, (-> Math or= 0)()
#### Statements as Expressions
# Compound Assignment
test "assign the result of a try/catch block", ->
# multiline
result = try
nonexistent * missing
catch error
true
eq true, result
# single line
result = try nonexistent * missing catch error then true
eq true, result
test "conditionals", ->
# assign inside the condition of a conditional statement
test "boolean operators", ->
nonce = {}
if a = nonce then 1
a = 0
a or= nonce
eq nonce, a
1 if b = nonce
eq nonce, b
# assign the result of a conditional statement
c = if true then nonce
eq nonce, c
b = 1
b or= nonce
eq 1, b
test "assign inside the condition of a `while` loop", ->
nonce = {}
count = 1
a = nonce while count--
eq nonce, a
count = 1
while count--
b = nonce
eq nonce, b
c = 0
c and= nonce
eq 0, c
d = 1
d and= nonce
eq nonce, d
#### Compound Assignment
# ensure that RHS is treated as a group
e = f = false
e and= f or true
eq false, e
test "compound assignment as a sub expression", ->
[a, b, c] = [1, 2, 3]
eq 6, (a + b += c)
eq 1, a
eq 5, b
eq 3, c
# *note: this test could still use refactoring*
test "compound assignment should be careful about caching variables", ->
count = 0
list = []
list[++count] or= 1
eq 1, list[1]
eq 1, count
list[++count] ?= 2
eq 2, list[2]
eq 2, count
list[count++] and= 6
eq 6, list[2]
eq 3, count
base = ->
++count
base
base().four or= 4
eq 4, base.four
eq 4, count
base().five ?= 5
eq 5, base.five
eq 5, count
test "compound assignment with implicit objects", ->
obj = undefined
obj ?=
one: 1
eq 1, obj.one
obj and=
two: 2
eq undefined, obj.one
eq 2, obj.two
test "compound assignment (math operators)", ->
num = 10
@@ -92,7 +134,137 @@ test "more compound assignment", ->
eq c, val
#### Destructuring Assignment
# Destructuring Assignment
# NO TESTS?!
# TODO: make tests for destructuring assignment
test "empty destructuring assignment", ->
{} = [] = undefined
test "chained destructuring assignments", ->
[a] = {0: b} = {'0': c} = [nonce={}]
eq nonce, a
eq nonce, b
eq nonce, c
test "variable swapping to verify caching of RHS values when appropriate", ->
a = nonceA = {}
b = nonceB = {}
c = nonceC = {}
[a, b, c] = [b, c, a]
eq nonceB, a
eq nonceC, b
eq nonceA, c
[a, b, c] = [b, c, a]
eq nonceC, a
eq nonceA, b
eq nonceB, c
fn = ->
[a, b, c] = [b, c, a]
arrayEq [nonceA,nonceB,nonceC], fn()
eq nonceA, a
eq nonceB, b
eq nonceC, c
test "#713", ->
nonces = [nonceA={},nonceB={}]
eq nonces, [a, b] = [c, d] = nonces
eq nonceA, a
eq nonceA, c
eq nonceB, b
eq nonceB, d
test "destructuring assignment with splats", ->
a = {}; b = {}; c = {}; d = {}; e = {}
[x,y...,z] = [a,b,c,d,e]
eq a, x
arrayEq [b,c,d], y
eq e, z
test "deep destructuring assignment with splats", ->
a={}; b={}; c={}; d={}; e={}; f={}; g={}; h={}; i={}
[u, [v, w..., x], y..., z] = [a, [b, c, d, e], f, g, h, i]
eq a, u
eq b, v
arrayEq [c,d], w
eq e, x
arrayEq [f,g,h], y
eq i, z
test "destructuring assignment with objects", ->
a={}; b={}; c={}
obj = {a,b,c}
{a:x, b:y, c:z} = obj
eq a, x
eq b, y
eq c, z
test "deep destructuring assignment with objects", ->
a={}; b={}; c={}; d={}
obj = {
a
b: {
'c': {
d: [
b
{e: c, f: d}
]
}
}
}
{a: w, 'b': {c: d: [x, {'f': z, e: y}]}} = obj
eq a, w
eq b, x
eq c, y
eq d, z
test "destructuring assignment with objects and splats", ->
a={}; b={}; c={}; d={}
obj = a: b: [a, b, c, d]
{a: b: [y, z...]} = obj
eq a, y
arrayEq [b,c,d], z
test "destructuring assignment against an expression", ->
a={}; b={}
[y, z] = if true then [a, b] else [b, a]
eq a, y
eq b, z
test "bracket insertion when necessary", ->
[a] = [0] ? [1]
eq a, 0
# for implicit destructuring assignment in comprehensions, see the comprehension tests
test "destructuring assignment with context (@) properties", ->
a={}; b={}; c={}; d={}; e={}
obj =
fn: () ->
local = [a, {b, c}, d, e]
[@a, {b: @b, c: @c}, @d, @e] = local
eq undefined, obj[key] for key in ['a','b','c','d','e']
obj.fn()
eq a, obj.a
eq b, obj.b
eq c, obj.c
eq d, obj.d
eq e, obj.e
test "#1024", ->
eq 2 * [] = 3 + 5, 16
# Existential Assignment
test "existential assignment", ->
nonce = {}
a = false
a ?= nonce
eq false, a
b = undefined
b ?= nonce
eq nonce, b
c = null
c ?= nonce
eq nonce, c
d ?= nonce
eq nonce, d

21
test/booleans.coffee Normal file
View File

@@ -0,0 +1,21 @@
# Boolean Literals
# ----------------
# TODO: add method invocation tests: true.toString() is "true"
test "#764 Booleans should be indexable", ->
toString = Boolean::toString
eq toString, true['toString']
eq toString, false['toString']
eq toString, yes['toString']
eq toString, no['toString']
eq toString, on['toString']
eq toString, off['toString']
eq toString, true.toString
eq toString, false.toString
eq toString, yes.toString
eq toString, no.toString
eq toString, on.toString
eq toString, off.toString

View File

@@ -1,18 +0,0 @@
# Break
# -----
test "break at the top level", ->
for i in [1,2,3]
result = i
if i == 2
break
eq 2, result
test "break *not* at the top level", ->
someFunc = () ->
i = 0
while ++i < 3
result = i
break if i > 1
result
eq 2, someFunc()

449
test/classes.coffee Normal file
View File

@@ -0,0 +1,449 @@
# Classes
# -------
# * Class Definition
# * Class Instantiation
# * Inheritance and Super
test "classes with a four-level inheritance chain", ->
class Base
func: (string) ->
"zero/#{string}"
@static: (string) ->
"static/#{string}"
class FirstChild extends Base
func: (string) ->
super('one/') + string
SecondChild = class extends FirstChild
func: (string) ->
super('two/') + string
thirdCtor = ->
@array = [1, 2, 3]
class ThirdChild extends SecondChild
constructor: -> thirdCtor.call this
# Gratuitous comment for testing.
func: (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok Base.static('word') is 'static/word'
FirstChild::func = (string) ->
super('one/').length + string
result = (new ThirdChild).func 'four'
ok result is '9two/three/four'
ok (new ThirdChild).array.join(' ') is '1 2 3'
test "constructors with inheritance and super", ->
identity = (f) -> f
class TopClass
constructor: (arg) ->
@prop = 'top-' + arg
class SuperClass extends TopClass
constructor: (arg) ->
identity super 'super-' + arg
class SubClass extends SuperClass
constructor: ->
identity super 'sub'
ok (new SubClass).prop is 'top-super-sub'
test "Overriding the static property new doesn't clobber Function::new", ->
class OneClass
@new: 'new'
function: 'function'
constructor: (name) -> @name = name
class TwoClass extends OneClass
delete TwoClass.new
Function.prototype.new = -> new this arguments...
ok (TwoClass.new('three')).name is 'three'
ok (new OneClass).function is 'function'
ok OneClass.new is 'new'
delete Function.prototype.new
test "basic classes, again, but in the manual prototype style", ->
Base = ->
Base::func = (string) ->
'zero/' + string
Base::['func-func'] = (string) ->
"dynamic-#{string}"
FirstChild = ->
SecondChild = ->
ThirdChild = ->
@array = [1, 2, 3]
this
ThirdChild extends SecondChild extends FirstChild extends Base
FirstChild::func = (string) ->
super('one/') + string
SecondChild::func = (string) ->
super('two/') + string
ThirdChild::func = (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
test "super with plain ol' functions as the original constructors", ->
TopClass = (arg) ->
@prop = 'top-' + arg
this
SuperClass = (arg) ->
super 'super-' + arg
this
SubClass = ->
super 'sub'
this
SuperClass extends TopClass
SubClass extends SuperClass
ok (new SubClass).prop is 'top-super-sub'
test "'@' referring to the current instance, and not being coerced into a call", ->
class ClassName
amI: ->
@ instanceof ClassName
obj = new ClassName
ok obj.amI()
test "super() calls in constructors of classes that are defined as object properties", ->
class Hive
constructor: (name) -> @name = name
class Hive.Bee extends Hive
constructor: (name) -> super
maya = new Hive.Bee 'Maya'
ok maya.name is 'Maya'
test "classes with JS-keyword properties", ->
class Class
class: 'class'
name: -> @class
instance = new Class
ok instance.class is 'class'
ok instance.name() is 'class'
test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
class Dog
constructor: (name) ->
@name = name
bark: =>
"#{@name} woofs!"
@static = =>
new this('Dog')
spark = new Dog('Spark')
fido = new Dog('Fido')
fido.bark = spark.bark
ok fido.bark() is 'Spark woofs!'
obj = func: Dog.static
ok obj.func().name is 'Dog'
test "a bound function in a bound function", ->
class Mini
num: 10
generate: =>
for i in [1..3]
=>
@num
m = new Mini
eq (func() for func in m.generate()).join(' '), '10 10 10'
test "contructor called with varargs", ->
class Connection
constructor: (one, two, three) ->
[@one, @two, @three] = [one, two, three]
out: ->
"#{@one}-#{@two}-#{@three}"
list = [3, 2, 1]
conn = new Connection list...
ok conn instanceof Connection
ok conn.out() is '3-2-1'
test "calling super and passing along all arguments", ->
class Parent
method: (args...) -> @args = args
class Child extends Parent
method: -> super
c = new Child
c.method 1, 2, 3, 4
ok c.args.join(' ') is '1 2 3 4'
test "classes wrapped in decorators", ->
func = (klass) ->
klass::prop = 'value'
klass
func class Test
prop2: 'value2'
ok (new Test).prop is 'value'
ok (new Test).prop2 is 'value2'
test "anonymous classes", ->
obj =
klass: class
method: -> 'value'
instance = new obj.klass
ok instance.method() is 'value'
test "Implicit objects as static properties", ->
class Static
@static =
one: 1
two: 2
ok Static.static.one is 1
ok Static.static.two is 2
test "nothing classes", ->
c = class
ok c instanceof Function
test "classes with value'd constructors", ->
counter = 0
classMaker = ->
counter++
inner = counter
->
@value = inner
class One
constructor: classMaker()
class Two
constructor: classMaker()
ok (new One).value is 1
ok (new Two).value is 2
ok (new One).value is 1
ok (new Two).value is 2
test "exectuable class bodies", ->
class A
if true
b: 'b'
else
c: 'c'
a = new A
eq a.b, 'b'
eq a.c, undefined
test "mild metaprogramming", ->
class Base
@attr: (name) ->
@::[name] = (val) ->
if arguments.length > 0
@["_#{name}"] = val
else
@["_#{name}"]
class Robot extends Base
@attr 'power'
@attr 'speed'
robby = new Robot
ok robby.power() is undefined
robby.power 11
robby.speed Infinity
eq robby.power(), 11
eq robby.speed(), Infinity
test "namespaced classes do not reserve their function name in outside scope", ->
one = {}
two = {}
class one.Klass
@label = "one"
class two.Klass
@label = "two"
eq typeof Klass, 'undefined'
eq one.Klass.label, 'one'
eq two.Klass.label, 'two'
test "nested classes", ->
class Outer
constructor: ->
@label = 'outer'
class @Inner
constructor: ->
@label = 'inner'
eq (new Outer).label, 'outer'
eq (new Outer.Inner).label, 'inner'
test "variables in constructor bodies are correctly scoped", ->
class A
x = 1
constructor: ->
x = 10
y = 20
y = 2
captured: ->
{x, y}
a = new A
eq a.captured().x, 10
eq a.captured().y, 2
test "Issue #924: Static methods in nested classes", ->
class A
@B: class
@c = -> 5
eq A.B.c(), 5
test "`class extends this`", ->
class A
func: -> 'A'
B = null
makeClass = ->
B = class extends this
func: -> super + ' B'
makeClass.call A
eq (new B()).func(), 'A B'
test "ensure that constructors invoked with splats return a new object", ->
args = [1, 2, 3]
Type = (@args) ->
type = new Type args
ok type and type instanceof Type
ok type.args and type.args instanceof Array
ok v is args[i] for v, i in type.args
Type1 = (@a, @b, @c) ->
type1 = new Type1 args...
ok type1 instanceof Type1
eq type1.constructor, Type1
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
# Ensure that constructors invoked with splats cache the function.
called = 0
get = -> if called++ then false else class Type
new get() args...
test "`new` shouldn't add extra parens", ->
ok new Date().constructor is Date
test "`new` works against bare function", ->
eq Date, new ->
eq this, new => this
Date
test "a subclass should be able to set its constructor to an external function", ->
ctor = ->
@val = 1
class A
class B extends A
constructor: ctor
eq (new B).val, 1

View File

@@ -1,6 +1,9 @@
# Comments
# --------
# * Single-Line Comments
# * Block Comments
# Note: awkward spacing seen in some tests is likely intentional.
test "comments in objects", ->
@@ -107,7 +110,7 @@ test "spaced comments with conditional statements", ->
eq nonce, result
#### Block Comments
# Block Comments
###
This is a here-comment.

61
test/compilation.coffee Normal file
View File

@@ -0,0 +1,61 @@
# Compilation
# -----------
# helper to assert that a string should fail compilation
cantCompile = (code) ->
throws -> CoffeeScript.compile code
test "ensure that carriage returns don't break compilation on Windows", ->
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
test "--bare", ->
eq -1, CoffeeScript.compile('x = y', bare: on).indexOf 'function'
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
test "multiple generated references", ->
a = {b: []}
a.b[true] = -> this == a.b
c = 0
d = []
ok a.b[0<++c<2] d...
test "splat on a line by itself is invalid", ->
cantCompile "x 'a'\n...\n"
test "Issue 750", ->
cantCompile 'f(->'
cantCompile 'a = (break)'
cantCompile 'a = (return 5 for item in list)'
cantCompile 'a = (return 5 while condition)'
cantCompile 'a = for x in y\n return 5'
test "Issue #986: Unicode identifiers", ->
λ = 5
eq λ, 5
test "don't accidentally stringify keywords", ->
ok (-> this == 'this')() is false
test "#1026", ->
cantCompile '''
if a
b
else
c
else
d
'''
test "#1050", ->
cantCompile "### */ ###"
test "#1106: __proto__ compilation", ->
object = eq
@["__proto__"] = true
ok __proto__

409
test/comprehensions.coffee Normal file
View File

@@ -0,0 +1,409 @@
# Comprehensions
# --------------
# * Array Comprehensions
# * Range Comprehensions
# * Object Comprehensions
# * Implicit Destructuring Assignment
# * Comprehensions with Nonstandard Step
# TODO: refactor comprehension tests
test "Basic array comprehensions.", ->
nums = (n * n for n in [1, 2, 3] when n & 1)
results = (n * 2 for n in nums)
ok results.join(',') is '2,18'
test "Basic object comprehensions.", ->
obj = {one: 1, two: 2, three: 3}
names = (prop + '!' for prop of obj)
odds = (prop + '!' for prop, value of obj when value & 1)
ok names.join(' ') is "one! two! three!"
ok odds.join(' ') is "one! three!"
test "Basic range comprehensions.", ->
nums = (i * 3 for i in [1..3])
negs = (x for x in [-20..-5*2])
negs = negs[0..2]
result = nums.concat(negs).join(', ')
ok result is '3, 6, 9, -20, -19, -18'
test "With range comprehensions, you can loop in steps.", ->
results = (x for x in [0...15] by 5)
ok results.join(' ') is '0 5 10'
results = (x for x in [0..100] by 10)
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
test "And can loop downwards, with a negative step.", ->
results = (x for x in [5..1])
ok results.join(' ') is '5 4 3 2 1'
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
results = (x for x in [10..1])
ok results.join(' ') is [10..1].join(' ')
results = (x for x in [10...0] by -2)
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
test "Range comprehension gymnastics.", ->
eq "#{i for i in [5..1]}", '5,4,3,2,1'
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
a = 6
b = 0
c = -2
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
eq "#{i for i in [a..b] by c}", '6,4,2,0'
test "Multiline array comprehension with filter.", ->
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
num *= -1
num -= 2
num * -1
eq evens + '', '4,6,8'
test "The in operator still works, standalone.", ->
ok 2 of evens
test "all isn't reserved.", ->
all = 1
test "Ensure that the closure wrapper preserves local variables.", ->
obj = {}
for method in ['one', 'two', 'three'] then do (method) ->
obj[method] = ->
"I'm " + method
ok obj.one() is "I'm one"
ok obj.two() is "I'm two"
ok obj.three() is "I'm three"
test "Index values at the end of a loop.", ->
i = 0
for i in [1..3]
-> 'func'
break if false
ok i is 4
test "Ensure that local variables are closed over for range comprehensions.", ->
funcs = for i in [1..3]
do (i) ->
-> -i
eq (func() for func in funcs).join(' '), '-1 -2 -3'
ok i is 4
test "Even when referenced in the filter.", ->
list = ['one', 'two', 'three']
methods = for num, i in list when num isnt 'two' and i isnt 1
do (num, i) ->
-> num + ' ' + i
ok methods.length is 2
ok methods[0]() is 'one 0'
ok methods[1]() is 'three 2'
test "Even a convoluted one.", ->
funcs = []
for i in [1..3]
do (i) ->
x = i * 2
((z)->
funcs.push -> z + ' ' + i
)(x)
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
funcs = []
results = for i in [1..3]
do (i) ->
z = (x * 3 for x in [1..i])
((a, b, c) -> [a, b, c].join(' ')).apply this, z
ok results.join(', ') is '3 , 3 6 , 3 6 9'
test "Naked ranges are expanded into arrays.", ->
array = [0..10]
ok(num % 2 is 0 for num in array by 2)
test "Nested shared scopes.", ->
foo = ->
for i in [0..7]
do (i) ->
for j in [0..7]
do (j) ->
-> i + j
eq foo()[3][4](), 7
test "Scoped loop pattern matching.", ->
a = [[0], [1]]
funcs = []
for [v] in a
do (v) ->
funcs.push -> v
eq funcs[0](), 0
eq funcs[1](), 1
test "Nested comprehensions.", ->
multiLiner =
for x in [3..5]
for y in [3..5]
[x, y]
singleLiner =
(([x, y] for y in [3..5]) for x in [3..5])
ok multiLiner.length is singleLiner.length
ok 5 is multiLiner[2][2][1]
ok 5 is singleLiner[2][2][1]
test "Comprehensions within parentheses.", ->
result = null
store = (obj) -> result = obj
store (x * 2 for x in [3, 2, 1])
ok result.join(' ') is '6 4 2'
test "Closure-wrapped comprehensions that refer to the 'arguments' object.", ->
expr = ->
result = (item * item for item in arguments)
ok expr(2, 4, 8).join(' ') is '4 16 64'
test "Fast object comprehensions over all properties, including prototypal ones.", ->
class Cat
constructor: -> @name = 'Whiskers'
breed: 'tabby'
hair: 'cream'
whiskers = new Cat
own = (value for own key, value of whiskers)
all = (value for key, value of whiskers)
ok own.join(' ') is 'Whiskers'
ok all.sort().join(' ') is 'Whiskers cream tabby'
test "Optimized range comprehensions.", ->
exxes = ('x' for [0...10])
ok exxes.join(' ') is 'x x x x x x x x x x'
test "Comprehensions safely redeclare parameters if they're not present in closest scope.", ->
rule = (x) -> x
learn = ->
rule for rule in [1, 2, 3]
ok learn().join(' ') is '1 2 3'
ok rule(101) is 101
f = -> [-> ok no, 'should cache source']
ok yes for k of [f] = f()
test "Lenient on pure statements not trying to reach out of the closure", ->
val = for i in [1]
for j in [] then break
i
ok val[0] is i
test "Comprehensions only wrap their last line in a closure, allowing other lines
to have pure expressions in them.", ->
func = -> for i in [1]
break if i is 2
j for j in [1]
ok func()[0][0] is 1
i = 6
odds = while i--
continue unless i & 1
i
ok odds.join(', ') is '5, 3, 1'
test "Issue #897: Ensure that plucked function variables aren't leaked.", ->
facets = {}
list = ['one', 'two']
(->
for entity in list
facets[entity] = -> entity
)()
eq typeof entity, 'undefined'
eq facets['two'](), 'two'
test "Issue #905. Soaks as the for loop subject.", ->
a = {b: {c: [1, 2, 3]}}
for d in a.b?.c
e = d
eq e, 3
test "Issue #948. Capturing loop variables.", ->
funcs = []
list = ->
[1, 2, 3]
for y in list()
do (y) ->
z = y
funcs.push -> "y is #{y} and z is #{z}"
eq funcs[1](), "y is 2 and z is 2"
test "Cancel the comprehension if there's a jump inside the loop.", ->
result = try
for i in [0...10]
continue if i < 5
i
eq result, 10
test "Comprehensions over break.", ->
arrayEq (break for [1..10]), []
test "Comprehensions over continue.", ->
arrayEq (continue for [1..10]), []
test "Comprehensions over function literals.", ->
a = 0
for f in [-> a = 1]
do (f) ->
do f
eq a, 1
test "Comprehensions that mention arguments.", ->
list = [arguments: 10]
args = for f in list
do (f) ->
f.arguments
eq args[0], 10
test "expression conversion under explicit returns", ->
nonce = {}
fn = ->
return (nonce for x in [1,2,3])
arrayEq [nonce,nonce,nonce], fn()
fn = ->
return [nonce for x in [1,2,3]][0]
arrayEq [nonce,nonce,nonce], fn()
fn = ->
return [(nonce for x in [1..3])][0]
arrayEq [nonce,nonce,nonce], fn()
test "implicit destructuring assignment in object of objects", ->
a={}; b={}; c={}
obj = {
a: { d: a },
b: { d: b }
c: { d: c }
}
result = ([y,z] for y, { d: z } of obj)
arrayEq [['a',a],['b',b],['c',c]], result
test "implicit destructuring assignment in array of objects", ->
a={}; b={}; c={}; d={}; e={}; f={}
arr = [
{ a: a, b: { c: b } },
{ a: c, b: { c: d } },
{ a: e, b: { c: f } }
]
result = ([y,z] for { a: y, b: { c: z } } in arr)
arrayEq [[a,b],[c,d],[e,f]], result
test "implicit destructuring assignment in array of arrays", ->
a={}; b={}; c={}; d={}; e={}; f={}
arr = [[a, [b]], [c, [d]], [e, [f]]]
result = ([y,z] for [y, [z]] in arr)
arrayEq [[a,b],[c,d],[e,f]], result
test "issue #1124: don't assign a variable in two scopes", ->
lista = [1, 2, 3, 4, 5]
listb = (_i + 1 for _i in lista)
arrayEq [2, 3, 4, 5, 6], listb

View File

@@ -1,181 +0,0 @@
# Conditionals
# ------------
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
#### Basic Conditionals
test "basic conditionals", ->
if false
ok false
else if false
ok false
else
ok true
if true
ok true
else if true
ok false
else
ok true
unless true
ok false
else unless true
ok false
else
ok true
unless false
ok true
else unless false
ok false
else
ok true
test "single-line conditional", ->
if false then ok false else ok true
unless false then ok true else ok false
test "nested conditionals", ->
nonce = {}
eq nonce, (if true
unless false
if false then false else
if true
nonce)
test "nested single-line conditionals", ->
nonce = {}
a = if false then undefined else b = if 0 then undefined else nonce
eq nonce, a
eq nonce, b
c = if false then undefined else (if 0 then undefined else nonce)
eq nonce, c
d = if true then id(if false then undefined else nonce)
eq nonce, d
test "empty conditional bodies", ->
eq undefined, (if false
else if false
else)
test "conditional bodies containing only comments", ->
eq undefined, (if true
###
block comment
###
else
# comment
)
eq undefined, (if false
# comment
else if true
###
block comment
###
else)
test "return value of if-else is from the proper body", ->
nonce = {}
eq nonce, if false then undefined else nonce
test "return value of unless-else is from the proper body", ->
nonce = {}
eq nonce, unless true then undefined else nonce
#### Interactions With Functions
test "single-line function definition with single-line conditional", ->
fn = -> if 1 < 0.5 then 1 else -1
ok fn() is -1
test "function resturns conditional value with no `else`", ->
fn = ->
return if false then true
eq undefined, fn()
test "function returns a conditional value", ->
a = {}
fnA = ->
return if false then undefined else a
eq a, fnA()
b = {}
fnB = ->
return unless false then b else undefined
eq b, fnB()
test "passing a conditional value to a function", ->
nonce = {}
eq nonce, id if false then undefined else nonce
test "unmatched `then` should catch implicit calls", ->
a = 0
trueFn = -> true
if trueFn undefined then a += 1
eq 1, a
#### if-to-ternary
test "if-to-ternary with instanceof requires parentheses", ->
nonce = {}
eq nonce, (if {} instanceof Object
nonce
else
undefined)
test "if-to-ternary as part of a larger operation requires parentheses", ->
ok 2, 1 + if false then 0 else 1
#### Odd Formatting
test "if-else indented within an assignment", ->
nonce = {}
result =
if false
undefined
else
nonce
eq nonce, result
test "suppressed indentation via assignment", ->
nonce = {}
result =
if false then undefined
else if no then undefined
else if 0 then undefined
else if 1 < 0 then undefined
else id(
if false then undefined
else nonce
)
eq nonce, result
test "tight formatting with leading `then`", ->
nonce = {}
eq nonce,
if true
then nonce
else undefined
test "#738", ->
nonce = {}
fn = if true then -> nonce
eq nonce, fn()
test "#748: trailing reserved identifiers", ->
nonce = {}
obj = delete: true
result = if obj.delete
nonce
eq nonce, result

420
test/control_flow.coffee Normal file
View File

@@ -0,0 +1,420 @@
# Control Flow
# ------------
# * Conditionals
# * Loops
# * For
# * While
# * Until
# * Loop
# * Switch
# TODO: make sure postfix forms and expression coercion are properly tested
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
# Conditionals
test "basic conditionals", ->
if false
ok false
else if false
ok false
else
ok true
if true
ok true
else if true
ok false
else
ok true
unless true
ok false
else unless true
ok false
else
ok true
unless false
ok true
else unless false
ok false
else
ok true
test "single-line conditional", ->
if false then ok false else ok true
unless false then ok true else ok false
test "nested conditionals", ->
nonce = {}
eq nonce, (if true
unless false
if false then false else
if true
nonce)
test "nested single-line conditionals", ->
nonce = {}
a = if false then undefined else b = if 0 then undefined else nonce
eq nonce, a
eq nonce, b
c = if false then undefined else (if 0 then undefined else nonce)
eq nonce, c
d = if true then id(if false then undefined else nonce)
eq nonce, d
test "empty conditional bodies", ->
eq undefined, (if false
else if false
else)
test "conditional bodies containing only comments", ->
eq undefined, (if true
###
block comment
###
else
# comment
)
eq undefined, (if false
# comment
else if true
###
block comment
###
else)
test "return value of if-else is from the proper body", ->
nonce = {}
eq nonce, if false then undefined else nonce
test "return value of unless-else is from the proper body", ->
nonce = {}
eq nonce, unless true then undefined else nonce
test "assign inside the condition of a conditional statement", ->
nonce = {}
if a = nonce then 1
eq nonce, a
1 if b = nonce
eq nonce, b
# Interactions With Functions
test "single-line function definition with single-line conditional", ->
fn = -> if 1 < 0.5 then 1 else -1
ok fn() is -1
test "function resturns conditional value with no `else`", ->
fn = ->
return if false then true
eq undefined, fn()
test "function returns a conditional value", ->
a = {}
fnA = ->
return if false then undefined else a
eq a, fnA()
b = {}
fnB = ->
return unless false then b else undefined
eq b, fnB()
test "passing a conditional value to a function", ->
nonce = {}
eq nonce, id if false then undefined else nonce
test "unmatched `then` should catch implicit calls", ->
a = 0
trueFn = -> true
if trueFn undefined then a++
eq 1, a
# if-to-ternary
test "if-to-ternary with instanceof requires parentheses", ->
nonce = {}
eq nonce, (if {} instanceof Object
nonce
else
undefined)
test "if-to-ternary as part of a larger operation requires parentheses", ->
ok 2, 1 + if false then 0 else 1
# Odd Formatting
test "if-else indented within an assignment", ->
nonce = {}
result =
if false
undefined
else
nonce
eq nonce, result
test "suppressed indentation via assignment", ->
nonce = {}
result =
if false then undefined
else if no then undefined
else if 0 then undefined
else if 1 < 0 then undefined
else id(
if false then undefined
else nonce
)
eq nonce, result
test "tight formatting with leading `then`", ->
nonce = {}
eq nonce,
if true
then nonce
else undefined
test "#738", ->
nonce = {}
fn = if true then -> nonce
eq nonce, fn()
test "#748: trailing reserved identifiers", ->
nonce = {}
obj = delete: true
result = if obj.delete
nonce
eq nonce, result
test "basic `while` loops", ->
i = 5
list = while i -= 1
i * 2
ok list.join(' ') is "8 6 4 2"
i = 5
list = (i * 3 while i -= 1)
ok list.join(' ') is "12 9 6 3"
i = 5
func = (num) -> i -= num
assert = -> ok i < 5 > 0
results = while func 1
assert()
i
ok results.join(' ') is '4 3 2 1'
i = 10
results = while i -= 1 when i % 2 is 0
i * 2
ok results.join(' ') is '16 12 8 4'
test "Issue 759: `if` within `while` condition", ->
2 while if 1 then 0
test "assignment inside the condition of a `while` loop", ->
nonce = {}
count = 1
a = nonce while count--
eq nonce, a
count = 1
while count--
b = nonce
eq nonce, b
test "While over break.", ->
i = 0
result = while i < 10
i++
break
arrayEq result, []
test "While over continue.", ->
i = 0
result = while i < 10
i++
continue
arrayEq result, []
test "Basic `until`", ->
value = false
i = 0
results = until value
value = true if i is 5
i++
ok i is 6
test "Basic `loop`", ->
i = 5
list = []
loop
i -= 1
break if i is 0
list.push i * 2
ok list.join(' ') is '8 6 4 2'
test "break at the top level", ->
for i in [1,2,3]
result = i
if i == 2
break
eq 2, result
test "break *not* at the top level", ->
someFunc = ->
i = 0
while ++i < 3
result = i
break if i > 1
result
eq 2, someFunc()
test "basic `switch`", ->
num = 10
result = switch num
when 5 then false
when 'a'
true
true
false
when 10 then true
# Mid-switch comment with whitespace
# and multi line
when 11 then false
else false
ok result
func = (num) ->
switch num
when 2, 4, 6
true
when 1, 3, 5
false
ok func(2)
ok func(6)
ok !func(3)
eq func(8), undefined
test "Ensure that trailing switch elses don't get rewritten.", ->
result = false
switch "word"
when "one thing"
doSomething()
else
result = true unless false
ok result
result = false
switch "word"
when "one thing"
doSomething()
when "other thing"
doSomething()
else
result = true unless false
ok result
test "Should be able to handle switches sans-condition.", ->
result = switch
when null then 0
when !1 then 1
when '' not of {''} then 2
when [] not instanceof Array then 3
when true is false then 4
when 'x' < 'y' > 'z' then 5
when 'a' in ['b', 'c'] then 6
when 'd' in (['e', 'f']) then 7
else ok
eq result, ok
test "Should be able to use `@properties` within the switch clause.", ->
obj = {
num: 101
func: ->
switch @num
when 101 then '101!'
else 'other'
}
ok obj.func() is '101!'
test "Should be able to use `@properties` within the switch cases.", ->
obj = {
num: 101
func: (yesOrNo) ->
result = switch yesOrNo
when yes then @num
else 'other'
result
}
ok obj.func(yes) is 101
test "Switch with break as the return value of a loop.", ->
i = 10
results = while i > 0
i--
switch i % 2
when 1 then i
when 0 then break
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
test "Issue #997. Switch doesn't fallthrough.", ->
val = 1
switch true
when true
if false
return 5
else
val = 2
eq val, 1

View File

@@ -1,17 +1,17 @@
# Exceptions
# ----------
# Exception Handling
# ------------------
# shared nonce
nonce = {}
#### Throw
# Throw
test "basic exception throwing", ->
throws (-> throw 'error'), 'error'
#### Empty Try/Catch/Finally
# Empty Try/Catch/Finally
test "try can exist alone", ->
try
@@ -43,7 +43,7 @@ test "single-line try/catch/finally with empty try, empty catch, empty finally",
try catch err then finally
#### Try/Catch/Finally as an Expression
# Try/Catch/Finally as an Expression
test "return the result of try when no exception is thrown", ->
result = try
@@ -81,7 +81,7 @@ test "optional catch", ->
eq nonce, fn()
#### Try/Catch/Finally Interaction With Other Constructs
# Try/Catch/Finally Interaction With Other Constructs
test "try/catch with empty catch as last statement in a function body", ->
fn = ->

118
test/formatting.coffee Normal file
View File

@@ -0,0 +1,118 @@
# Formatting
# ----------
# TODO: maybe this file should be split up into their respective sections:
# operators -> operators
# array literals -> array literals
# string literals -> string literals
# function invocations -> function invocations
# * Line Continuation
# * Property Accesss
# * Operators
# * Array Literals
# * Function Invocations
# * String Literals
doesNotThrow -> CoffeeScript.compile "a = then b"
test "multiple semicolon-separated statements in parentheticals", ->
nonce = {}
eq nonce, (1; 2; nonce)
eq nonce, (-> return (1; 2; nonce))()
# Line Continuation
# Property Access
test "chained accesses split on period/newline, backwards and forwards", ->
str = 'abc'
result = str.
split('').
reverse().
reverse().
reverse()
arrayEq ['c','b','a'], result
arrayEq ['c','b','a'], str.
split('').
reverse().
reverse().
reverse()
result = str
.split('')
.reverse()
.reverse()
.reverse()
arrayEq ['c','b','a'], result
arrayEq ['c','b','a'], str
.split('')
.reverse()
.reverse()
.reverse()
arrayEq ['c','b','a'], str.
split('')
.reverse().
reverse()
.reverse()
# Operators
test "newline suppression for operators", ->
six =
1 +
2 +
3
eq 6, six
test "`?.` and `::` should continue lines", ->
ok not Date
::
?.foo
#eq Object::toString, Date?.
#prototype
#::
#?.foo
doesNotThrow -> CoffeeScript.compile """
oh. yes
oh?. true
oh:: return
"""
doesNotThrow -> CoffeeScript.compile """
a?[b..]
a?[...b]
a?[b..c]
"""
# Array Literals
test "indented array literals don't trigger whitespace rewriting", ->
getArgs = -> arguments
result = getArgs(
[[[[[],
[]],
[[]]]],
[]])
eq 1, result.length
# Function Invocations
doesNotThrow -> CoffeeScript.compile """
obj = then fn 1,
1: 1
a:
b: ->
fn c,
d: e
f: 1
"""
# String Literals
test "indented heredoc", ->
result = ((_) -> _)(
"""
abc
""")
eq "abc", result

View File

@@ -0,0 +1,445 @@
# Function Invocation
# -------------------
# * Function Invocation
# * Splats in Function Invocations
# * Implicit Returns
# * Explicit Returns
# shared identity function
id = (_) -> if arguments.length is 1 then _ else [arguments...]
test "basic argument passing", ->
a = {}
b = {}
c = {}
eq 1, (id 1)
eq 2, (id 1, 2)[1]
eq a, (id a)
eq c, (id a, b, c)[2]
test "passing arguments on separate lines", ->
a = {}
b = {}
c = {}
ok(id(
a
b
c
)[1] is b)
eq(0, id(
0
10
)[0])
eq(a,id(
a
))
eq b,
(id b)
test "optional parens can be used in a nested fashion", ->
call = (func) -> func()
add = (a,b) -> a + b
result = call ->
inner = call ->
add 5, 5
ok result is 10
test "hanging commas and semicolons in argument list", ->
fn = () -> arguments.length
eq 2, fn(0,1,)
eq 3, fn 0, 1,
2
eq 2, fn(0, 1;)
# TODO: this test fails (the string compiles), but should it?
#throws -> CoffeeScript.compile "fn(0,1,;)"
throws -> CoffeeScript.compile "fn(0,1,;;)"
throws -> CoffeeScript.compile "fn(0, 1;,)"
throws -> CoffeeScript.compile "fn(,0)"
throws -> CoffeeScript.compile "fn(;0)"
test "function invocation", ->
func = ->
return if true
eq undefined, func()
result = ("hello".slice) 3
ok result is 'lo'
test "And even with strange things like this:", ->
funcs = [((x) -> x), ((x) -> x * x)]
result = funcs[1] 5
ok result is 25
test "More fun with optional parens.", ->
fn = (arg) -> arg
ok fn(fn {prop: 101}).prop is 101
okFunc = (f) -> ok(f())
okFunc -> true
test "chained function calls", ->
nonce = {}
identityWrap = (x) ->
-> x
eq nonce, identityWrap(identityWrap(nonce))()()
eq nonce, (identityWrap identityWrap nonce)()()
test "Multi-blocks with optional parens.", ->
fn = (arg) -> arg
result = fn( ->
fn ->
"Wrapped"
)
ok result()() is 'Wrapped'
test "method calls", ->
fnId = (fn) -> -> fn.apply this, arguments
math = {
add: (a, b) -> a + b
anonymousAdd: (a, b) -> a + b
fastAdd: fnId (a, b) -> a + b
}
ok math.add(5, 5) is 10
ok math.anonymousAdd(10, 10) is 20
ok math.fastAdd(20, 20) is 40
test "Ensure that functions can have a trailing comma in their argument list", ->
mult = (x, mids..., y) ->
x *= n for n in mids
x *= y
ok mult(1, 2,) is 2
ok mult(1, 2, 3,) is 6
ok mult(10, (i for i in [1..6])...) is 7200
test "`@` and `this` should both be able to invoke a method", ->
nonce = {}
fn = (arg) -> eq nonce, arg
fn.withAt = -> @ nonce
fn.withThis = -> this nonce
fn.withAt()
fn.withThis()
test "Trying an implicit object call with a trailing function.", ->
a = null
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
meth 'apple', b: 1, a: 13, ->
'orange'
ok a is '13 apple orange'
test "Ensure that empty functions don't return mistaken values.", ->
obj =
func: (@param, @rest...) ->
ok obj.func(101, 102, 103, 104) is undefined
ok obj.param is 101
ok obj.rest.join(' ') is '102 103 104'
test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->
sum = (one, two) -> one() + two()
result = sum ->
7 + 9
, ->
1 + 3
ok result is 20
test "Implicit call with a trailing if statement as a param.", ->
func = -> arguments[1]
result = func 'one', if false then 100 else 13
ok result is 13
test "Test more function passing:", ->
sum = (one, two) -> one() + two()
result = sum( ->
1 + 2
, ->
2 + 1
)
ok result is 6
sum = (a, b) -> a + b
result = sum(1
, 2)
ok result is 3
test "Chained blocks, with proper indentation levels:", ->
counter =
results: []
tick: (func) ->
@results.push func()
this
counter
.tick ->
3
.tick ->
2
.tick ->
1
arrayEq [3,2,1], counter.results
test "This is a crazy one.", ->
x = (obj, func) -> func obj
ident = (x) -> x
result = x {one: ident 1}, (obj) ->
inner = ident(obj)
ident inner
ok result.one is 1
test "More paren compilation tests:", ->
reverse = (obj) -> obj.reverse()
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
test "Test for inline functions with parentheses and implicit calls.", ->
combine = (func, num) -> func() * num
result = combine (-> 1 + 2), 3
ok result is 9
test "Test for calls/parens/multiline-chains.", ->
f = (x) -> x
result = (f 1).toString()
.length
ok result is 1
test "Test implicit calls in functions in parens:", ->
result = ((val) ->
[].push val
val
)(10)
ok result is 10
test "Ensure that chained calls with indented implicit object literals below are alright.", ->
result = null
obj =
method: (val) -> this
second: (hash) -> result = hash.three
obj
.method(
101
).second(
one:
two: 2
three: 3
)
eq result, 3
test "Test newline-supressed call chains with nested functions.", ->
obj =
call: -> this
func = ->
obj
.call ->
one two
.call ->
three four
101
eq func(), 101
test "Implicit objects with number arguments.", ->
func = (x, y) -> y
obj =
prop: func "a", 1
ok obj.prop is 1
test "Non-spaced unary and binary operators should cause a function call.", ->
func = (val) -> val + 1
ok (func +5) is 6
ok (func -5) is -4
test "Prefix unary assignment operators are allowed in parenless calls.", ->
func = (val) -> val + 1
val = 5
ok (func --val) is 5
test "#855: execution context for `func arr...` should be `null`", ->
contextTest = -> eq @, if window? then window else global
array = []
contextTest array
contextTest.apply null, array
contextTest array...
test "#904: Destructuring function arguments with same-named variables in scope", ->
a = b = nonce = {}
fn = ([a,b]) -> {a:a,b:b}
result = fn([c={},d={}])
eq c, result.a
eq d, result.b
eq nonce, a
eq nonce, b
test "caching base value", ->
obj =
index: 0
0: {method: -> this is obj[0]}
ok obj[obj.index++].method([]...)
test "passing splats to functions", ->
arrayEq [0..4], id id [0..4]...
fn = (a, b, c..., d) -> [a, b, c, d]
range = [0..3]
[first, second, others, last] = fn range..., 4, [5...8]...
eq 0, first
eq 1, second
arrayEq [2..6], others
eq 7, last
test "splat variables are local to the function", ->
outer = "x"
clobber = (avar, outer...) -> outer
clobber "foo", "bar"
eq "x", outer
test "Issue 894: Splatting against constructor-chained functions.", ->
x = null
class Foo
bar: (y) -> x = y
new Foo().bar([101]...)
eq x, 101
test "Functions with splats being called with too few arguments.", ->
pen = null
method = (first, variable..., penultimate, ultimate) ->
pen = penultimate
method 1, 2, 3, 4, 5, 6, 7, 8, 9
ok pen is 8
method 1, 2, 3
ok pen is 2
method 1, 2
ok pen is 2
test "splats with super() within classes.", ->
class Parent
meth: (args...) ->
args
class Child extends Parent
meth: ->
nums = [3, 2, 1]
super nums...
ok (new Child).meth().join(' ') is '3 2 1'
test "#1011: passing a splat to a method of a number", ->
eq '1011', 11.toString [2]...
eq '1011', (31).toString [3]...
eq '1011', 69.0.toString [4]...
eq '1011', (131.0).toString [5]...
test "implicit return", ->
eq ok, new ->
ok
### Should `return` implicitly ###
### even with trailing comments. ###
test "implicit returns with multiple branches", ->
nonce = {}
fn = ->
if false
for a in b
return c if d
else
nonce
eq nonce, fn()
test "implicit returns with switches", ->
nonce = {}
fn = ->
switch nonce
when nonce then nonce
else return undefined
eq nonce, fn()
test "preserve context when generating closure wrappers for expression conversions", ->
nonce = {}
obj =
property: nonce
method: ->
this.result = if false
10
else
"a"
"b"
this.property
eq nonce, obj.method()
eq nonce, obj.property
test "don't wrap 'pure' statements in a closure", ->
nonce = {}
items = [0, 1, 2, 3, nonce, 4, 5]
fn = (items) ->
for item in items
return item if item is nonce
eq nonce, fn items
#### Unusual `new` Usage
test "usage of `new` is careful about where the invocation parens end up", ->
eq 'object', typeof new try Array
eq 'object', typeof new do -> ->

View File

@@ -1,48 +1,78 @@
# Arguments
# ---------
# Function Literals
# -----------------
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
# TODO: add indexing and method invocation tests: (->)[0], (->).call()
test "basic argument passing tests", ->
a = {}
b = {}
c = {}
eq 1, (id 1)
eq 2, (id 1, 2)[1]
eq a, (id a)
eq c, (id a, b, c)[2]
# * Function Definition
# * Bound Function Definition
# * Parameter List Features
# * Splat Parameters
# * Context (@) Parameters
# * Parameter Destructuring
# * Default Parameters
test "passing arguments on separate lines", ->
a = {}
b = {}
c = {}
ok(id(
a
b
c
)[1] is b)
eq(0, id(
0
10
)[0])
eq(a,id(
a
))
eq b,
(id b)
# Function Definition
test "reference `arguments` inside of functions", ->
sumOfArgs = ->
sum = (a,b) -> a + b
sum = 0
sum += num for num in arguments
sum
x = 1
y = {}
y.x = -> 3
ok x is 1
ok typeof(y.x) is 'function'
ok y.x instanceof Function
ok y.x() is 3
eq 10, sumOfArgs(0, 1, 2, 3, 4)
# The empty function should not cause a syntax error.
->
() ->
# Multiple nested function declarations mixed with implicit calls should not
# cause a syntax error.
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
# with multiple single-line functions on the same line.
func = (x) -> (x) -> (x) -> x
ok func(1)(2)(3) is 3
# Make incorrect indentation safe.
func = ->
obj = {
key: 10
}
obj.key - 5
eq func(), 5
# Ensure that functions with the same name don't clash with helper functions.
del = -> 5
ok del() is 5
#### Parameter List Features
# Bound Function Definition
obj =
bound: ->
(=> this)()
unbound: ->
(-> this)()
nested: ->
(=>
(=>
(=> this)()
)()
)()
eq obj, obj.bound()
ok obj isnt obj.unbound()
eq obj, obj.nested()
test "self-referencing functions", ->
changeMe = ->
changeMe = 2
changeMe()
eq changeMe, 2
# Parameter List Features
test "splats", ->
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
@@ -125,3 +155,11 @@ test "default values with splatted arguments", ->
eq 5, withSplats(1,1)
eq 1, withSplats(1,1,1)
eq 2, withSplats(1,1,1,1)
test "default values with function calls", ->
doesNotThrow -> CoffeeScript.compile "(x = f()) ->"
test "arguments vs parameters", ->
doesNotThrow -> CoffeeScript.compile "f(x) ->"
f = (g) -> g()
eq 5, f (x) -> 5

View File

@@ -5,7 +5,7 @@
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
#### `starts`
# `starts`
test "the `starts` helper tests if a string starts with another string", ->
ok starts('01234', '012')
@@ -16,7 +16,7 @@ test "the `starts` helper can take an optional offset", ->
ok not starts('01234', '01', 1)
#### `ends`
# `ends`
test "the `ends` helper tests if a string ends with another string", ->
ok ends('01234', '234')
@@ -27,7 +27,7 @@ test "the `ends` helper can take an optional offset", ->
ok not ends('01234', '234', 6)
#### `compact`
# `compact`
test "the `compact` helper removes falsey values from an array, preserves truthy ones", ->
allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true]
@@ -35,7 +35,7 @@ test "the `compact` helper removes falsey values from an array, preserves truthy
arrayEq truthyValues, compact(allValues)
#### `count`
# `count`
test "the `count` helper counts the number of occurances of a string in another string", ->
eq 1/0, count('abc', '')
@@ -46,7 +46,7 @@ test "the `count` helper counts the number of occurances of a string in another
eq 2, count('abcdabcd','abc')
#### `merge`
# `merge`
test "the `merge` helper makes a new object with all properties of the objects given as its arguments", ->
ary = [0, 1, 2, 3, 4]
@@ -58,7 +58,7 @@ test "the `merge` helper makes a new object with all properties of the objects g
eq val, merged[key]
#### `extend`
# `extend`
test "the `extend` helper performs a shallow copy", ->
ary = [0, 1, 2, 3]
@@ -69,7 +69,7 @@ test "the `extend` helper performs a shallow copy", ->
eq 2, obj[2]
#### `flatten`
# `flatten`
test "the `flatten` helper flattens an array", ->
success = yes
@@ -77,7 +77,7 @@ test "the `flatten` helper flattens an array", ->
ok success
#### `del`
# `del`
test "the `del` helper deletes a property from an object and returns the deleted value", ->
obj = [0, 1, 2]
@@ -85,7 +85,7 @@ test "the `del` helper deletes a property from an object and returns the deleted
ok 1 not of obj
#### `last`
# `last`
test "the `last` helper returns the last item of an array-like object", ->
ary = [0, 1, 2, 3, 4]

View File

@@ -1,23 +1,24 @@
eq '(((dollars)))', '\(\(\(dollars\)\)\)'
eq 'one two three', "one
two
three"
eq "four five", 'four
# Interpolation
# -------------
five'
# * String Interpolation
# * Regular Expression Interpolation
#647
eq "''Hello, World\\''", '''
'\'Hello, World\\\''
'''
eq '""Hello, World\\""', """
"\"Hello, World\\\""
"""
eq 'Hello, World\n', '''
Hello, World\
# String Interpolation
'''
# TODO: refactor string interpolation tests
eq 'multiline nested "interpolations" work', """multiline #{
"nested #{
ok true
"\"interpolations\""
}"
} work"""
# Issue #923: Tricky interpolation.
eq "#{ "{" }", "{"
eq "#{ '#{}}' } }", '#{}} }'
eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'"
hello = 'Hello'
world = 'World'
@@ -28,37 +29,30 @@ ok "#{hello}##{world}" is 'Hello#World'
ok "Hello #{ 1 + 2 } World" is 'Hello 3 World'
ok "#{hello} #{ 1 + 2 } #{world}" is "Hello 3 World"
[s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g']
ok "#{s}#{t}#{r}#{i}#{n}#{g}" is 'string'
ok "\#{s}\#{t}\#{r}\#{i}\#{n}\#{g}" is '#{s}#{t}#{r}#{i}#{n}#{g}'
ok "\#{string}" is '#{string}'
ok "\#{Escaping} first" is '#{Escaping} first'
ok "Escaping \#{in} middle" is 'Escaping #{in} middle'
ok "Escaping \#{last}" is 'Escaping #{last}'
ok "##" is '##'
ok "#{}" is ''
ok "#{}A#{} #{} #{}B#{}" is 'A B'
ok "\\\#{}" is '\\#{}'
ok "I won ##{20} last night." is 'I won #20 last night.'
ok "I won ##{'#20'} last night." is 'I won ##20 last night.'
ok "#{hello + world}" is 'HelloWorld'
ok "#{hello + ' ' + world + '!'}" is 'Hello World!'
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ok "values: #{list.join(', ')}, length: #{list.length}." is 'values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, length: 10.'
ok "values: #{list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9'
obj = {
name: 'Joe'
hi: -> "Hello #{@name}."
@@ -67,7 +61,6 @@ obj = {
ok obj.hi() is "Hello Joe."
ok obj.cya() is "Goodbye Joe."
ok "With #{"quotes"}" is 'With quotes'
ok 'With #{"quotes"}' is 'With #{"quotes"}'
@@ -78,41 +71,54 @@ ok "Hello #{world ? "#{hello}"}" is 'Hello World'
ok "Hello #{"#{"#{obj["name"]}" + '!'}"}" is 'Hello Joe!'
a = """
Hello #{ "Joe" }
"""
ok a is "Hello Joe"
a = 1
b = 2
c = 3
ok "#{a}#{b}#{c}" is '123'
result = null
stash = (str) -> result = str
stash "a #{ ('aa').replace /a/g, 'b' } c"
ok result is 'a bb c'
foo = "hello"
ok "#{foo.replace("\"", "")}" is 'hello'
val = 10
a = """
basic heredoc #{val}
on two lines
"""
b = '''
basic heredoc #{val}
on two lines
'''
ok a is "basic heredoc 10\non two lines"
ok b is "basic heredoc \#{val}\non two lines"
eq 'multiline nested "interpolations" work', """multiline #{
"nested #{
ok true
"nested #{(->
ok yes
"\"interpolations\""
}"
)()}"
} work"""
# Issue #923: Tricky interpolation.
eq "#{ "{" }", "{"
# Regular Expression Interpolation
eq "#{ '#{}}' } }", '#{}} }'
eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'"
# TODO: improve heregex interpolation tests
test "heregex interpolation", ->
eq /\\#{}\\\"/ + '', ///
#{
"#{ '\\' }" # normal comment
}
# regex comment
\#{}
\\ \"
/// + ''

View File

@@ -0,0 +1,10 @@
# Javascript Literals
# -------------------
# TODO: refactor javascript literal tests
# TODO: add indexing and method invocation tests: `[1]`[0] is 1, `function(){}`.call()
eq '\\`', `
// Inline JS
"\\\`"
`

44
test/numbers.coffee Normal file
View File

@@ -0,0 +1,44 @@
# Number Literals
# ---------------
# * Decimal Integer Literals
# * Octal Integer Literals
# * Hexadecimal Integer Literals
# * Scientific Notation Integer Literals
# * Scientific Notation Non-Integer Literals
# * Non-Integer Literals
# Decimal Integer Literals
test "call methods directly on numbers", ->
eq 4, 4.valueOf()
eq '11', 4.toString 3
eq -1, 3 -4
#764: Numbers should be indexable
eq Number::toString, 42['toString']
eq Number::toString, 42.toString
# Non-Integer Literals
# Decimal number literals.
value = .25 + .75
ok value is 1
value = 0.0 + -.25 - -.75 + 0.0
ok value is 0.5
#764: Numbers should be indexable
eq Number::toString, 4.2['toString']
eq Number::toString, .42['toString']
eq Number::toString, 4.2.toString
eq Number::toString, .42.toString
test '#1168: leading floating point suppresses newline', ->
eq 1, do ->
1
.5 + 0.5

View File

@@ -1,47 +1,14 @@
a = [((x) -> x), ((x) -> x * x)]
# Object Literals
# ---------------
ok a.length is 2
neg = (3 -4)
ok neg is -1
# Decimal number literals.
value = .25 + .75
ok value is 1
value = 0.0 + -.25 - -.75 + 0.0
ok value is 0.5
# Can call methods directly on numbers.
4.valueOf() is 4
func = ->
return if true
ok func() is undefined
trailingComma = [1, 2, 3,]
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
trailingComma = [
1, 2, 3,
4, 5, 6
7, 8, 9,
]
(sum = (sum or 0) + n) for n in trailingComma
# TODO: refactor object literal tests
# TODO: add indexing and method invocation tests: {a}['a'] is a, {a}.a()
trailingComma = {k1: "v1", k2: 4, k3: (-> true),}
ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1")
ok {a: (num) -> num is 10 }.a 10
moe = {
name: 'Moe'
greet: (salutation) ->
@@ -50,138 +17,70 @@ moe = {
@['greet'] "Hello"
10: 'number'
}
ok moe.hello() is "Hello Moe"
ok moe[10] is 'number'
moe.hello = ->
this['greet'] "Hello"
ok moe.hello() is 'Hello Moe'
obj = {
is: -> yes,
'not': -> no,
}
ok obj.is()
ok not obj.not()
### Top-level object literal... ###
obj: 1
### ...doesn't break things. ###
# Funky indentation within non-comma-seperated arrays.
result = [['a']
{b: 'c'}]
ok result[0][0] is 'a'
ok result[1]['b'] is 'c'
# Object literals should be able to include keywords.
obj = {class: 'höt'}
obj.function = 'dog'
ok obj.class + obj.function is 'hötdog'
# But keyword assignment should be smart enough not to stringify variables.
func = ->
this == 'this'
ok func() is false
# Implicit objects as part of chained calls.
pluck = (x) -> x.a
eq 100, pluck pluck pluck a: a: a: 100
# New fancy implicit objects:
config =
development:
server: 'localhost'
timeout: 10
test "YAML-style object literals", ->
obj =
a: 1
b: 2
eq 1, obj.a
eq 2, obj.b
production:
server: 'dreamboat'
timeout: 1000
config =
development:
server: 'localhost'
timeout: 10
ok config.development.server is 'localhost'
ok config.production.server is 'dreamboat'
ok config.development.timeout is 10
ok config.production.timeout is 1000
production:
server: 'dreamboat'
timeout: 1000
obj =
a: 1
b: 2
ok obj.a is 1
ok obj.b is 2
ok config.development.server is 'localhost'
ok config.production.server is 'dreamboat'
ok config.development.timeout is 10
ok config.production.timeout is 1000
obj =
a: 1,
b: 2,
ok obj.a is 1
ok obj.b is 2
# Implicit objects nesting.
obj =
options:
value: yes
fn: ->
{}
null
ok obj.options.value is yes
ok obj.fn() is null
# Implicit arguments to function calls:
func = (obj) -> obj.a
func2 = -> arguments
result = func
a: 10
ok result is 10
result = func
"a": 20
ok result is 20
third = (a, b, c) -> c
obj =
one: 'one'
two: third 'one', 'two', 'three'
ok obj.one is 'one'
ok obj.two is 'three'
a = b = undefined
result = func
b:1
a
ok result is undefined
result = func
a:
b:2
b:1
ok result.b is 2
result = func2
a:1
b
c:1
ok result.length is 3
ok result[2].c is 1
# Implicit objects with wacky indentation:
obj =
'reverse': (obj) ->
@@ -202,7 +101,6 @@ obj =
[],
[],
[]]
ok obj.abc().join(' ') is 'a b c'
ok obj.one.length is 5
ok obj.one[4] is 4
@@ -212,29 +110,14 @@ ok obj.red.orange.yellow.green is 'blue'
ok obj.red.indigo is 'violet'
ok obj.misdent.toString() is ',,,'
second = (x, y) -> y
obj = then second 'the',
1: 1
two:
three: ->
four five,
six: seven
three: 3
ok obj[1] is 1
ok obj.three is 3
# Implicit objects as part of chained calls.
pluck = (x) -> x.a
eq 100, pluck pluck pluck a: a: a: 100
eq '\\`', `
// Inline JS
"\\\`"
`
#542: Objects leading expression statement should be parenthesized.
{f: -> ok yes }.f() + 1
# String-keyed objects shouldn't suppress newlines.
one =
'>!': 3
six: -> 10
ok not one.six
# Shorthand objects with property references.
obj =
@@ -244,27 +127,91 @@ obj =
two: 2
object: -> {@one, @two}
list: -> [@one, @two]
result = obj.object()
eq result.one, 1
eq result.two, 2
eq result.two, obj.list()[1]
third = (a, b, c) -> c
obj =
one: 'one'
two: third 'one', 'two', 'three'
ok obj.one is 'one'
ok obj.two is 'three'
#542: Objects leading expression statement should be parenthesized.
{f: -> ok yes }.f() + 1
test "invoking functions with implicit object literals", ->
generateGetter = (prop) -> (obj) -> obj[prop]
getA = generateGetter 'a'
getArgs = -> arguments
a = b = 30
result = getA
a: 10
eq 10, result
#764: Boolean/Number should be indexable.
ok 42['toString']
ok on['toString']
result = getA
"a": 20
eq 20, result
result = getA a,
b:1
eq undefined, result
# String-keyed objects shouldn't suppress newlines.
one =
'>!': 3
six: -> 10
result = getA b:1
a:43
eq 43, result
ok not one.six
result = getA b:1,
a:62
eq undefined, result
result = getA
b:1
a
eq undefined, result
result = getA
a:
b:2
b:1
eq 2, result.b
result = getArgs
a:1
b
c:1
ok result.length is 3
ok result[2].c is 1
result = getA b: 13, a: 42, 2
eq 42, result
result = getArgs a:1, (1 + 1)
ok result[1] is 2
result = getArgs a:1, b
ok result.length is 2
ok result[1] is 30
result = getArgs a:1, b, b:1, a
ok result.length is 4
ok result[2].b is 1
throws -> CoffeeScript.compile "a = b:1, c"
test "some weird indentation in YAML-style object literals", ->
two = (a, b) -> b
obj = then two 1,
1: 1
a:
b: ->
fn c,
d: e
f: 1
eq 1, obj[1]
test "#1274: `{} = a()` compiles to `false` instead of `a()`", ->
a = false
fn = -> a = true
{} = fn()
ok a

View File

@@ -1,6 +1,13 @@
# Operators
# ---------
# * Operators
# * Existential Operator (Binary)
# * Existential Operator (Unary)
# * Aliased Operators
# * [not] in/of
# * Chained Comparison
test "binary (2-ary) math operators do not require spaces", ->
a = 1
b = -1
@@ -42,84 +49,72 @@ test "`instanceof`", ->
ok new Number not instanceof String
ok new Array not instanceof Boolean
test "use `::` operator on keywords `this` and `@`", ->
nonce = {}
obj =
withAt: -> @::prop
withThis: -> this::prop
obj.prototype = prop: nonce
eq nonce, obj.withAt()
eq nonce, obj.withThis()
#### Compound Assignment Operators
test "boolean operators", ->
# Existential Operator (Binary)
test "binary existential operator", ->
nonce = {}
a = 0
a or= nonce
eq nonce, a
b = a ? nonce
eq nonce, b
b = 1
b or= nonce
eq 1, b
a = null
b = undefined
b = a ? nonce
eq nonce, b
c = 0
c and= nonce
eq 0, c
a = false
b = a ? nonce
eq false, b
d = 1
d and= nonce
eq nonce, d
a = 0
b = a ? nonce
eq 0, b
# ensure that RHS is treated as a group
e = f = false
e and= f or true
eq false, e
test "binary existential operator conditionally evaluates second operand", ->
i = 1
func = -> i -= 1
result = func() ? func()
eq result, 0
test "compound assignment as a sub expression", ->
[a, b, c] = [1, 2, 3]
eq 6, (a + b += c)
eq 1, a
eq 5, b
eq 3, c
# *note: this test could still use refactoring*
test "compound assignment should be careful about caching variables", ->
count = 0
list = []
list[++count] or= 1
eq 1, list[1]
eq 1, count
list[++count] ?= 2
eq 2, list[2]
eq 2, count
list[count++] and= 6
eq 6, list[2]
eq 3, count
base = ->
++count
base
base().four or= 4
eq 4, base.four
eq 4, count
base().five ?= 5
eq 5, base.five
eq 5, count
test "compound assignment with implicit objects", ->
obj = undefined
obj ?=
one: 1
eq 1, obj.one
obj and=
two: 2
eq undefined, obj.one
eq 2, obj.two
test "binary existential operator with negative number", ->
a = null ? - 1
eq -1, a
#### `is`,`isnt`,`==`,`!=`
# Existential Operator (Unary)
test "postfix existential operator", ->
ok (if nonexistent? then false else true)
defined = true
ok defined?
defined = false
ok defined?
test "postfix existential operator only evaluates its operand once", ->
semaphore = 0
fn = ->
ok false if semaphore
++semaphore
ok(if fn()? then true else false)
test "negated postfix existential operator", ->
ok !nothing?.value
test "postfix existential operator on expressions", ->
eq true, (1 or 0)?, true
# `is`,`isnt`,`==`,`!=`
test "`==` and `is` should be interchangeable", ->
a = b = 1
@@ -135,7 +130,7 @@ test "`!=` and `isnt` should be interchangeable", ->
ok a isnt b
#### `in`, `of`
# [not] in/of
# - `in` should check if an array contains a value using `indexOf`
# - `of` should check if a property is defined on an object using `in`
@@ -189,8 +184,12 @@ test "#768: `in` should preserve evaluation order", ->
ok a() not in [b(),c()]
eq 3, share
test "#1099: empty array after `in` should compile to `false`", ->
eq 1, [5 in []].length
eq false, do -> return 0 in []
#### Chainable Operators
# Chained Comparison
test "chainable operators", ->
ok 100 > 10 > 1 > 0 > -1

View File

@@ -1,3 +1,8 @@
# Option Parser
# -------------
# TODO: refactor option parser tests
# Ensure that the OptionParser handles arguments correctly.
return unless require?
{OptionParser} = require './../lib/optparse'

85
test/ranges.coffee Normal file
View File

@@ -0,0 +1,85 @@
# Range Literals
# --------------
# TODO: add indexing and method invocation tests: [1..4][0] is 1, [0...3].toString()
# shared array
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
test "basic inclusive ranges", ->
arrayEq [1, 2, 3] , [1..3]
arrayEq [0, 1, 2] , [0..2]
arrayEq [0, 1] , [0..1]
arrayEq [0] , [0..0]
arrayEq [-1] , [-1..-1]
arrayEq [-1, 0] , [-1..0]
arrayEq [-1, 0, 1], [-1..1]
test "basic exclusive ranges", ->
arrayEq [1, 2, 3] , [1...4]
arrayEq [0, 1, 2] , [0...3]
arrayEq [0, 1] , [0...2]
arrayEq [0] , [0...1]
arrayEq [-1] , [-1...0]
arrayEq [-1, 0] , [-1...1]
arrayEq [-1, 0, 1], [-1...2]
arrayEq [], [1...1]
arrayEq [], [0...0]
arrayEq [], [-1...-1]
test "downward ranges", ->
arrayEq shared, [9..0].reverse()
arrayEq [5, 4, 3, 2] , [5..2]
arrayEq [2, 1, 0, -1], [2..-1]
arrayEq [3, 2, 1] , [3..1]
arrayEq [2, 1, 0] , [2..0]
arrayEq [1, 0] , [1..0]
arrayEq [0] , [0..0]
arrayEq [-1] , [-1..-1]
arrayEq [0, -1] , [0..-1]
arrayEq [1, 0, -1] , [1..-1]
arrayEq [0, -1, -2], [0..-2]
arrayEq [4, 3, 2], [4...1]
arrayEq [3, 2, 1], [3...0]
arrayEq [2, 1] , [2...0]
arrayEq [1] , [1...0]
arrayEq [] , [0...0]
arrayEq [] , [-1...-1]
arrayEq [0] , [0...-1]
arrayEq [0, -1] , [0...-2]
arrayEq [1, 0] , [1...-1]
arrayEq [2, 1, 0], [2...-1]
test "ranges with variables as enpoints", ->
[a, b] = [1, 3]
arrayEq [1, 2, 3], [a..b]
arrayEq [1, 2] , [a...b]
b = -2
arrayEq [1, 0, -1, -2], [a..b]
arrayEq [1, 0, -1] , [a...b]
test "ranges with expressions as endpoints", ->
[a, b] = [1, 3]
arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
arrayEq [2, 3, 4, 5] , [(a+1)...2*b]
test "large ranges are generated with looping constructs", ->
down = [99..0]
eq 100, (len = down.length)
eq 0, down[len - 1]
up = [0...100]
eq 100, (len = up.length)
eq 99, up[len - 1]
test "#1012 slices with arguments object", ->
expected = [0..9]
argsAtStart = (-> [arguments[0]..9]) 0
arrayEq expected, argsAtStart
argsAtEnd = (-> [0..arguments[0]]) 9
arrayEq expected, argsAtEnd
argsAtBoth = (-> [arguments[0]..arguments[1]]) 0, 9
arrayEq expected, argsAtBoth

View File

@@ -1,6 +1,10 @@
# Regular Expressions
# -------------------
#TODO: add some rigorous regex interpolation tests
# Regular Expression Literals
# ---------------------------
# TODO: add method invocation tests: /regex/.toString()
# * Regexen
# * Heregexen
test "basic regular expression literals", ->
ok 'a'.match(/a/)
@@ -16,6 +20,10 @@ test "division is not confused for a regular expression", ->
g = 1
eq 2, a / b/g
a = 10
b = a /= 4 / 2
eq a, 5
obj = method: -> 2
two = 2
eq 2, (obj.method()/two + obj.method()/two)
@@ -24,9 +32,6 @@ test "division is not confused for a regular expression", ->
eq 2, (4)/2/i
eq 1, i/i/i
test "backslash escapes", ->
eq "\\/\\\\", /\/\\/.source
test "#764: regular expressions should be indexable", ->
eq /0/['source'], ///#{0}///['source']
@@ -34,7 +39,7 @@ test "#584: slashes are allowed unescaped in character classes", ->
ok /^a\/[/]b$/.test 'a//b'
#### Heregexe(n|s)
# Heregexe(n|s)
test "a heregex will ignore whitespace and comments", ->
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
@@ -42,15 +47,5 @@ test "a heregex will ignore whitespace and comments", ->
Heregex? / // # or not
///gim + ''
test "heregex interpolation", ->
eq /\\#{}\\\"/ + '', ///
#{
"#{ '\\' }" # normal comment
}
# regex comment
\#{}
\\ \"
/// + ''
test "an empty heregex will compile to an empty, non-capturing group", ->
eq /(?:)/ + '', /// /// + ''

4
test/repl.coffee Normal file
View File

@@ -0,0 +1,4 @@
# REPL
# ----
# TODO: add tests

22
test/scope.coffee Normal file
View File

@@ -0,0 +1,22 @@
# Scope
# -----
# * Variable Safety
# * Variable Shadowing
# * Auto-closure (`do`)
# * Global Scope Leaks
test "reference `arguments` inside of functions", ->
sumOfArgs = ->
sum = (a,b) -> a + b
sum = 0
sum += num for num in arguments
sum
eq 10, sumOfArgs(0, 1, 2, 3, 4)
test "assignment to an Object.prototype-named variable should not leak to outer scope", ->
# FIXME: fails on IE
(->
constructor = 'word'
)()
ok constructor isnt 'word'

View File

@@ -1,83 +1,13 @@
# Ranges, Slices, and Splices
# ---------------------------
# Slicing and Splicing
# --------------------
# * Slicing
# * Splicing
# shared array
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#### Ranges
test "basic inclusive ranges", ->
arrayEq [1, 2, 3] , [1..3]
arrayEq [0, 1, 2] , [0..2]
arrayEq [0, 1] , [0..1]
arrayEq [0] , [0..0]
arrayEq [-1] , [-1..-1]
arrayEq [-1, 0] , [-1..0]
arrayEq [-1, 0, 1], [-1..1]
test "basic exclusive ranges", ->
arrayEq [1, 2, 3] , [1...4]
arrayEq [0, 1, 2] , [0...3]
arrayEq [0, 1] , [0...2]
arrayEq [0] , [0...1]
arrayEq [-1] , [-1...0]
arrayEq [-1, 0] , [-1...1]
arrayEq [-1, 0, 1], [-1...2]
arrayEq [], [1...1]
arrayEq [], [0...0]
arrayEq [], [-1...-1]
test "downward ranges", ->
arrayEq shared, [9..0].reverse()
arrayEq [5, 4, 3, 2] , [5..2]
arrayEq [2, 1, 0, -1], [2..-1]
arrayEq [3, 2, 1] , [3..1]
arrayEq [2, 1, 0] , [2..0]
arrayEq [1, 0] , [1..0]
arrayEq [0] , [0..0]
arrayEq [-1] , [-1..-1]
arrayEq [0, -1] , [0..-1]
arrayEq [1, 0, -1] , [1..-1]
arrayEq [0, -1, -2], [0..-2]
arrayEq [4, 3, 2], [4...1]
arrayEq [3, 2, 1], [3...0]
arrayEq [2, 1] , [2...0]
arrayEq [1] , [1...0]
arrayEq [] , [0...0]
arrayEq [] , [-1...-1]
arrayEq [0] , [0...-1]
arrayEq [0, -1] , [0...-2]
arrayEq [1, 0] , [1...-1]
arrayEq [2, 1, 0], [2...-1]
test "ranges with variables as enpoints", ->
[a, b] = [1, 3]
arrayEq [1, 2, 3], [a..b]
arrayEq [1, 2] , [a...b]
b = -2
arrayEq [1, 0, -1, -2], [a..b]
arrayEq [1, 0, -1] , [a...b]
test "ranges with expressions as endpoints", ->
[a, b] = [1, 3]
arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
arrayEq [2, 3, 4, 5] , [(a+1)...2*b]
test "large ranges are generated with looping constructs", ->
down = [99..0]
eq 100, (len = down.length)
eq 0, down[len - 1]
up = [0...100]
eq 100, (len = up.length)
eq 99, up[len - 1]
#### Slices
# Slicing
test "basic slicing", ->
arrayEq [7, 8, 9] , shared[7..9]
@@ -123,7 +53,7 @@ test "string slicing", ->
ok str[-5..] is "vwxyz"
#### Splices
# Splicing
test "basic splicing", ->
ary = [0..9]

134
test/soaks.coffee Normal file
View File

@@ -0,0 +1,134 @@
# Soaks
# -----
# * Soaked Property Access
# * Soaked Method Invocation
# * Soaked Function Invocation
# Soaked Property Access
test "soaked property access", ->
nonce = {}
obj = a: b: nonce
eq nonce , obj?.a.b
eq nonce , obj?['a'].b
eq nonce , obj.a?.b
eq nonce , obj?.a?['b']
eq undefined, obj?.a?.non?.existent?.property
test "soaked property access caches method calls", ->
nonce ={}
obj = fn: -> a: nonce
eq nonce , obj.fn()?.a
eq undefined, obj.fn()?.b
test "soaked property access chaching", ->
nonce = {}
counter = 0
fn = ->
counter++
'self'
obj =
self: -> @
prop: nonce
eq nonce, obj[fn()]()[fn()]()[fn()]()?.prop
eq 3, counter
test "method calls on soaked methods", ->
nonce = {}
obj = null
eq undefined, obj?.a().b()
obj = a: -> b: -> nonce
eq nonce , obj?.a().b()
test "postfix existential operator mixes well with soaked property accesses", ->
eq false, nonexistent?.property?
test "function invocation with soaked property access", ->
id = (_) -> _
eq undefined, id nonexistent?.method()
test "if-to-ternary should safely parenthesize soaked property accesses", ->
ok (if nonexistent?.property then false else true)
test "#726", ->
# TODO: check this test, looks like it's not really testing anything
eq undefined, nonexistent?[Date()]
test "#756", ->
# TODO: improve this test
a = null
ok isNaN a?.b.c + 1
eq undefined, a?.b.c += 1
eq undefined, ++a?.b.c
eq undefined, delete a?.b.c
test "operations on soaked properties", ->
# TODO: improve this test
a = b: {c: 0}
eq 1, a?.b.c + 1
eq 1, a?.b.c += 1
eq 2, ++a?.b.c
eq yes, delete a?.b.c
# Soaked Method Invocation
test "soaked method invocation", ->
nonce = {}
counter = 0
obj =
self: -> @
increment: -> counter++; @
eq obj , obj.self?()
eq undefined, obj.method?()
eq nonce , obj.self?().property = nonce
eq undefined, obj.method?().property = nonce
eq obj , obj.increment().increment().self?()
eq 2 , counter
test "#733", ->
a = b: {c: null}
eq a.b?.c?(), undefined
a.b?.c or= (it) -> it
eq a.b?.c?(1), 1
eq a.b?.c?([2, 3]...), 2
# Soaked Function Invocation
test "soaked function invocation", ->
nonce = {}
id = (_) -> _
eq nonce , id?(nonce)
eq nonce , (id? nonce)
eq undefined, nonexistent?(nonce)
eq undefined, (nonexistent? nonce)
test "soaked function invocation with generated functions", ->
nonce = {}
id = (_) -> _
maybe = (fn, arg) -> if typeof fn is 'function' then () -> fn(arg)
eq maybe(id, nonce)?(), nonce
eq (maybe id, nonce)?(), nonce
eq (maybe false, nonce)?(), undefined
test "soaked constructor invocation", ->
eq 42 , +new Number? 42
eq undefined, new Other? 42
test "soaked constructor invocations with caching and property access", ->
semaphore = 0
nonce = {}
class C
constructor: ->
ok false if semaphore
semaphore++
prop: nonce
eq nonce, (new C())?.prop
eq 1, semaphore
test "soaked function invocation safe on non-functions", ->
eq undefined, 0?(1)
eq undefined, 0? 1, 2

View File

@@ -1,86 +1,85 @@
# String Literals
# ---------------
# TODO: refactor string literal tests
# TODO: add indexing and method invocation tests: "string"["toString"] is String::toString, "string".toString() is "string"
# * Strings
# * Heredocs
test "backslash escapes", ->
eq "\\/\\\\", /\/\\/.source
eq '(((dollars)))', '\(\(\(dollars\)\)\)'
eq 'one two three', "one
two
three"
eq "four five", 'four
five'
#647
eq "''Hello, World\\''", '''
'\'Hello, World\\\''
'''
eq '""Hello, World\\""', """
"\"Hello, World\\\""
"""
eq 'Hello, World\n', '''
Hello, World\
'''
a = """
basic heredoc
on two lines
"""
ok a is "basic heredoc\non two lines"
a = '''
a
"b
c
'''
ok a is "a\n \"b\nc"
a = """
a
b
c
"""
ok a is "a\n b\n c"
a = '''one-liner'''
ok a is 'one-liner'
a = """
out
here
"""
ok a is "out\nhere"
a = '''
a
b
c
'''
ok a is " a\n b\nc"
a = '''
a
b c
'''
ok a is "a\n\n\nb c"
a = '''more"than"one"quote'''
ok a is 'more"than"one"quote'
val = 10
a = """
basic heredoc #{val}
on two lines
"""
b = '''
basic heredoc #{val}
on two lines
'''
ok a is "basic heredoc 10\non two lines"
ok b is "basic heredoc \#{val}\non two lines"
a = '''here's an apostrophe'''
ok a is "here's an apostrophe"
# The indentation detector ignores blank lines without trailing whitespace
a = """
one
@@ -103,9 +102,6 @@ eq """ "\\\" """, ' "\\" '
eq ''' <- keep these spaces -> ''', ' <- keep these spaces -> '
eq 'multiline nested "interpolations" work', """multiline #{
"nested #{(->
ok yes
"\"interpolations\""
)()}"
} work"""
test "#1046, empty string interpolations", ->
eq "#{ }", ''

View File

@@ -27,10 +27,9 @@
start = new Date
success = total = done = failed = 0
say = (msg, yay) ->
say = (msg) ->
div = document.createElement 'div'
div.appendChild document.createTextNode msg
div.style.color = if yay then 'green' else 'red'
stdout.appendChild div
msg
@@ -72,16 +71,9 @@
return
ok no
CoffeeScript.run = (code, cb) ->
try Function(CoffeeScript.compile code, wrap: no)()
catch e then cb(); throw e
cb yes
run = (name) ->
CoffeeScript.load "#{name}.coffee", (yay) ->
say "#{ if yay then '\u2714' else '\u3000' } #{name}", yay
++failed unless yay
CoffeeScript.load "#{name}.coffee", ->
say '\u2714 ' + name
fin() if ++done is names.length
fin = ->
@@ -92,30 +84,33 @@
say msg, yay
run name for name in names = [
'arguments'
'arrays'
'assignment'
'break'
'booleans'
'classes'
'comments'
'compilation'
'comprehensions'
'control_flow'
'exception_handling'
'formatting'
'function_invocation'
'functions'
'helpers'
'importing'
'interpolation'
'javascript_literals'
'numbers'
'objects'
'operators'
'regular_expressions'
'test_chaining'
'test_classes'
'test_compilation'
'test_comprehensions'
'test_existence'
'test_functions'
'test_heredocs'
'conditionals'
'test_literals'
'test_pattern_matching'
'ranges_slices_and_splices'
'test_returns'
'test_splats'
'test_strings'
'test_switch'
'test_while'
'option_parser'
'ranges'
'regexps'
'repl'
'scope'
'slicing_and_splicing'
'soaks'
'strings'
]
</script>

View File

@@ -1,77 +0,0 @@
# Chaining
# --------
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
# Basic chained function calls.
identityWrap = (x) ->
-> x
result = identityWrap(identityWrap(true))()()
ok result
# Should be able to look at prototypes on keywords.
obj =
withAt: -> @::prop
withThis: -> this::prop
proto:
prop: 100
obj.prototype = obj.proto
eq obj.withAt() , 100
eq obj.withThis(), 100
# Chained accesses split on period/newline, backwards and forwards.
str = 'god'
result = str.
split('').
reverse().
reverse().
reverse()
ok result.join('') is 'dog'
result = str
.split('')
.reverse()
.reverse()
.reverse()
ok result.join('') is 'dog'
# Newline suppression for operators.
six =
1 +
2 +
3
ok six is 6
# Ensure that indented array literals don't trigger whitespace rewriting.
func = () ->
ok arguments.length is 1
func(
[[[[[],
[]],
[[]]]],
[]])
greeting = id(
"""
Hello
""")
ok greeting is "Hello"
ok not Date
::
?.foo, '`?.` and `::` should also continue lines'

View File

@@ -1,372 +0,0 @@
# Test classes with a four-level inheritance chain.
class Base
func: (string) ->
"zero/#{string}"
@static: (string) ->
"static/#{string}"
class FirstChild extends Base
func: (string) ->
super('one/') + string
SecondChild = class extends FirstChild
func: (string) ->
super('two/') + string
thirdCtor = ->
@array = [1, 2, 3]
class ThirdChild extends SecondChild
constructor: -> thirdCtor.call this
# Gratuitous comment for testing.
func: (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok Base.static('word') is 'static/word'
FirstChild::func = (string) ->
super('one/').length + string
result = (new ThirdChild).func 'four'
ok result is '9two/three/four'
ok (new ThirdChild).array.join(' ') is '1 2 3'
identity = (f) -> f
class TopClass
constructor: (arg) ->
@prop = 'top-' + arg
class SuperClass extends TopClass
constructor: (arg) ->
identity super 'super-' + arg
class SubClass extends SuperClass
constructor: ->
identity super 'sub'
ok (new SubClass).prop is 'top-super-sub'
class OneClass
@new: 'new'
function: 'function'
constructor: (name) -> @name = name
class TwoClass extends OneClass
delete TwoClass.new
Function.prototype.new = -> new this arguments...
ok (TwoClass.new('three')).name is 'three'
ok (new OneClass).function is 'function'
ok OneClass.new is 'new'
delete Function.prototype.new
# And now the same tests, but written in the manual style:
Base = ->
Base::func = (string) ->
'zero/' + string
Base::['func-func'] = (string) ->
"dynamic-#{string}"
FirstChild = ->
SecondChild = ->
ThirdChild = ->
@array = [1, 2, 3]
this
ThirdChild extends SecondChild extends FirstChild extends Base
FirstChild::func = (string) ->
super('one/') + string
SecondChild::func = (string) ->
super('two/') + string
ThirdChild::func = (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
TopClass = (arg) ->
@prop = 'top-' + arg
this
SuperClass = (arg) ->
super 'super-' + arg
this
SubClass = ->
super 'sub'
this
SuperClass extends TopClass
SubClass extends SuperClass
ok (new SubClass).prop is 'top-super-sub'
# '@' referring to the current instance, and not being coerced into a call.
class ClassName
amI: ->
@ instanceof ClassName
obj = new ClassName
ok obj.amI()
# super() calls in constructors of classes that are defined as object properties.
class Hive
constructor: (name) -> @name = name
class Hive.Bee extends Hive
constructor: (name) -> super
maya = new Hive.Bee 'Maya'
ok maya.name is 'Maya'
# Class with JS-keyword properties.
class Class
class: 'class'
name: -> @class
instance = new Class
ok instance.class is 'class'
ok instance.name() is 'class'
# Classes with methods that are pre-bound to the instance.
# ... or statically, to the class.
class Dog
constructor: (name) ->
@name = name
bark: =>
"#{@name} woofs!"
@static = =>
new this('Dog')
spark = new Dog('Spark')
fido = new Dog('Fido')
fido.bark = spark.bark
ok fido.bark() is 'Spark woofs!'
obj = func: Dog.static
ok obj.func().name is 'Dog'
# Testing a bound function in a bound function.
class Mini
num: 10
generate: =>
for i in [1..3]
=>
@num
m = new Mini
eq (func() for func in m.generate()).join(' '), '10 10 10'
# Testing a contructor called with varargs.
class Connection
constructor: (one, two, three) ->
[@one, @two, @three] = [one, two, three]
out: ->
"#{@one}-#{@two}-#{@three}"
list = [3, 2, 1]
conn = new Connection list...
ok conn instanceof Connection
ok conn.out() is '3-2-1'
# Test calling super and passing along all arguments.
class Parent
method: (args...) -> @args = args
class Child extends Parent
method: -> super
c = new Child
c.method 1, 2, 3, 4
ok c.args.join(' ') is '1 2 3 4'
# Test classes wrapped in decorators.
func = (klass) ->
klass::prop = 'value'
klass
func class Test
prop2: 'value2'
ok (new Test).prop is 'value'
ok (new Test).prop2 is 'value2'
# Test anonymous classes.
obj =
klass: class
method: -> 'value'
instance = new obj.klass
ok instance.method() is 'value'
# Implicit objects as static properties.
class Static
@static =
one: 1
two: 2
ok Static.static.one is 1
ok Static.static.two is 2
# Nothing classes.
c = class
ok c instanceof Function
# Classes with value'd constructors.
counter = 0
classMaker = ->
counter += 1
inner = counter
->
@value = inner
class One
constructor: classMaker()
class Two
constructor: classMaker()
ok (new One).value is 1
ok (new Two).value is 2
ok (new One).value is 1
ok (new Two).value is 2
# Exectuable class bodies.
class A
if true
b: 'b'
else
c: 'c'
a = new A
eq a.b, 'b'
eq a.c, undefined
# Light metaprogramming.
class Base
@attr: (name) ->
@::[name] = (val) ->
if arguments.length > 0
@["_#{name}"] = val
else
@["_#{name}"]
class Robot extends Base
@attr 'power'
@attr 'speed'
robby = new Robot
ok robby.power() is undefined
robby.power 11
robby.speed Infinity
eq robby.power(), 11
eq robby.speed(), Infinity
# Namespaced classes do not reserve their function name in outside scope.
one = {}
two = {}
class one.Klass
@label = "one"
class two.Klass
@label = "two"
eq typeof Klass, 'undefined'
eq one.Klass.label, 'one'
eq two.Klass.label, 'two'
# Nested classes.
class Outer
constructor: ->
@label = 'outer'
class @Inner
constructor: ->
@label = 'inner'
eq (new Outer).label, 'outer'
eq (new Outer.Inner).label, 'inner'
# Variables in constructor bodies are correctly scoped.
class A
x = 1
constructor: ->
x = 10
y = 20
y = 2
captured: ->
{x, y}
a = new A
eq a.captured().x, 10
eq a.captured().y, 2
# Issue #924: Static methods in nested classes.
class A
@B: class
@c = -> 5
eq A.B.c(), 5
# `class extends this` ...
class A
func: -> 'A'
B = null
makeClass = ->
B = class extends this
func: -> super + ' B'
makeClass.call A
eq (new B()).func(), 'A B'

View File

@@ -1,26 +0,0 @@
# Ensure that carriage returns don't break compilation on Windows.
eq CoffeeScript.compile('one\r\ntwo', bare: on), 'one;\ntwo;'
# `globals: on` removes `var`s
eq CoffeeScript.compile('x = y', bare: on, globals: on), 'x = y;'
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, fileName: 'test'
#750
try ok not CoffeeScript.nodes 'f(->'
catch e then eq e.message, 'unclosed CALL_START on line 1'
eq CoffeeScript.compile('for k of o then', bare: on, globals: on),
'for (k in o) {}'
# Compilations that should fail.
cantCompile = (code) ->
throws -> CoffeeScript.compile code
cantCompile 'a = (break)'
cantCompile 'a = (return 5 for item in list)'
cantCompile 'a = (return 5 while condition)'
cantCompile 'a = for x in y\n return 5'

View File

@@ -1,318 +0,0 @@
# Basic array comprehensions.
nums = (n * n for n in [1, 2, 3] when n & 1)
results = (n * 2 for n in nums)
ok results.join(',') is '2,18'
# Basic object comprehensions.
obj = {one: 1, two: 2, three: 3}
names = (prop + '!' for prop of obj)
odds = (prop + '!' for prop, value of obj when value & 1)
ok names.join(' ') is "one! two! three!"
ok odds.join(' ') is "one! three!"
# Basic range comprehensions.
nums = (i * 3 for i in [1..3])
negs = (x for x in [-20..-5*2])
negs = negs[0..2]
result = nums.concat(negs).join(', ')
ok result is '3, 6, 9, -20, -19, -18'
# With range comprehensions, you can loop in steps.
results = (x for x in [0...15] by 5)
ok results.join(' ') is '0 5 10'
results = (x for x in [0..100] by 10)
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
# And can loop downwards, with a negative step.
results = (x for x in [5..1])
ok results.join(' ') is '5 4 3 2 1'
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
results = (x for x in [10..1])
ok results.join(' ') is [10..1].join(' ')
results = (x for x in [10...0] by -2)
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
# Range comprehension gymnastics.
eq "#{i for i in [5..1]}", '5,4,3,2,1'
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
a = 6
b = 0
c = -2
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
eq "#{i for i in [a..b] by c}", '6,4,2,0'
# Multiline array comprehension with filter.
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
num *= -1
num -= 2
num * -1
eq evens + '', '4,6,8'
# The in operator still works, standalone.
ok 2 of evens
# all isn't reserved.
all = 1
# Ensure that the closure wrapper preserves local variables.
obj = {}
for method in ['one', 'two', 'three'] then do (method) ->
obj[method] = ->
"I'm " + method
ok obj.one() is "I'm one"
ok obj.two() is "I'm two"
ok obj.three() is "I'm three"
# Index values at the end of a loop.
i = 0
for i in [1..3]
-> 'func'
break if false
ok i is 4
# Ensure that local variables are closed over for range comprehensions.
funcs = for i in [1..3]
do (i) ->
-> -i
eq (func() for func in funcs).join(' '), '-1 -2 -3'
ok i is 4
# Even when referenced in the filter.
list = ['one', 'two', 'three']
methods = for num, i in list when num isnt 'two' and i isnt 1
do (num, i) ->
-> num + ' ' + i
ok methods.length is 2
ok methods[0]() is 'one 0'
ok methods[1]() is 'three 2'
# Even a convoluted one.
funcs = []
for i in [1..3]
do (i) ->
x = i * 2
((z)->
funcs.push -> z + ' ' + i
)(x)
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
funcs = []
results = for i in [1..3]
do (i) ->
z = (x * 3 for x in [1..i])
((a, b, c) -> [a, b, c].join(' ')).apply this, z
ok results.join(', ') is '3 , 3 6 , 3 6 9'
# Naked ranges are expanded into arrays.
array = [0..10]
ok(num % 2 is 0 for num in array by 2)
# Nested shared scopes.
foo = ->
for i in [0..7]
do (i) ->
for j in [0..7]
do (j) ->
-> i + j
eq foo()[3][4](), 7
# Scoped loop pattern matching.
a = [[0], [1]]
funcs = []
for [v] in a
do (v) ->
funcs.push -> v
eq funcs[0](), 0
eq funcs[1](), 1
# Nested comprehensions.
multiLiner =
for x in [3..5]
for y in [3..5]
[x, y]
singleLiner =
(([x, y] for y in [3..5]) for x in [3..5])
ok multiLiner.length is singleLiner.length
ok 5 is multiLiner[2][2][1]
ok 5 is singleLiner[2][2][1]
# Comprehensions within parentheses.
result = null
store = (obj) -> result = obj
store (x * 2 for x in [3, 2, 1])
ok result.join(' ') is '6 4 2'
# Closure-wrapped comprehensions that refer to the "arguments" object.
expr = ->
result = (item * item for item in arguments)
ok expr(2, 4, 8).join(' ') is '4 16 64'
# Fast object comprehensions over all properties, including prototypal ones.
class Cat
constructor: -> @name = 'Whiskers'
breed: 'tabby'
hair: 'cream'
whiskers = new Cat
own = (value for own key, value of whiskers)
all = (value for key, value of whiskers)
ok own.join(' ') is 'Whiskers'
ok all.sort().join(' ') is 'Whiskers cream tabby'
# Optimized range comprehensions.
exxes = ('x' for [0...10])
ok exxes.join(' ') is 'x x x x x x x x x x'
# Comprehensions safely redeclare parameters if they're not present in closest
# scope.
rule = (x) -> x
learn = ->
rule for rule in [1, 2, 3]
ok learn().join(' ') is '1 2 3'
ok rule(101) is 101
f = -> [-> ok no, 'should cache source']
ok yes for k of [f] = f()
# Lenient on pure statements not trying to reach out of the closure
val = for i in [1]
for j in [] then break
i
ok val[0] is i
# Comprehensions only wrap their last line in a closure, allowing other lines
# to have pure expressions in them.
func = -> for i in [1]
break if i is 2
j for j in [1]
ok func()[0][0] is 1
i = 6
odds = while i--
continue unless i & 1
i
ok odds.join(', ') is '5, 3, 1'
# Issue #897: Ensure that plucked function variables aren't leaked.
facets = {}
list = ['one', 'two']
(->
for entity in list
facets[entity] = -> entity
)()
eq typeof entity, 'undefined'
eq facets['two'](), 'two'
# Issue #905. Soaks as the for loop subject.
a = {b: {c: [1, 2, 3]}}
for d in a.b?.c
e = d
eq e, 3
# Issue #948. Capturing loop variables.
funcs = []
list = ->
[1, 2, 3]
for y in list()
do (y) ->
z = y
funcs.push -> "y is #{y} and z is #{z}"
eq funcs[1](), "y is 2 and z is 2"
# Cancel the comprehension if there's a jump inside the loop.
result = try
for i in [0...10]
continue if i < 5
i
eq result, 10
# Comprehensions over break.
arrayEq (break for [1..10]), []
# Comprehensions over continue.
arrayEq (break for [1..10]), []
# Comprehensions over function literals.
a = 0
for f in [-> a = 1]
do (f) ->
do f
eq a, 1
# Comprehensions that mention arguments.
list = [arguments: 10]
args = for f in list
do (f) ->
f.arguments
eq args[0], 10

View File

@@ -1,165 +0,0 @@
ok(if mySpecialVariable? then false else true)
mySpecialVariable = false
ok(if mySpecialVariable? then true else false)
# Existential assignment.
a = 5
a = null
a ?= 10
b ?= 10
ok a is 10 and b is 10
# The existential operator.
z = null
x = z ? "EX"
ok z is null and x is "EX"
i = 9
func = -> i += 1
result = func() ? 101
ok result is 10
# Only evaluate once.
counter = 0
getNextNode = ->
throw "up" if counter
counter++
ok(if getNextNode()? then true else false)
# Existence chains, soaking up undefined properties:
obj =
prop: "hello"
eq obj?.prop, "hello"
eq obj?['prop'], "hello"
eq obj.prop?.length, 5
eq obj?.prop?['length'], 5
eq obj?.prop?.non?.existent?.property, undefined
# Soaks and caches method calls as well.
arr = ["--", "----"]
eq arr.pop()?.length, 4
eq arr.pop()?.length, 2
eq arr.pop()?.length, undefined
eq arr.pop()?.length?.non?.existent()?.property, undefined
# Soaks method calls safely.
value = null
eq value?.toString().toLowerCase(), undefined
value = 10
eq value?.toString().toLowerCase(), '10'
eq 0.nothing?.property() or 101, 101
counter = 0
func = ->
counter += 1
'prop'
obj =
prop: -> this
value: 25
ok obj[func()]()[func()]()[func()]()?.value is 25
ok counter is 3
ident = (obj) -> obj
eq ident(non?.existent().method()), undefined, 'soaks inner values'
# Soaks constructor invocations.
a = 0
class Foo
constructor: -> a += 1
bar: "bat"
ok (new Foo())?.bar is 'bat'
ok a is 1
ok not value?.property?, 'safely checks existence on soaks'
eq nothing?.value, undefined, 'safely calls values off of non-existent variables'
eq !nothing?.value and 1, 1, 'corresponding operators work as expected'
# Assign to the result of an exsitential operation with a minus.
x = null ? - 1
ok x is - 1
# Things that compile to ternaries should force parentheses, like operators do.
duration = if options?.animated then 150 else 0
ok duration is 0
# Function soaks.
plus1 = (x) -> x + 1
count = 0
obj = {
counter: -> count += 1; this
returnThis: -> this
}
eq plus1?(41), 42
eq (plus1? 41), 42
eq plus2?(41), undefined
eq (plus2? 41), undefined
eq obj.returnThis?(), obj
eq obj.returnSelf?(), undefined
eq obj.returnThis?().flag = on, on
eq obj.returnSelf?().flag = on, undefined
eq obj.counter().counter().returnThis?(), obj
eq count, 2
maybe_close = (f, arg) -> if typeof f is 'function' then () -> f(arg) else -1
eq maybe_close(plus1, 41)?(), 42
eq (maybe_close plus1, 41)?(), 42
eq (maybe_close 'string', 41)?(), undefined
eq 2?(3), undefined
eq new Number?(42) | 0, 42
eq new Bumper?(42) | 0, 0
#726
eq calendar?[Date()], undefined
#733
a = b: {c: null}
eq a.b?.c?(), undefined
a.b?.c or= (it) -> it
eq a.b?.c?(1), 1
eq a.b?.c?([2, 3]...), 2
#756
a = null
ok isNaN a?.b.c + 1
eq undefined, a?.b.c += 1
eq undefined, ++a?.b.c
eq undefined, delete a?.b.c
a = b: {c: 0}
eq 1, a?.b.c + 1
eq 1, a?.b.c += 1
eq 2, ++a?.b.c
eq yes, delete a?.b.c
eq (1 or 0)?, true, 'postfix `?` should unwrap correctly'

View File

@@ -1,379 +0,0 @@
x = 1
y = {}
y.x = -> 3
ok x is 1
ok typeof(y.x) is 'function'
ok y.x instanceof Function
ok y.x() is 3
# The empty function should not cause a syntax error.
->
() ->
# Multiple nested function declarations mixed with implicit calls should not
# cause a syntax error.
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
obj = {
name: 'Fred'
bound: ->
do (=> eq this, obj)
unbound: ->
do (-> ok this isnt obj)
nested: ->
(=>
do (=>
(=>
eq this, obj
)()
)
)()
}
obj.unbound()
obj.bound()
obj.nested()
# Python decorator style wrapper that memoizes any function
memoize = (fn) ->
cache = {}
self = this
(args...) ->
key = args.toString()
return cache[key] if cache[key]
cache[key] = fn.apply(self, args)
Math = {
Add: (a, b) -> a + b
AnonymousAdd: (a, b) -> a + b
FastAdd: memoize (a, b) -> a + b
}
ok Math.Add(5, 5) is 10
ok Math.AnonymousAdd(10, 10) is 20
ok Math.FastAdd(20, 20) is 40
okFunc = (f) -> ok(f())
okFunc -> true
# Optional parens can be used in a nested fashion.
call = (func) -> func()
result = call ->
inner = call ->
Math.Add(5, 5)
ok result is 10
# More fun with optional parens.
fn = (arg) -> arg
ok fn(fn {prop: 101}).prop is 101
# Multi-blocks with optional parens.
result = fn( ->
fn ->
"Wrapped"
)
ok result()() is 'Wrapped'
# And even with strange things like this:
funcs = [((x) -> x), ((x) -> x * x)]
result = funcs[1] 5
ok result is 25
result = ("hello".slice) 3
ok result is 'lo'
# And with multiple single-line functions on the same line.
func = (x) -> (x) -> (x) -> x
ok func(1)(2)(3) is 3
# Ensure that functions with the same name don't clash with helper functions.
del = -> 5
ok del() is 5
# Ensure that functions can have a trailing comma in their argument list
mult = (x, mids..., y) ->
x *= n for n in mids
x *= y
ok mult(1, 2,) is 2
ok mult(1, 2, 3,) is 6
ok mult(10, (i for i in [1..6])...) is 7200
# Test for inline functions with parentheses and implicit calls.
combine = (func, num) -> func() * num
result = combine (-> 1 + 2), 3
ok result is 9
# Test for calls/parens/multiline-chains.
f = (x) -> x
result = (f 1).toString()
.length
ok result is 1
# Test implicit calls in functions in parens:
result = ((val) ->
[].push val
val
)(10)
ok result is 10
# More paren compilation tests:
reverse = (obj) -> obj.reverse()
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
# Passing multiple functions without paren-wrapping is legal, and should compile.
sum = (one, two) -> one() + two()
result = sum ->
7 + 9
, ->
1 + 3
ok result is 20
# Implicit call with a trailing if statement as a param.
func = -> arguments[1]
result = func 'one', if false then 100 else 13
ok result is 13
# Test more function passing:
result = sum( ->
1 + 2
, ->
2 + 1
)
ok result is 6
sum = (a, b) -> a + b
result = sum(1
, 2)
ok result is 3
# This is a crazy one.
x = (obj, func) -> func obj
ident = (x) -> x
result = x {one: ident 1}, (obj) ->
inner = ident(obj)
ident inner
ok result.one is 1
# Assignment to a Object.prototype-named variable should not leak to outer scope.
# FIXME: fails on IE
(->
constructor = 'word'
)()
ok constructor isnt 'word'
# Trying an implicit object call with a trailing function.
a = null
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
meth 'apple', b: 1, a: 13, ->
'orange'
ok a is '13 apple orange'
# Ensure that empty functions don't return mistaken values.
obj =
func: (@param, @rest...) ->
ok obj.func(101, 102, 103, 104) is undefined
ok obj.param is 101
ok obj.rest.join(' ') is '102 103 104'
# `@` and `this` should both be able to invoke a method.
func = (arg) -> ok arg is true
func.withAt = -> @ true
func.withThis = -> this true
func.withAt()
func.withThis()
# Ensure that constructors invoked with splats return a new object.
args = [1, 2, 3]
Type = (@args) ->
type = new Type args
ok type and type instanceof Type
ok type.args and type.args instanceof Array
ok v is args[i] for v, i in type.args
Type1 = (@a, @b, @c) ->
type1 = new Type1 args...
ok type1 instanceof Type1
eq type1.constructor, Type1
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
# Ensure that constructors invoked with splats cache the function.
called = 0
get = -> if called++ then false else class Type
new get() args...
# Chained blocks, with proper indentation levels:
counter =
results: []
tick: (func) ->
@results.push func()
this
counter
.tick ->
3
.tick ->
2
.tick ->
1
eq counter.results.join(' '), '3 2 1'
# Make incorrect indentation safe.
func = ->
obj = {
key: 10
}
obj.key - 5
eq func(), 5
# Ensure that chained calls with indented implicit object literals below are
# alright.
result = null
obj =
method: (val) -> this
second: (hash) -> result = hash.three
obj
.method(
101
).second(
one:
two: 2
three: 3
)
eq result, 3
# Test newline-supressed call chains with nested functions.
obj =
call: -> this
func = ->
obj
.call ->
one two
.call ->
three four
101
eq func(), 101
# `new` shouldn't add extra parens
ok new Date().constructor is Date
# `new` works against bare function
eq Date, new ->
eq this, new => this
Date
# Implicit objects with number arguments.
func = (x, y) -> y
obj =
prop: func "a", 1
ok obj.prop is 1
# Non-spaced unary and binary operators should cause a function call.
func = (val) -> val + 1
ok (func +5) is 6
ok (func -5) is -4
# Prefix unary assignment operators are allowed in parenless calls.
val = 5
ok (func --val) is 5
eq ok, new ->
ok
### Should `return` implicitly ###
### even with trailing comments. ###
#855: execution context for `func arr...` should be `null`
(->
global = @
contextTest = -> ok global is @
array = []
contextTest array
contextTest.apply null, array
contextTest array...
)()
# #894: Splatting against constructor-chained functions.
x = null
class Foo
bar: (y) -> x = y
new Foo().bar([101]...)
eq x, 101
test "#904: Destructuring function arguments with same-named variables in scope", ->
a = b = nonce = {}
fn = ([a,b]) -> {a:a,b:b}
result = fn([c={},d={}])
eq c, result.a
eq d, result.b
eq nonce, a
eq nonce, b

View File

@@ -1,162 +0,0 @@
# Simple variable swapping.
a = -1
b = -2
[a, b] = [b, a]
eq a, -2
eq b, -1
func = ->
[a, b] = [b, a]
eq func().join(' '), '-1 -2'
eq a, -1
eq b, -2
#713
eq (onetwo = [1, 2]), [a, b] = [c, d] = onetwo
ok a is c is 1 and b is d is 2
# Array destructuring, including splats.
[x,y...,z] = [1,2,3,4,5]
ok x is 1
ok y.length is 3
ok z is 5
[x, [y, mids..., last], z..., end] = [1, [10, 20, 30, 40], 2,3,4, 5]
ok x is 1
ok y is 10
ok mids.length is 2 and mids[1] is 30
ok last is 40
ok z.length is 3 and z[2] is 4
ok end is 5
# Object destructuring.
obj = {x: 10, y: 20, z: 30}
{x: a, y: b, z: c} = obj
ok a is 10
ok b is 20
ok c is 30
person = {
name: "Moe"
family: {
'elder-brother': {
addresses: [
"first"
{
street: "101 Deercreek Ln."
city: "Moquasset NY, 10021"
}
]
}
}
}
{name: a, family: {'elder-brother': {addresses: [one, {city: b}]}}} = person
ok a is "Moe"
ok b is "Moquasset NY, 10021"
test = {
person: {
address: [
"------"
"Street 101"
"Apt 101"
"City 101"
]
}
}
{person: {address: [ignore, addr...]}} = test
ok addr.join(', ') is "Street 101, Apt 101, City 101"
# Pattern matching against an expression.
[a, b] = if true then [2, 1] else [1, 2]
ok a is 2
ok b is 1
# Pattern matching with object shorthand.
person = {
name: "Bob"
age: 26
dogs: ["Prince", "Bowie"]
}
{name, age, dogs: [first, second]} = person
ok name is "Bob"
ok age is 26
ok first is "Prince"
ok second is "Bowie"
# Pattern matching within for..loops.
persons = {
George: { name: "Bob" },
Bob: { name: "Alice" }
Christopher: { name: "Stan" }
}
join1 = ("#{key}: #{name}" for key, { name } of persons)
eq join1.join(' / '), "George: Bob / Bob: Alice / Christopher: Stan"
persons = [
{ name: "Bob", parent: { name: "George" } },
{ name: "Alice", parent: { name: "Bob" } },
{ name: "Stan", parent: { name: "Christopher" } }
]
join2 = ("#{parent}: #{name}" for { name, parent: { name: parent } } in persons)
eq join1.join(' '), join2.join(' ')
persons = [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]]
join3 = ("#{parent}: #{name}" for [name, [parent]] in persons)
eq join2.join(' '), join3.join(' ')
# Pattern matching doesn't clash with implicit block objects.
obj = a: 101
func = -> true
if func func
{a} = obj
ok a is 101
[x] = {0: y} = {'0': z} = [Math.random()]
ok x is y is z, 'destructuring in multiple'
# Destructuring into an object.
obj =
func: (list, object) ->
[@one, @two] = list
{@a, @b} = object
{@a} = object
null
{} = [] = ok yes, 'empty assignment is allowed'
obj.func [1, 2], a: 'a', b: 'b'
eq obj.one, 1
eq obj.two, 2
eq obj.a, 'a'
eq obj.b, 'b'

View File

@@ -1,63 +0,0 @@
# Expression conversion under explicit returns.
first = ->
return ('do' for x in [1,2,3])
second = ->
return ['re' for x in [1,2,3]]
third = ->
return ('mi' for x in [1,2,3])
ok first().join(' ') is 'do do do'
ok second()[0].join(' ') is 're re re'
ok third().join(' ') is 'mi mi mi'
# Testing returns with multiple branches.
func = ->
if false
for a in b
return c if d
else
"word"
ok func() is 'word'
# And with switches.
func = ->
switch 'a'
when 'a' then 42
else return 23
eq func(), 42
# Ensure that we don't wrap Nodes that are "pureStatement" in a closure.
items = [1, 2, 3, "bacon", 4, 5]
findit = (items) ->
for item in items
return item if item is "bacon"
ok findit(items) is "bacon"
# When a closure wrapper is generated for expression conversion, make sure
# that references to "this" within the wrapper are safely converted as well.
obj =
num: 5
func: ->
this.result = if false
10
else
"a"
"b"
this.num
eq obj.num, obj.func()
eq obj.num, obj.result
# Multiple semicolon-separated statements in parentheticals.
eq 3, (1; 2; 3)
eq 3, (-> return (1; 2; 3))()

View File

@@ -1,102 +0,0 @@
# Splats
# ------
# note: splats in parameter lists of function definitions are tested in `arguments.coffee`
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
test "passing splats to functions", ->
arrayEq [0..4], id id [0..4]...
fn = (a, b, c..., d) -> [a, b, c, d]
[first, second, others, last] = fn [0..3]..., 4, [5...8]...
eq 0, first
eq 1, second
arrayEq [2..6], others
eq 7, last
obj =
name: 'moe'
accessor: (args...) ->
[@name].concat(args).join(' ')
getNames: ->
args = ['jane', 'ted']
@accessor(args...)
index: 0
0: {method: -> this is obj[0]}
ok obj.getNames() is 'moe jane ted'
ok obj[obj.index++].method([]...), 'should cache base value'
#crowd = [
# contenders...
# "Mighty Mouse"
#]
#
#bests = [
# "Mighty Mouse"
# contenders.slice(0, 4)...
#]
#
#ok crowd[0] is contenders[0]
#ok crowd[10] is "Mighty Mouse"
#
#ok bests[1] is contenders[0]
#ok bests[4] is contenders[3]
# Finally, splats with super() within classes.
class Parent
meth: (args...) ->
args
class Child extends Parent
meth: ->
nums = [3, 2, 1]
super nums...
ok (new Child).meth().join(' ') is '3 2 1'
# Functions with splats being called with too few arguments.
pen = null
method = (first, variable..., penultimate, ultimate) ->
pen = penultimate
method 1, 2, 3, 4, 5, 6, 7, 8, 9
ok pen is 8
method 1, 2, 3
ok pen is 2
method 1, 2
ok pen is 2
# Array splat expansions with assigns.
nums = [1, 2, 3]
list = [a = 0, nums..., b = 4]
ok a is 0
ok b is 4
ok list.join(' ') is '0 1 2 3 4'
# Splat on a line by itself is invalid.
failed = true
try
CoffeeScript.compile "x 'a'\n...\n"
failed = false
catch err
ok failed
# multiple generated references
(->
a = {b: []}
a.b[true] = -> this == a.b
c = 0
d = []
ok a.b[0<++c<2] d...
)()

View File

@@ -1,103 +0,0 @@
num = 10
result = switch num
when 5 then false
when 'a'
true
true
false
when 10 then true
# Mid-switch comment with whitespace
# and multi line
when 11 then false
else false
ok result
func = (num) ->
switch num
when 2, 4, 6
true
when 1, 3, 5
false
ok func(2)
ok func(6)
ok !func(3)
eq func(8), undefined
# Ensure that trailing switch elses don't get rewritten.
result = false
switch "word"
when "one thing"
doSomething()
else
result = true unless false
ok result
result = false
switch "word"
when "one thing"
doSomething()
when "other thing"
doSomething()
else
result = true unless false
ok result
# Should be able to handle switches sans-condition.
result = switch
when null then 0
when !1 then 1
when '' not of {''} then 2
when [] not instanceof Array then 3
when true is false then 4
when 'x' < 'y' > 'z' then 5
when 'a' in ['b', 'c'] then 6
when 'd' in (['e', 'f']) then 7
else ok
eq result, ok
# Should be able to use "@properties" within the switch clause.
obj = {
num: 101
func: ->
switch @num
when 101 then '101!'
else 'other'
}
ok obj.func() is '101!'
# Should be able to use "@properties" within the switch cases.
obj = {
num: 101
func: (yesOrNo) ->
result = switch yesOrNo
when yes then @num
else 'other'
result
}
ok obj.func(yes) is 101
# Switch with break as the return value of a loop.
i = 10
results = while i > 0
i--
switch i % 2
when 1 then i
when 0 then break
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '

View File

@@ -1,71 +0,0 @@
i = 5
list = while i -= 1
i * 2
ok list.join(' ') is "8 6 4 2"
i = 5
list = (i * 3 while i -= 1)
ok list.join(' ') is "12 9 6 3"
i = 5
func = (num) -> i -= num
assert = -> ok i < 5 > 0
results = while func 1
assert()
i
ok results.join(' ') is '4 3 2 1'
i = 10
results = while i -= 1 when i % 2 is 0
i * 2
ok results.join(' ') is '16 12 8 4'
value = false
i = 0
results = until value
value = true if i is 5
i += 1
ok i is 6
# And, the loop form of while.
i = 5
list = []
loop
i -= 1
break if i is 0
list.push i * 2
ok list.join(' ') is '8 6 4 2'
#759: `if` within `while` condition
2 while if 1 then 0
# While over break.
i = 0
result = while i < 10
i++
break
arrayEq result, []
# While over continue.
i = 0
result = while i < 10
i++
continue
arrayEq result, []