Compare commits

..

201 Commits
0.9.5 ... 1.0.0

Author SHA1 Message Date
Jeremy Ashkenas
33d2577fb5 CoffeeScript 1.0.0 2010-12-24 11:02:10 -08:00
Jeremy Ashkenas
3be22bd43b Documenting and testing 'do' 2010-12-24 09:22:27 -08:00
Jeremy Ashkenas
094b876a38 Scoped comprehensions are back out, Do is back in. 2010-12-24 08:59:30 -08:00
Jeremy Ashkenas
97f8e9ce1c reserving __bind and __indexOf 2010-12-23 22:24:14 -08:00
Jeremy Ashkenas
385be63126 disallowing --watch and --join together for the time being. 2010-12-23 22:22:34 -08:00
Jeremy Ashkenas
7710528f01 Adding a test for the previous commit. 2010-12-23 17:58:22 -08:00
Jeremy Ashkenas
c25462d924 Fixing for a in b() -> ... 2010-12-23 17:57:29 -08:00
Jeremy Ashkenas
9b45d240bb splice literals should evaluate to their right hand side, like any other type of assignment. 2010-12-23 14:46:34 -08:00
Jeremy Ashkenas
8bd27db727 Fixing issue #965 -- first character of '.' prefixed folder. 2010-12-23 14:34:50 -08:00
Jeremy Ashkenas
83a7985a97 more work on site, down to arrays and objects. 2010-12-23 14:26:10 -08:00
Jeremy Ashkenas
2d54a45a80 splicing to the end of a one-time expression. 2010-12-23 14:02:46 -08:00
Jeremy Ashkenas
813a5f1e1f documentation waypoint 2010-12-23 13:44:12 -08:00
Jeremy Ashkenas
c7d7757dbd Fixing the asKey setting in Obj. 2010-12-23 13:38:20 -08:00
Jeremy Ashkenas
d7b6996bcf Documentation tweaks, up to Language Reference. 2010-12-23 13:30:35 -08:00
Jeremy Ashkenas
61705e4d22 Issue #964. Super should trigger an implicit call. 2010-12-23 12:57:27 -08:00
Jeremy Ashkenas
6a1730956e slightly less parentheticals. 2010-12-23 12:41:42 -08:00
Jeremy Ashkenas
df8a6529ac tagging more nodes as keys. 2010-12-23 12:14:47 -08:00
Jeremy Ashkenas
97a29f9c50 fixing mentionsArgs for accesses. 2010-12-23 12:00:23 -08:00
Jeremy Ashkenas
9395d58669 Remove seenFor in favor of a safe scanLineBack. 2010-12-23 11:22:01 -08:00
Jeremy Ashkenas
f9a0bbbc20 safer paren-wrapping for closures. 2010-12-23 10:50:52 -08:00
Jeremy Ashkenas
ccfd369a77 Fixing class extends this in a non-class context. 2010-12-23 10:22:52 -08:00
Jeremy Ashkenas
2ec1c3b56c reinstating makeReturn for statement literals. 2010-12-23 10:09:05 -08:00
Jeremy Ashkenas
dbeb626f32 switch with debugger in a case should still break, afterwards. 2010-12-23 09:38:57 -08:00
Jeremy Ashkenas
8fd78d3819 Fixing literals that should be statements, and adding failed compilation tests. 2010-12-23 09:33:12 -08:00
Jeremy Ashkenas
b56b08387d Comprehensions over break and continue 2010-12-23 08:50:34 -08:00
Jeremy Ashkenas
34b16699fa Merge branch 'refactorTests' of http://github.com/michaelficarra/coffee-script 2010-12-23 08:16:42 -08:00
Jeremy Ashkenas
75dfa5af7e forgot to inherit For::jumps from While::jumps 2010-12-23 08:14:00 -08:00
Jeremy Ashkenas
e983032762 more docs... scoped loops, --join. 2010-12-22 22:43:13 -08:00
Jeremy Ashkenas
f5c5709cd9 trailing file, uncompiled. 2010-12-22 21:46:06 -08:00
Jeremy Ashkenas
fb874e1d65 fixing test_literals 2010-12-22 21:32:48 -08:00
Jeremy Ashkenas
6495508194 First draft of --join. 2010-12-22 21:26:15 -08:00
Jeremy Ashkenas
482626b9b8 Fixing issue #924 ... static methods of nested classes. 2010-12-22 19:01:32 -08:00
Jeremy Ashkenas
9f01040d46 fixing arrayEq and arrayEqual in test.html 2010-12-22 18:34:36 -08:00
Jeremy Ashkenas
cdf298bafb Updating test.html 2010-12-22 17:10:21 -08:00
Jeremy Ashkenas
a2f9f9320b Adding a comprehension/jump test. 2010-12-22 09:44:59 -08:00
Jeremy Ashkenas
0a48f613ec Removed the last bits of pureStatements 2010-12-22 12:23:08 -05:00
Jeremy Ashkenas
19f2d69be8 removing containsPureStatement 2010-12-22 12:10:52 -05:00
Jeremy Ashkenas
241de27c75 waypoint 2010-12-22 12:09:05 -05:00
Jeremy Ashkenas
df8dafc5ca starting to move over isPureStatement to Coco style jumps() 2010-12-22 12:00:46 -05:00
Jeremy Ashkenas
d01b7ac682 last logo tweak (I promise) 2010-12-22 10:24:12 -05:00
Jeremy Ashkenas
3161723c8b change logo 2010-12-22 06:25:30 -05:00
Michael Ficarra
a907811b22 just finishing up ranges_slices_and_splices.coffee 2010-12-22 01:39:58 -05:00
Jeremy Ashkenas
f1d298450d intro. 2010-12-21 22:34:53 -05:00
Jeremy Ashkenas
53eb66e5c4 trying to shorten the table of contents. 2010-12-21 22:24:24 -05:00
Jeremy Ashkenas
907f576010 sprucing up the error messages. 2010-12-21 22:02:53 -05:00
Jeremy Ashkenas
f24c2146e0 blackening the logo. 2010-12-21 21:53:49 -05:00
Jeremy Ashkenas
c342b58a87 The load button now includes the snippet from the 'run' button, at the end (homepage) 2010-12-21 21:51:39 -05:00
Jeremy Ashkenas
be8feb7ee8 Accurate positioning of the repl_bridge, hopefully. 2010-12-21 21:35:43 -05:00
Jeremy Ashkenas
b32eb2bfc1 new logo, credit to rampall. 2010-12-21 21:28:31 -05:00
Jeremy Ashkenas
4375a03f38 Fiddling with For#compileNode. 2010-12-21 21:03:52 -05:00
Jeremy Ashkenas
ad9b7d700a Fiddling with For#compileNode. 2010-12-21 20:59:58 -05:00
Jeremy Ashkenas
460272291f Some Try CoffeeScript tweaks ... scrolling left-hand, opt-out load buttons, correct cursor. 2010-12-21 20:43:13 -05:00
Jeremy Ashkenas
f567dafe62 being stricter about body-less scoped loops. 2010-12-21 20:28:48 -05:00
Jeremy Ashkenas
3c86c57765 some cleanups for hasPure 2010-12-21 20:01:30 -05:00
Jeremy Ashkenas
dc2f77e019 Allowing the fat arrow to be used in scoped loops. 2010-12-21 19:14:53 -05:00
Jeremy Ashkenas
80693d8338 Updating documentation for has own key, value 2010-12-21 18:57:23 -05:00
Jeremy Ashkenas
72e5c4300c Removing 'do', in favor of a trailing -> 2010-12-21 18:54:36 -05:00
Jeremy Ashkenas
6e7168b3e9 first re-implementation of 'do' 2010-12-21 16:12:30 -05:00
Jeremy Ashkenas
31892e1d68 Issue #959 (and countless others) Removing the loop-block-scoped magic for once and for all. 2010-12-21 15:45:46 -05:00
Jeremy Ashkenas
aa3099ce09 Adding notes about Ubuntu and Windows installation. 2010-12-21 14:25:28 -05:00
Jeremy Ashkenas
c6b90b9068 Congo -> coffee-mongo 2010-12-21 12:08:04 -05:00
Jeremy Ashkenas
47fe5c201c more existential. 2010-12-21 00:48:54 -05:00
Jeremy Ashkenas
f7d19f5a3a drying up compileSplice 2010-12-21 00:46:31 -05:00
Jeremy Ashkenas
d42f7daef7 Issue #943 -- splices with expressions. 2010-12-20 23:41:58 -05:00
Jeremy Ashkenas
53363e6b80 Issue #958. Removing UNLESS tokens to make them just inverted IFs. 2010-12-20 22:50:49 -05:00
Jeremy Ashkenas
7ba0573702 More tweaks to Slice#compileNode 2010-12-20 08:13:07 -05:00
Jeremy Ashkenas
777a99fe07 tweaks to Slice#compileNode 2010-12-19 20:19:50 -05:00
Jeremy Ashkenas
3b392b2dd9 rebuilt parser with Jison 0.2.0 2010-12-19 20:04:49 -05:00
Jeremy Ashkenas
6009929a3b Merge branch 'master' of https://github.com/grayrest/coffee-script 2010-12-18 18:28:16 -05:00
Jeremy Ashkenas
c1c9de4546 utils -> util (again) 2010-12-18 17:44:28 -05:00
Karl Guertin
c08ae001a6 Add additional test cases for implicit object calls 2010-12-18 16:06:07 -05:00
Joshua Peek
6c2c4d4428 Exclude docs, examples, and tests from npm package 2010-12-18 14:27:31 -06:00
Karl Guertin
e692e7cd9e Take out object call rewriter condition 2010-12-18 15:27:19 -05:00
Michael Ficarra
f0a62e83c8 Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-18 15:05:39 -05:00
Michael Ficarra
a01225db39 moving global identity function back into just the files in which it is
used
2010-12-18 15:04:47 -05:00
Jeremy Ashkenas
b36f6b67e6 removing start from balancedString. 2010-12-18 14:48:44 -05:00
Michael Ficarra
782de8743f updated comment for arrayEqual function, mentioning that it tests for
functional equivalence
2010-12-18 14:48:43 -05:00
Michael Ficarra
c42ac967ea changed arrayEqual to arrayEq, added global identity function id 2010-12-18 14:45:32 -05:00
Jeremy Ashkenas
e379fcf2cf unterminated -> missing. 2010-12-18 14:40:22 -05:00
Jeremy Ashkenas
89678fca47 unterminated -> missing. 2010-12-18 14:38:55 -05:00
Michael Ficarra
e378f79d2b moving splats.coffee back to test_splats.coffee while it's in development 2010-12-18 14:24:40 -05:00
Jeremy Ashkenas
fba165408c #923 ... correct interpolation. 2010-12-18 13:20:14 -05:00
Jeremy Ashkenas
dd168373a1 1.0.0-pre, that is. 2010-12-18 12:14:40 -05:00
Michael Ficarra
076e60378a begun working on refactoring test_splats.coffee 2010-12-18 11:57:27 -05:00
Jeremy Ashkenas
526af777d4 Adding 'by' to the documentation. 2010-12-18 11:54:40 -05:00
Jeremy Ashkenas
f121558668 Starting to use development versions. This one is '1.0-pre' 2010-12-18 10:53:08 -05:00
Jeremy Ashkenas
640ba7d69e Issue #948. A plucked direct call should not have shared scope. (kinda defeats the whole point.) 2010-12-18 10:41:44 -05:00
Jeremy Ashkenas
bc4498e018 Issue #910. Adding support for a --nodejs flag to forward arguments. 2010-12-18 09:29:04 -05:00
Michael Ficarra
805d03125b added --node flag for passing options through directly to node 2010-12-17 02:39:39 -05:00
Michael Ficarra
7499f0811b bugfix for previous fix to #930 and added (almost) all tests to
ranges_slices_and_splices.coffee
2010-12-16 20:21:29 -05:00
Michael Ficarra
37e0566957 Merge branch 'master' of git://github.com/jashkenas/coffee-script into refactorTests 2010-12-16 12:41:55 -05:00
Michael Ficarra
1fbaff9f81 using 9e9 over 1/0 for compatibility 2010-12-16 12:18:53 -05:00
Jeremy Ashkenas
c3943d21d0 Pulling out a lastNonComment method. 2010-12-16 11:35:51 -05:00
Jeremy Ashkenas
a7158ec69c fixing trailing herecomments with 'break' 2010-12-16 08:23:34 -05:00
Michael Ficarra
f66906d54d finished converting tests to newer, cleaner format in
test_ranges_slices_and_splices.coffee, just need to add some new ones
2010-12-16 05:14:57 -05:00
Michael Ficarra
85afef9981 crap, forgot to remove a piece of temporary code 2010-12-16 04:43:32 -05:00
Michael Ficarra
bd463a038c overhaul of last fix for #930, much better this time 2010-12-16 04:39:17 -05:00
Michael Ficarra
eeb1a284a8 Fixing #930 so I can work on testing ranges, slices, and splices.
Regression tests for this will come with the other refactored slicing
tests in a future commit.
2010-12-16 03:25:54 -05:00
Michael Ficarra
b38cc75f17 refactored test_if.coffee, renamed to conditionals.coffee 2010-12-16 01:06:40 -05:00
Michael Ficarra
dd11528160 changed occurrences of deepEqual to new, self-defined arrayEqual for
recursively walking arrays and testing if their values are equal
2010-12-16 00:12:11 -05:00
Michael Ficarra
912d6f442a Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-15 23:57:15 -05:00
Jeremy Ashkenas
346621ed21 Fix for #926 2010-12-15 23:38:27 -05:00
Jeremy Ashkenas
941f5a8ecb tagged -> stable 2010-12-15 23:20:32 -05:00
Jeremy Ashkenas
76e11e6f64 Fixing #934 (at least partially). 2010-12-15 22:59:28 -05:00
Jeremy Ashkenas
3c558ebbee pulling jQuery in locally, rebuilding docs with variable scope patch 2010-12-15 21:11:43 -05:00
Michael Ficarra
eba7b16ccf Merge branch 'master' of git://github.com/jashkenas/coffee-script into refactorTests
Conflicts:
	test/importing.coffee
2010-12-14 03:23:44 -05:00
Jeremy Ashkenas
466cd43277 Pulling in variable declarations closer to inner scope (after Coco). 2010-12-13 21:24:32 -05:00
Michael Ficarra
47acbefa57 forgot to rename test_helpers.coffee to helpers.coffee 2010-12-13 06:34:42 -05:00
Michael Ficarra
d9cf34ab8c Refactored test_helpers.coffee. Added now-needed deepEqual to browser
test page; warning: was unable to test it, so it might be completely
broken!
2010-12-13 06:28:17 -05:00
Michael Ficarra
9dc7d2a081 CoffeeScript.helpers.count now handles empty strings properly instead of
going into an infinite loop
2010-12-13 05:51:57 -05:00
Michael Ficarra
438708ea15 using deepEqual where I would have like to before, if I had known about
it
2010-12-13 05:03:11 -05:00
Michael Ficarra
835840e8da minor enhancements to test/exception_handling.coffee 2010-12-13 01:27:22 -05:00
Michael Ficarra
d13e0762d3 fixed error introduced when testingBrowser global was added to
cakefile and test/importing.coffee. `testingBrowser` did not exist when
running the test suite through cake:test.
2010-12-13 00:27:41 -05:00
Michael Ficarra
ae8f6a6db5 Merge branch 'master' of git://github.com/jashkenas/coffee-script into refactorTests 2010-12-12 23:28:14 -05:00
Michael Ficarra
608c5fd516 Merge branch 'master' of github.com:michaelficarra/coffee-script into refactorTests 2010-12-12 23:28:04 -05:00
Jeremy Ashkenas
b5bd58b2b6 fixing some site bugs. 2010-12-12 21:53:17 -05:00
Jeremy Ashkenas
9785fd0333 Bumping site. 2010-12-12 21:41:04 -05:00
Michael Ficarra
b02a1ee037 just fixing a single test in test_functions.coffee for now, so I don't
forget my suggested fix
2010-12-12 18:35:41 -05:00
Michael Ficarra
5de43fca4e added try-catch around script eval so that errors that are NOT inside
`test` calls (or syntax errors) are caught, and the test suite can
continue on
2010-12-12 18:34:44 -05:00
Jeremy Ashkenas
46fdbd629d prettifying coffeescript.org, part 3. Next up, Try CoffeeScript 2010-12-12 15:02:27 -05:00
Jeremy Ashkenas
2f4902a478 prettifying coffeescript.org, part 2 2010-12-12 14:34:33 -05:00
Jeremy Ashkenas
7e58c5009e first round of prettifications to coffeescript.org 2010-12-12 14:11:33 -05:00
Jeremy Ashkenas
39009dcfb9 Fixing Issue #916. Overoptimization leading to empty var; 2010-12-12 12:16:27 -05:00
Michael Ficarra
a19ea4b662 refactored test_regexps.coffee 2010-12-12 05:04:48 -05:00
Michael Ficarra
63bc12d3f1 refactored test_importing.coffee 2010-12-12 01:13:02 -05:00
Jeremy Ashkenas
b9c2236885 Merging in MichaelFicarra's refactorTests branch. 2010-12-11 20:30:48 -05:00
Jeremy Ashkenas
450ae723cb Merge branch 'refactorTests' of http://github.com/michaelficarra/coffee-script 2010-12-11 19:47:35 -05:00
Jeremy Ashkenas
2ac5ee4062 Adding an existential infix operator example. 2010-12-11 19:44:11 -05:00
Michael Ficarra
0d436b5f11 updated comments.coffee to make use of new micro-framework 2010-12-11 15:51:48 -05:00
Michael Ficarra
ca6983139e Merge branch 'master' of git://github.com/jashkenas/coffee-script into refactorTests 2010-12-11 15:02:37 -05:00
Jeremy Ashkenas
9f56c92497 Issue #853. Normalizing values of ARGV and argv with Node.js 2010-12-11 13:50:59 -05:00
Michael Ficarra
113cecc4f0 updated all completed test files except comments.coffee to the new
testing mini-framework
2010-12-10 00:23:37 -05:00
Michael Ficarra
7ac1176120 a little extra enhancement to cake test 2010-12-10 00:16:25 -05:00
Michael Ficarra
09c23a564d majorly enhanced test output 2010-12-09 23:59:50 -05:00
Michael Ficarra
a969d3ff1d Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-09 22:49:58 -05:00
Jeremy Ashkenas
b6324d0007 Fixing issue #902 ... collected comprehension when no comprehension is necessary. 2010-12-09 22:16:32 -05:00
Jeremy Ashkenas
ba27b4be69 Fixing Issue #904. Destructuring parameters need to reserve their variable names as if they were true parameters. 2010-12-09 21:34:52 -05:00
Jeremy Ashkenas
7c3ef56332 LEVEL_PAREN -> LEVEL_LIST 2010-12-09 21:12:24 -05:00
Jeremy Ashkenas
7b9286b2c2 Issue #905. Fixing soaked-value-as-a-comprehension-subject ... incorrect LEVEL_TOP. 2010-12-09 21:03:41 -05:00
Michael Ficarra
50d2b4e0b5 Merge branch 'master' of git://github.com/jashkenas/coffee-script into refactorTests 2010-12-08 01:29:40 -05:00
Michael Ficarra
f1988a9e20 refactored test_try_catch.coffee 2010-12-08 01:27:29 -05:00
Jeremy Ashkenas
a24a3c565e Merge branch 'fixSplices' of http://github.com/michaelficarra/coffee-script 2010-12-07 22:24:17 -05:00
Jeremy Ashkenas
20d87297b2 merging in 909 2010-12-07 22:16:27 -05:00
Michael Ficarra
049df99afc consistency: eq(expected,actual), formatting, etc. 2010-12-07 22:04:16 -05:00
Michael Ficarra
6dcdf4ff45 refactored test_comments.coffee 2010-12-07 21:01:58 -05:00
Michael Ficarra
00fd33b635 fixes (temporarily) issue #908; line 1232 of src/nodes.coffee still
needs a rewrite though
2010-12-07 19:44:47 -05:00
Michael Ficarra
f2dc526fc8 Fixing compileSplice broken by c7a9801d because " + 1" is now evaluated
as NaN by node. Removed that implicit cast entirely.
2010-12-07 14:27:44 -05:00
Michael Ficarra
e5491198f6 Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests
Conflicts:
	lib/coffee-script.js
2010-12-07 12:27:03 -05:00
Jeremy Ashkenas
4cab45c759 mention dynakey removal in the changelog 2010-12-07 11:08:16 -05:00
Jeremy Ashkenas
fa53a4c057 CoffeeScript 0.9.6 2010-12-07 00:21:34 -05:00
Jeremy Ashkenas
edd0c5af5a no-op. 2010-12-06 23:39:06 -05:00
Jeremy Ashkenas
2fb269a938 refactoring Scope. 2010-12-06 23:32:32 -05:00
Jeremy Ashkenas
3eac6aeb99 rebuilding browser coffee-script.js ... all tests pass. 2010-12-06 23:21:55 -05:00
Jeremy Ashkenas
ec64646fee Issue #901 ... allow constructor functions to maintain their position in the class body. 2010-12-06 01:01:57 -05:00
Michael Ficarra
5371268f8f Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-05 22:31:28 -05:00
Jeremy Ashkenas
2decb30d4e Issue #897 ... fixed leaking direct-call-plucked comprehension variables, due to shared scope. 2010-12-05 21:18:30 -05:00
Jeremy Ashkenas
c0bbc609be Fixing direct construction splats. 2010-12-05 20:44:32 -05:00
Jeremy Ashkenas
f6be426aa0 utils -> util. 2010-12-05 17:51:52 -05:00
Jeremy Ashkenas
17b5c8ac6f Issue #887 and #893. Adding timestamps to --watch --compile. 2010-12-05 16:06:13 -05:00
Jeremy Ashkenas
b18d0d75fd adding newlines after error stacktrace in REPL. 2010-12-05 15:46:04 -05:00
Jeremy Ashkenas
77e13e459b Fixing the repl so that errors print properly, and async exceptions are logged instead of killing the session. 2010-12-05 15:40:49 -05:00
Jeremy Ashkenas
06647bdd0a Adding warning about accidentally-comprehended-functions. Issue #896. 2010-12-05 15:29:28 -05:00
Jeremy Ashkenas
24183d9a39 Issue #894: Strange interaction between class instantiation and splats 2010-12-05 15:08:41 -05:00
Michael Ficarra
1e080cc258 Merge branch 'master' of github.com:michaelficarra/coffee-script into refactorTests 2010-12-05 13:37:34 -05:00
Michael Ficarra
dc5854689b fix for bug introduced in 63cbb643 2010-12-05 13:10:14 -05:00
Michael Ficarra
ed70b9d4d0 test for bug introduced in 63cbb643
discussion: 63cbb64341 (commitcomment-209643)
2010-12-05 13:08:14 -05:00
Jeremy Ashkenas
c7a9801db7 simplifying generated output for common-case splices. 2010-12-04 15:06:21 -05:00
Jeremy Ashkenas
85521f88b2 typo 2010-12-04 12:55:46 -05:00
Jeremy Ashkenas
75ca0f23ac redocumenting slices/splices ... issue #833 2010-12-04 12:52:51 -05:00
Michael Ficarra
eba73f6844 refactored test_break.coffee 2010-12-04 01:44:08 -05:00
Michael Ficarra
cf45da33f6 refactored test_assignment.coffee 2010-12-03 18:21:09 -05:00
Michael Ficarra
fb7498a8ec made reserved words available as CoffeeScript.RESERVED 2010-12-03 18:07:36 -05:00
Michael Ficarra
574f9afa3d using nonces more where applicable, also added tests for default
arguments
2010-12-03 17:10:36 -05:00
Michael Ficarra
3751ac1784 refactored test_arguments.coffee 2010-12-03 16:24:22 -05:00
Michael Ficarra
af759dcf42 test_operations: removed the top-level closures that symbolized
sections
2010-12-03 14:49:21 -05:00
Michael Ficarra
47426c28e1 test_operations: using eq instead of ok wherever possible, as per
satyr's suggestion
2010-12-03 14:43:45 -05:00
Michael Ficarra
49f7775d2d refactored test_operations.coffee 2010-12-03 13:01:13 -05:00
Jeremy Ashkenas
67c20c0715 style tweaks to previous patch. 2010-12-03 01:23:54 -05:00
Michael Ficarra
c50cb65019 Chained comparisons now properly apply DeMorgan's Laws. I couldn't
believe there wasn't a test to remind me to toggle the
{dis,con}junctions. Added that test.
2010-12-03 00:07:30 -05:00
Michael Ficarra
23b4d2fd1d Finally got !== and === back to inverting again (instead of wrapping in
`!()`)

Also, removed the `@inverted` kludge. It was gross to begin with, but I
didn't know the proper way to do it.
2010-12-02 23:03:21 -05:00
Michael Ficarra
dd18703b50 Issue #891: cannot safely invert < and > to >= and <= (or the
other way around). Proper fix this time.
2010-12-02 20:55:19 -05:00
Michael Ficarra
b1ba298ffc Reverted previous change to what was believed to be an errant test case.
Also added a test for NaN safety
2010-12-02 20:54:15 -05:00
Michael Ficarra
992324b425 fix for #891: incorrect inversion of chained comparisons 2010-12-02 12:55:53 -05:00
Michael Ficarra
56e10f9bce added test for #891: incorrect inversion of chained comparisons; fixed a
faulty test case in test/test_switch.coffee
2010-12-02 12:55:28 -05:00
Jeremy Ashkenas
69664a1bb3 Adding precedence change note to changelog 2010-12-01 14:17:10 -05:00
Jeremy Ashkenas
1f5727fe9d Coco 38aa762: rewriter: made addImplicitBraces consume multiple leading comments 2010-11-28 17:54:00 -08:00
Jeremy Ashkenas
b52a1ed60a disallow index mentions for range loops. 2010-11-28 15:54:39 -08:00
Jeremy Ashkenas
c3f1820ebc Issue #856. Invert 2010-11-28 15:33:43 -08:00
Jeremy Ashkenas
4afa6a2887 Issue #860. Nested classes. 2010-11-28 14:56:07 -08:00
Jeremy Ashkenas
1254efaddb Issue #878. Namespaced classes should not leak their function name. 2010-11-28 10:08:49 -08:00
Jeremy Ashkenas
adeace8f62 Merge branch 'issue/875' of git://github.com/StanAngeloff/coffee-script 2010-11-28 09:55:54 -08:00
Jeremy Ashkenas
4447180d5a Removing dynamic keys from objects. 2010-11-28 09:42:43 -08:00
Jeremy Ashkenas
41beccbe3c reverting Scope#temporary simplification. 2010-11-28 09:28:46 -08:00
Jeremy Ashkenas
a4958e76c1 whitespace 2010-11-28 09:27:06 -08:00
Stan Angeloff
a9e264dd84 console.{log,warn} → print{Line,Warn} 2010-11-28 16:04:52 +02:00
Jeremy Ashkenas
51988dba09 Removing unused garbage collection from Scope. 2010-11-27 18:04:40 -08:00
Jeremy Ashkenas
39c4c23200 nested shared scopes don't clobber variables. 2010-11-27 17:52:52 -08:00
Michael Ficarra
63cbb64341 fixes #855; fix partially inspired by satyr/coco 3e37cf32 2010-11-26 02:08:25 -05:00
Michael Ficarra
c0cb0c35e2 adding tests for #855 2010-11-26 02:06:10 -05:00
Jeremy Ashkenas
9db6d6f4ef Updating rake task to pull version number and date. 2010-11-21 22:33:27 -05:00
Jeremy Ashkenas
57bd6bc2cd Adding the coffee-script-source gem publisher to the Rakefile. 2010-11-21 21:42:15 -05:00
119 changed files with 11334 additions and 3684 deletions

11
.npmignore Normal file
View File

@@ -0,0 +1,11 @@
*.coffee
*.html
.DS_Store
.git*
Cakefile
documentation/
examples/
extras/
raw/
src/
test/

View File

@@ -73,7 +73,7 @@ task 'build:full', 'rebuild the source twice, and run the tests', ->
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
extend global, require('utils')
extend global, require('util')
require 'jison'
parser = require('./lib/grammar').parser
fs.writeFile 'lib/parser.js', parser.generate()
@@ -143,32 +143,78 @@ task 'loc', 'count the lines of source code in the CoffeeScript compiler', ->
console.log stdout.trim()
# Run the CoffeeScript test suite.
runTests = (CoffeeScript) ->
startTime = Date.now()
passedTests = failedTests = 0
for all name, func of require 'assert'
startTime = Date.now()
currentFile = null
passedTests = 0
failures = []
# Mix in the assert module globally, to make it available for tests.
addGlobal = (name, func) ->
global[name] = ->
passedTests += 1
func arguments...
addGlobal name, func for name, func of require 'assert'
# Convenience aliases.
global.eq = global.strictEqual
global.CoffeeScript = CoffeeScript
# Our test helper function for delimiting different test cases.
global.test = (description, fn) ->
try
fn()
catch e
e.description = description if description?
e.source = fn.toString() if fn.toString?
failures.push file: currentFile, error: e
# A recursive functional equivalence helper; uses egal for testing equivalence.
# See http://wiki.ecmascript.org/doku.php?id=harmony:egal
arrayEqual = (a, b) ->
if a is b
# 0 isnt -0
a isnt 0 or 1/a is 1/b
else if a instanceof Array and b instanceof Array
return no unless a.length is b.length
return no for el, idx in a when not arrayEqual el, b[idx]
yes
else
# NaN is NaN
a isnt a and b isnt b
global.arrayEq = (a, b, msg) -> ok arrayEqual(a,b), msg
# When all the tests have run, collect and print errors.
# If a stacktrace is available, output the compiled function source.
process.on 'exit', ->
time = ((Date.now() - startTime) / 1000).toFixed(2)
message = "passed #{passedTests} tests in #{time} seconds#{reset}"
if failedTests
log "failed #{failedTests} and #{message}", red
else
log message, green
return log(message, green) unless failures.length
log "failed #{failures.length} and #{message}", red
for fail in failures
{error, file} = fail
jsFile = file.replace(/\.coffee$/,'.js')
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
[match, line, col] = match if match
log "\n #{error.toString()}", red
log " #{error.description}", red if error.description
log " #{jsFile}: line #{line or 'unknown'}, column #{col or 'unknown'}", red
console.log " #{error.source}" if error.source
# Run every test in the `test` folder, recording failures.
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
try
CoffeeScript.run code.toString(), {fileName}
catch err
failedTests += 1
log "failed #{fileName}", red, '\n' + err.stack?.toString()
catch e
failures.push file: currentFile, error: e
task 'test', 'run the CoffeeScript language test suite', ->
@@ -178,5 +224,6 @@ task 'test', 'run the CoffeeScript language test suite', ->
task 'test:browser', 'run the test suite against the merged browser script', ->
source = fs.readFileSync 'extras/coffee-script.js', 'utf-8'
result = {}
global.testingBrowser = yes
(-> eval source).call result
runTests result.CoffeeScript

View File

@@ -1,6 +1,8 @@
require 'rubygems'
require 'erb'
require 'fileutils'
require 'rake/testtask'
require 'json'
desc "Build the documentation page"
task :doc do
@@ -19,3 +21,58 @@ task :doc do
end
end
desc "Build coffee-script-source gem"
task :gem do
require 'rubygems'
require 'rubygems/package'
gemspec = Gem::Specification.new do |s|
s.name = 'coffee-script-source'
s.version = JSON.parse(File.read('package.json'))["version"]
s.date = Time.now.strftime("%Y-%m-%d")
s.homepage = "http://jashkenas.github.com/coffee-script/"
s.summary = "The CoffeeScript Compiler"
s.description = <<-EOS
CoffeeScript is a little language that compiles into JavaScript.
Underneath all of those embarrassing braces and semicolons,
JavaScript has always had a gorgeous object model at its heart.
CoffeeScript is an attempt to expose the good parts of JavaScript
in a simple way.
EOS
s.files = [
'lib/coffee_script/coffee-script.js',
'lib/coffee_script/source.rb'
]
s.authors = ['Jeremy Ashkenas']
s.email = 'jashkenas@gmail.com'
s.rubyforge_project = 'coffee-script-source'
end
file = File.open("coffee-script-source.gem", "w")
Gem::Package.open(file, 'w') do |pkg|
pkg.metadata = gemspec.to_yaml
path = "lib/coffee_script/source.rb"
contents = <<-ERUBY
module CoffeeScript
module Source
def self.bundled_path
File.expand_path("../coffee-script.js", __FILE__)
end
end
end
ERUBY
pkg.add_file_simple(path, 0644, contents.size) do |tar_io|
tar_io.write(contents)
end
contents = File.read("extras/coffee-script.js")
path = "lib/coffee_script/coffee-script.js"
pkg.add_file_simple(path, 0644, contents.size) do |tar_io|
tar_io.write(contents)
end
end
end

View File

@@ -1,7 +1,2 @@
# Eat lunch.
lunch = eat food for food in ['toast', 'cheese', 'wine']
# Naive collision detection.
for roid, pos in asteroids
for roid2 in asteroids when roid isnt roid2
roid.explode() if roid.overlaps roid2
eat food for food in ['toast', 'cheese', 'wine']

View File

@@ -1,4 +1,6 @@
###
CoffeeScript Compiler v0.9.5
CoffeeScript Compiler v1.0.0
Released under the MIT License
###
###

View File

@@ -8,4 +8,6 @@ else
date = if friday then sue else jill
options or= defaults
options or= defaults

View File

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

View File

@@ -1,6 +1,8 @@
solipsism = true if mind? and not world?
speed ?= 140
speed ?= 75
footprints = yeti ? "bear"

View File

@@ -1 +1,3 @@
six = (one = 1) + (two = 2) + (three = 3)
six = (one = 1) + (two = 2) + (three = 3)

View File

@@ -3,4 +3,5 @@ alert(
nonexistent / undefined
catch error
"And the error is ... " + error
)
)

View File

@@ -2,4 +2,6 @@ html = '''
<strong>
cup of coffeescript
</strong>
'''
'''

View File

@@ -6,4 +6,6 @@ OPERATOR = /// ^ (
| ([&|<>])\2=? # logic / shift
| \?\. # soak access
| \.{2,3} # range or splat
) ///
) ///

View File

@@ -2,7 +2,7 @@ song = ["do", "re", "mi", "fa", "so"]
singers = {Jagger: "Rock", Elvis: "Roll"}
matrix = [
bitlist = [
1, 0, 1
0, 0, 1
1, 1, 0
@@ -14,4 +14,6 @@ kids =
age: 11
sister:
name: "Ida"
age: 9
age: 9

View File

@@ -1,3 +1,5 @@
$('.account').attr class: 'active'
log object.class
log object.class

View File

@@ -1,4 +1,6 @@
theBait = 1000
theSwitch = 0
[theBait, theSwitch] = [theSwitch, theBait]
[theBait, theSwitch] = [theSwitch, theBait]

View File

@@ -1,2 +1,3 @@
String::dasherize = ->
this.replace /_/g, "-"
this.replace /_/g, "-"

View File

@@ -0,0 +1,7 @@
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
copy = numbers[0...numbers.length]
middle = copy[3..6]

View File

@@ -22,4 +22,6 @@ awardMedals contenders...
alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest
alert "The Field: " + rest

View File

@@ -0,0 +1,5 @@
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers[3..6] = [-3, -4, -5, -6]

View File

@@ -4,4 +4,5 @@ try
catch error
print error
finally
cleanUp()
cleanUp()

View File

@@ -1,8 +1,9 @@
body {
font-size: 13px;
line-height: 20px;
color: #191933;
font-family: "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important;
font-size: 14px;
line-height: 21px;
color: #333;
background: #f6f6f6 url(../images/background.png);
font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif !important;
}
.container {
width: 950px;
@@ -13,11 +14,14 @@ p, li {
width: 625px;
}
a {
color: #000055;
color: #191933;
}
h1, h2, h3, h4, h5, h6, b.header {
font-size: 18px;
color: #000;
margin-top: 40px;
margin-bottom: 15px;
text-shadow: #fff 0 1px 1px;
}
br.clear {
height: 0;
@@ -27,9 +31,7 @@ ul {
padding-left: 20px;
}
b.header {
color: #000055;
display: block;
font-size: 16px;
}
li {
margin-bottom: 10px;
@@ -47,7 +49,7 @@ table {
table.definitions {
width: auto;
margin: 30px 0;
border-left: 6px solid #ccccdd;
border-left: 5px solid rgba(0,0,0,0.2);;
}
table.definitions td {
text-align: center;
@@ -57,17 +59,18 @@ code, pre, tt, textarea {
font-family: Monaco, Consolas, "Lucida Console", monospace;
font-size: 12px;
line-height: 18px;
color: #191955;
color: #155;
white-space: pre-wrap;
word-wrap: break-word;
}
tt {
background: #f8f8ff;
display: inline-block;
background: #fff;
border: 1px solid #dedede;
padding: 0px 0.2em;
}
pre {
border-left: 6px solid #ccccdd;
border-left: 5px solid rgba(0,0,0,0.2);
padding: 3px 0 3px 12px;
font-size: 12px;
}
@@ -76,26 +79,35 @@ code, pre, tt, textarea {
margin-left: 0;
padding-left: 0;
}
.timestamp {
font-size: 12px;
font-weight: normal;
color: black;
}
div.code {
position: relative;
border: 1px solid #cacaca;
background: #fafaff;
padding: 7px 0 10px 0;
-moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px;
-webkit-box-shadow: 0px 0px 7px #cacaca;
background: #fff;
border: 1px solid #d8d8d8;
-webkit-box-shadow: 0px 0px 4px rgba(0,0,0,0.23);
-moz-box-shadow: 0px 0px 4px rgba(0,0,0,0.23);
box-shadow: 0px 0px 4px rgba(0,0,0,0.23);
zoom: 1;
}
div.code button {
div.code .minibutton {
text-transform: none;
position: absolute;
right: 8px; bottom: 8px;
}
div.code .load {
left: 8px; right: auto;
}
div.code pre, div.code textarea {
float: left;
width: 450px;
background: #fafaff;
border-left: 1px dotted #559;
background: #fff;
border-left: 1px dotted #d0d0d0;
margin: 10px 0 15px 3px;
padding: 0 0 0 12px;
margin: 0;
}
div.code pre:first-child {
border-left: 0;
@@ -116,32 +128,38 @@ div.code {
height: 50px;
min-width: 490px;
left: 40px; right: 40px; top: 25px;
padding-left: 235px;
padding-left: 252px;
background: #eee;
background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#d0d0d0));
background: -moz-linear-gradient(top, #f5f5f5, #d0d0d0);
background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#dadada));
background: -moz-linear-gradient(top, #f8f8f8, #dadada);
border: 1px solid #aaa;
-webkit-border-radius: 20px; -moz-border-radius: 20px; border-radius: 20px;
-webkit-box-shadow: 0 0 7px #aaa; -moz-box-shadow: 0 0 7px #aaa;
border-top: 1px solid #bbb;
border-bottom: 1px solid #888;
-webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;
-webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1);
-moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1);
box-shadow: 0 3px 5px rgba(0,0,0,0.1);
}
#logo {
display: block;
width: 215px; height: 50px;
width: 225px; height: 50px;
background: url('../images/logo.png');
position: absolute;
top: 0px; left: 10px;
}
#error {
position: absolute;
-webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px;
right: 15px; top: 15px; left: 730px;
height: 15px;
padding: 2px 5px;
-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;
-webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0; border-top-left-radius: 0;
-webkit-border-bottom-left-radius: 0; -moz-border-radius-bottomleft: 0; border-bottom-left-radius: 0;
right: 0px; top: 0px; left: 726px; bottom: 0;
padding: 0 0 0 15px;
background: #fdcdcc;
color: #864544;
border: 1px solid #864544;
background: -webkit-gradient(linear, left top, left bottom, from(#ffedec), to(#ff9a95));
background: -moz-linear-gradient(top, #f8f8f8, #dadada);
color: #862322;
font-size: 10px;
line-height: 15px;
line-height: 50px;
overflow: hidden;
text-transform: uppercase;
}
@@ -153,91 +171,93 @@ div.code {
position: relative;
float: left;
padding: 0 20px;
border: 1px solid #bbb;
border: 1px solid #aaa;
border-top: 0; border-bottom: 0; border-left-width: 0;
cursor: pointer;
}
body.full_screen .navigation {
position: static;
}
.navigation.toc {
border-left-width: 1px;
}
.navigation:hover,
.navigation.active {
background: #eee;
background: -webkit-gradient(linear, left top, left bottom, from(#f0f0f0), to(#c0c0c0));
background: -moz-linear-gradient(top, #f0f0f0, #c0c0c0);
background: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#f8f8f8));
background: -moz-linear-gradient(top, #eee, #f8f8f8);
}
.navigation.active {
height: 51px;
color: #000;
background: -webkit-gradient(linear, left top, left bottom, from(#e5e5e5), to(#fff));
background: -moz-linear-gradient(top, #e5e5e5, #fff);
}
.navigation .button {
font-weight: bold;
}
.navigation .button::selection {
background: transparent;
}
.navigation .contents {
display: none;
position: absolute;
background: #fff;
opacity: 0.97;
top: 51px; left: 0;
padding: 5px 0;
margin-left: -1px;
border: 1px solid #aaa; border-top: 0;
-webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px;
-webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0;
-webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0;
-webkit-box-shadow: 0 5px 10px #999; -moz-box-shadow: 0 5px 10px #999;
border: 1px solid #aaa;
-webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;
-webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.2);
-moz-box-shadow: 0 3px 5px rgba(0,0,0,0.2);
box-shadow: 0 3px 5px rgba(0,0,0,0.2);
}
.navigation.active .contents {
display: block;
}
.navigation .contents.repl_wrapper {
left: -162px;
width: 700px;
padding: 0;
}
body.full_screen .navigation .contents.repl_wrapper {
position: fixed;
width: auto; height: auto;
left: 60px; top: 77px; right: 60px; bottom: 30px;
}
.navigation .contents.repl_wrapper .code {
-webkit-box-shadow: none; -moz-box-shadow: none;
background: transparent;
border: 0;
position: static;
}
body.full_screen .navigation .contents.repl_wrapper .code {
height: 100%;
padding: 0; margin: 0;
}
.navigation .code button {
bottom: 10px;
text-transform: none;
line-height: 14px;
left: auto; right: auto;
}
.navigation .code .run {
width: 40px;
right: 10px;
}
.navigation .code .full_screen, .navigation .code .minimize {
left: 10px;
display: none;
width: 90px;
}
body.minimized .code .full_screen, body.full_screen .code .minimize {
display: inline;
}
.navigation .contents a {
display: block;
width: 290px;
text-transform: none;
text-decoration: none;
font-weight: normal;
height: 12px;
line-height: 12px;
padding: 4px 10px;
border: 1px solid transparent;
border-left: 0; border-right: 0;
}
.navigation .contents a:hover {
background: #f0f0f0;
border-color: #ddd;
background: #eee;
}
.navigation.active .contents {
display: block;
}
.navigation .contents.menu {
border-top: 0;
-webkit-border-top-left-radius: 0; -moz-border-radius-topleft: 0; border-top-left-radius: 0;
-webkit-border-top-right-radius: 0; -moz-border-radius-topright: 0; border-top-right-radius: 0;
}
.navigation .contents.repl_wrapper {
padding: 0;
position: fixed;
width: auto; height: auto;
left: 40px; top: 90px; right: 40px; bottom: 30px;
background: -webkit-gradient(linear, left top, left bottom, from(#fafafa), to(#eaeaea));
}
.navigation .repl_bridge {
position: absolute;
height: 12px;
left: -1px; right: -1px;
bottom: -14px;
border: 1px solid #aaa;
z-index: 5;
background: #fff;
display: none;
border-top-color: #fff; border-bottom-color: #fff;
}
.navigation.active .repl_bridge {
display: block;
}
.navigation .code .minibutton {
top: 10px; right: 10px;
width: 40px;
text-transform: none;
}
.bookmark {
@@ -247,45 +267,108 @@ div.code {
top: -90px;
}
.navigation .contents.repl_wrapper .code {
cursor: text;
-webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none;
background: #181a3a url(../images/banding.png);
border: 2px solid #555;
padding: 0;
position: absolute;
top: 15px; left: 15px; right: 15px; bottom: 15px;
}
.repl_wrapper .screenshadow {
position: absolute;
width: 200px; height: 150px;
background: url(../images/screenshadow.png?2);
}
.repl_wrapper .screenshadow.tl {
top: 0; left: 0;
background-position: 0 0;
}
.repl_wrapper .screenshadow.tr {
top: 0; right: 0;
background-position: -200px 0;
}
.repl_wrapper .screenshadow.bl {
bottom: 0; left: 0;
background-position: 0 -150px;
}
.repl_wrapper .screenshadow.br {
bottom: 0; right: 0;
background-position: -200px -150px;
}
#repl_source, #repl_results {
background: transparent;
outline: none;
margin: 5px 0 20px;
color: #def;
}
#repl_source_wrap {
margin-left: 5px;
height: 250px;
width: 307px;
position: relative;
float: left;
#repl_results, #repl_source_wrap {
width: auto; height: auto;
position: absolute;
margin-bottom: 0;
top: 10px; left: 10px; right: 10px; bottom: 15px;
}
#repl_source {
width: 96%;
height: 250px;
border: 0;
resize: none;
#repl_source_wrap {
margin-left: 5px;
width: 47%; right: 50%;
float: left;
}
#repl_results {
font-family: Monaco, Consolas, "Lucida Console", monospace;
text-transform: none;
font-weight: normal;
height: 260px;
margin-bottom: 25px;
overflow-y: auto;
width: 370px;
}
body.full_screen #repl_results, body.full_screen #repl_source_wrap {
width: auto; height: auto;
position: absolute;
margin-bottom: 0;
top: 10px; left: 10px; right: 10px; bottom: 40px;
}
body.full_screen #repl_source {
#repl_source {
padding-left: 5px;
width: 100%;
height: 100%;
border: 0;
overflow-y: auto;
resize: none;
}
body.full_screen #repl_source_wrap {
right: 50%;
}
body.full_screen #repl_results {
#repl_results_wrap {
white-space: pre;
}
#repl_results {
text-transform: none;
overflow-y: auto;
left: 50%;
border-left-color: #555;
}
/*----------------------------- Mini Buttons ---------------------------------*/
.minibutton {
cursor: pointer;
color: #333;
text-shadow: #eee 0 1px 1px;
font-weight: bold;
font-size: 11px;
line-height: 11px;
padding: 5px 10px 6px;
height: 11px;
text-align: center;
-webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;
box-shadow: 0 1px 2px rgba(0,0,0,0.2); -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
border: 1px solid #b2b2b2; border-top-color: #c9c9c9; border-bottom-color: #9a9a9a;
background: url(../images/button_bg.png) repeat-x left top;
}
.minibutton:active {
border-color: #aaa;
box-shadow: 0 1px 2px #e4e4e4; -webkit-box-shadow: 0 1px 2px #e4e4e4; -moz-box-shadow: 0 1px 2px #e4e4e4;
}
.minibutton::selection {
background: transparent;
}
.minibutton ::-moz-selection {
background: transparent;
}
.minibutton.ok {
color: #fff;
background-image: url(../images/button_bg_green.gif);
border-color: #4ba47c; border-top-color: #53b388; border-bottom-color: #459671;
text-shadow: #aaa 0 -1px 0;
}
.minibutton.dark {
border: 0;
color: #fff;
box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none;
background-image: url(../images/button_bg_dark.gif);
text-shadow: none;
}

View File

@@ -31,7 +31,7 @@ If no tasks are passed, print the help screen.</p> </td>
<span class="nv">options = </span><span class="nx">oparse</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
<span class="nx">invoke</span> <span class="nx">arg</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">options</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>Display the list of Cake tasks in a format similar to <code>rake -T</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTasks = </span><span class="o">-&gt;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s1">&#39;&#39;</span>
<span class="k">for</span> <span class="nx">all</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">task</span> <span class="k">of</span> <span class="nx">tasks</span>
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">task</span> <span class="k">of</span> <span class="nx">tasks</span>
<span class="nv">spaces = </span><span class="mi">20</span> <span class="o">-</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">spaces = </span><span class="k">if</span> <span class="nx">spaces</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="k">then</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">spaces</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="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="nv">desc = </span><span class="k">if</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span> <span class="k">then</span> <span class="s2">&quot;# #{task.description}&quot;</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>

View File

@@ -4,38 +4,38 @@ contains the main entry functions for tokenizing, parsing, and compiling
source CoffeeScript into JavaScript.</p>
<p>If included on a webpage, it will automatically sniff out, compile, and
execute all scripts present in <code>text/coffeescript</code> tags.</p> </td> <td class="code"> <div class="highlight"><pre><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="p">{</span><span class="nx">Lexer</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>
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="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="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;0.9.5&#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>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-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#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.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
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="k">throw</span> <span class="nx">err</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>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-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>Parse a string of CoffeeScript code or an array of lexed tokens, and
<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,
or traverse it by using <code>.traverse()</code> with a callback.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.nodes = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="k">typeof</span> <span class="nx">source</span> <span class="o">is</span> <span class="s1">&#39;string&#39;</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">source</span><span class="p">,</span> <span class="nx">options</span>
<span class="k">else</span>
<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-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#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-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#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="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-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#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-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#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-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#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">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="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-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
<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-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#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-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
<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
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,16 +4,21 @@ 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>
<span class="p">{</span><span class="nx">spawn</span><span class="p">,</span> <span class="nx">exec</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;child_process&#39;</span>
<span class="p">{</span><span class="nx">EventEmitter</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;events&#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>Allow CoffeeScript to emit Node.js events.</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">CoffeeScript</span><span class="p">,</span> <span class="k">new</span> <span class="nx">EventEmitter</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>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER = </span><span class="s1">&#39;&#39;&#39;</span>
<span class="p">{</span><span class="nx">EventEmitter</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">&#39;events&#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>Allow CoffeeScript to emit Node.js events.</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">CoffeeScript</span><span class="p">,</span> <span class="k">new</span> <span class="nx">EventEmitter</span>
<span class="nv">printLine = </span><span class="p">(</span><span class="nx">line</span><span class="p">)</span> <span class="o">-&gt;</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">line</span> <span class="o">+</span> <span class="s1">&#39;\n&#39;</span>
<span class="nv">printWarn = </span><span class="p">(</span><span class="nx">line</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">process</span><span class="p">.</span><span class="nx">binding</span><span class="p">(</span><span class="s1">&#39;stdio&#39;</span><span class="p">).</span><span class="nx">writeError</span> <span class="nx">line</span> <span class="o">+</span> <span class="s1">&#39;\n&#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>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER = </span><span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> Usage: coffee [options] path/to/script.coffee</span>
<span class="s1"> &#39;&#39;&#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>The list of all the valid option flags that <code>coffee</code> knows how to handle.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SWITCHES = </span><span class="p">[</span>
<span class="p">[</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--compile&#39;</span><span class="p">,</span> <span class="s1">&#39;compile to JavaScript and save as .js files&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-i&#39;</span><span class="p">,</span> <span class="s1">&#39;--interactive&#39;</span><span class="p">,</span> <span class="s1">&#39;run an interactive CoffeeScript REPL&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-o&#39;</span><span class="p">,</span> <span class="s1">&#39;--output [DIR]&#39;</span><span class="p">,</span> <span class="s1">&#39;set the directory for compiled JavaScript&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-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;-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>
@@ -23,33 +28,27 @@ interactive REPL.</p> </td> <td class="code">
<span class="p">[</span><span class="s1">&#39;-b&#39;</span><span class="p">,</span> <span class="s1">&#39;--bare&#39;</span><span class="p">,</span> <span class="s1">&#39;compile without the top-level function wrapper&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-t&#39;</span><span class="p">,</span> <span class="s1">&#39;--tokens&#39;</span><span class="p">,</span> <span class="s1">&#39;print the tokens that the lexer produces&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-n&#39;</span><span class="p">,</span> <span class="s1">&#39;--nodes&#39;</span><span class="p">,</span> <span class="s1">&#39;print the parse tree that Jison produces&#39;</span><span class="p">]</span>
<span class="p">[</span> <span class="s1">&#39;--nodejs [ARGS]&#39;</span><span class="p">,</span> <span class="s1">&#39;pass options through to the &quot;node&quot; binary&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-v&#39;</span><span class="p">,</span> <span class="s1">&#39;--version&#39;</span><span class="p">,</span> <span class="s1">&#39;display CoffeeScript version&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-h&#39;</span><span class="p">,</span> <span class="s1">&#39;--help&#39;</span><span class="p">,</span> <span class="s1">&#39;display this help message&#39;</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>Switches that are still supported, but will cause a warning message.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">DEPRECATED_SWITCHES = </span><span class="p">[</span>
<span class="p">[</span><span class="s1">&#39;--no-wrap&#39;</span><span class="p">,</span> <span class="s1">&#39;compile without the top-level function wrapper&#39;</span><span class="p">]</span>
<span class="p">]</span>
<span class="nv">ALL_SWITCHES = </span><span class="nx">SWITCHES</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">DEPRECATED_SWITCHES</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>Top-level objects shared by all the functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">opts = </span><span class="p">{}</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>Top-level objects shared by all the functions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">opts = </span><span class="p">{}</span>
<span class="nv">sources = </span><span class="p">[]</span>
<span class="nv">optionParser = </span><span class="kc">null</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>Run <code>coffee</code> by parsing passed options and determining what action to take.
<span class="nv">contents = </span><span class="p">[]</span>
<span class="nv">optionParser = </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>Run <code>coffee</code> by parsing passed options and determining what action to take.
Many flags cause us to divert before compiling anything. Flags passed after
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.run = </span><span class="o">-&gt;</span>
<span class="nx">parseOptions</span><span class="p">()</span>
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">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="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>
<span class="k">return</span> <span class="nx">require</span> <span class="s1">&#39;./repl&#39;</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">separator = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">&#39;--&#39;</span>
<span class="nv">flags = </span><span class="p">[]</span>
<span class="k">if</span> <span class="nx">separator</span> <span class="o">&gt;=</span> <span class="mi">0</span>
<span class="nv">flags = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">separator</span> <span class="o">+</span> <span class="mi">1</span>
<span class="nx">sources</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<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="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>
<span class="k">return</span> <span class="nx">require</span> <span class="s1">&#39;./repl&#39;</span> <span class="nx">unless</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">run</span>
<span class="nv">flags = </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">flags</span>
<span class="nv">process.ARGV = process.argv = </span><span class="nx">flags</span>
<span class="nx">compileScripts</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>Asynchronously read in each CoffeeScript in a list of source files and
<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">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>
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
@@ -63,9 +62,14 @@ compile them. If a directory is passed, recursively compile all
<span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span>
<span class="nx">compile</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="nx">file</span><span class="p">)</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">topLevel</span> <span class="o">or</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">is</span> <span class="s1">&#39;.coffee&#39;</span>
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">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="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">true</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>Compile a single source script, containing the given code, according to the
<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="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>
<span class="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="kc">true</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 a single source script, containing the given code, according to the
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>
@@ -76,27 +80,30 @@ requested options. If evaluating the script directly sets <code>__filename</code
<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>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">tokens</span> <span class="k">then</span> <span class="nx">printTokens</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">tokens</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">input</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="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">nodes</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">nodes</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">input</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="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">run</span> <span class="k">then</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
<span class="k">else</span>
<span class="nv">t.output = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">t</span><span class="p">.</span><span class="nx">input</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">options</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">&#39;success&#39;</span><span class="p">,</span> <span class="nx">task</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">writeJs</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">base</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span> <span class="k">then</span> <span class="nx">lint</span> <span class="nx">t</span><span class="p">.</span><span class="nx">file</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">output</span>
<span class="k">catch</span> <span class="nx">err</span>
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">&#39;failure&#39;</span><span class="p">,</span> <span class="nx">err</span><span class="p">,</span> <span class="nx">task</span>
<span class="k">return</span> <span class="k">if</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">listeners</span><span class="p">(</span><span class="s1">&#39;failure&#39;</span><span class="p">).</span><span class="nx">length</span>
<span class="k">return</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">error</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</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>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
<span class="k">return</span> <span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span>
<span class="nx">printWarn</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</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>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
and write them back to <strong>stdout</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileStdio = </span><span class="o">-&gt;</span>
<span class="nv">code = </span><span class="s1">&#39;&#39;</span>
<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="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">code</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">buffer</span>
<span class="nx">stdin</span><span class="p">.</span><span class="kc">on</span> <span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
<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-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="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
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>
@@ -108,18 +115,18 @@ are written out in <code>cwd</code> as <code>.js</code> files with the same name
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>
<span class="nv">srcDir = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">source</span>
<span class="nv">baseDir = </span><span class="nx">srcDir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">baseDir = </span><span class="k">if</span> <span class="nx">base</span> <span class="o">is</span> <span class="s1">&#39;.&#39;</span> <span class="k">then</span> <span class="nx">srcDir</span> <span class="k">else</span> <span class="nx">srcDir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
<span class="nv">dir = </span><span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">output</span> <span class="k">then</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">baseDir</span> <span class="k">else</span> <span class="nx">srcDir</span>
<span class="nv">jsPath = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">filename</span>
<span class="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">console</span><span class="p">.</span><span class="nx">log</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">console</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="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="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
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">console</span><span class="p">.</span><span class="nx">log</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">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>
<span class="nv">jsl = </span><span class="nx">spawn</span> <span class="s1">&#39;jsl&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;-nologo&#39;</span><span class="p">,</span> <span class="s1">&#39;-stdin&#39;</span><span class="p">,</span> <span class="s1">&#39;-conf&#39;</span><span class="p">,</span> <span class="nx">conf</span><span class="p">]</span>
<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>
@@ -129,20 +136,26 @@ any errors or warnings that arise.</p> </td> <td class="
<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">console</span><span class="p">.</span><span class="nx">log</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-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
<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">ALL_SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</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>
<span class="k">if</span> <span class="nx">opts</span><span class="p">[</span><span class="s1">&#39;no-wrap&#39;</span><span class="p">]</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">warn</span> <span class="s1">&#39;--no-wrap is deprecated; please use --bare instead.&#39;</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="o">or</span> <span class="nx">opts</span><span class="p">[</span><span class="s1">&#39;no-wrap&#39;</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>Print the <code>--help</code> usage message and exit. Deprecated switches are not
<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
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>
<span class="nx">args</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">args</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">&#39;--nodejs&#39;</span><span class="p">),</span> <span class="mi">2</span>
<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
shown.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">usage = </span><span class="o">-&gt;</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</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-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#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">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">&quot;CoffeeScript version #{CoffeeScript.VERSION}&quot;</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="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

@@ -69,8 +69,8 @@ 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 Body 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;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 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>
<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>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
@@ -99,7 +99,6 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
<span class="nx">ObjAssignable</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Identifier&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;AlphaNumeric&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;Parenthetical&#39;</span>
<span class="nx">o</span> <span class="s1">&#39;ThisProperty&#39;</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>A return statement from a function body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Return</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;RETURN Expression&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Return</span> <span class="nx">$2</span>
@@ -186,10 +185,8 @@ and optional references to the superclass.</p> </td> <td
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-35">&#182;</a> </div> <p>Ordinary function invocation, or a chained series of calls.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Invocation</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Value OptFuncExist Arguments&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Call</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;Invocation OptFuncExist Arguments&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Call</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;SUPER&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
<span class="k">new</span> <span class="nx">Call</span> <span class="s1">&#39;super&#39;</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Splat</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;arguments&#39;</span><span class="p">]</span>
<span class="nx">o</span> <span class="s1">&#39;SUPER Arguments&#39;</span><span class="p">,</span> <span class="o">-&gt;</span>
<span class="k">new</span> <span class="nx">Call</span> <span class="s1">&#39;super&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;SUPER&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Call</span> <span class="s1">&#39;super&#39;</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Splat</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">&#39;arguments&#39;</span><span class="p">]</span>
<span class="nx">o</span> <span class="s1">&#39;SUPER Arguments&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">Call</span> <span class="s1">&#39;super&#39;</span><span class="p">,</span> <span class="nx">$2</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-36">&#182;</a> </div> <p>An optional existence check on a function.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">OptFuncExist</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="kc">no</span>
<span class="nx">o</span> <span class="s1">&#39;FUNC_EXIST&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="kc">yes</span>
@@ -263,19 +260,19 @@ or postfix, with a single expression. There is no do..while.</p> </t
<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>
<span class="nx">o</span> <span class="s1">&#39;Statement ForBody&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s1">&#39;Expression ForBody&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s1">&#39;ForBody Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">vars</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nx">o</span> <span class="s1">&#39;Statement ForBody&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;Expression ForBody&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;ForBody Block&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nx">For</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
<span class="p">]</span>
<span class="nx">ForBody</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;FOR Range&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">source</span><span class="o">:</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">$2</span><span class="p">),</span> <span class="nx">vars</span><span class="o">:</span> <span class="p">[]</span>
<span class="nx">o</span> <span class="s1">&#39;ForStart ForSource&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nv">$2.raw = </span><span class="nx">$1</span><span class="p">.</span><span class="nx">raw</span><span class="p">;</span> <span class="nv">$2.vars = </span><span class="nx">$1</span><span class="p">;</span> <span class="nx">$2</span>
<span class="nx">o</span> <span class="s1">&#39;FOR Range&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nx">source</span><span class="o">:</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">$2</span><span class="p">)</span>
<span class="nx">o</span> <span class="s1">&#39;ForStart ForSource&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nv">$2.own = </span><span class="nx">$1</span><span class="p">.</span><span class="nx">own</span><span class="p">;</span> <span class="nv">$2.name = </span><span class="nx">$1</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="nv">$2.index = </span><span class="nx">$1</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="nx">$2</span>
<span class="p">]</span>
<span class="nx">ForStart</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;FOR ForVariables&#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;FOR ALL ForVariables&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nv">$3.raw = </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$3</span>
<span class="nx">o</span> <span class="s1">&#39;FOR OWN ForVariables&#39;</span><span class="p">,</span> <span class="o">-&gt;</span> <span class="nv">$3.own = </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$3</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">&#182;</a> </div> <p>An array of all accepted values for a variable inside the loop.
This enables support for pattern matching.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForValue</span><span class="o">:</span> <span class="p">[</span>
<span class="nx">o</span> <span class="s1">&#39;Identifier&#39;</span>
@@ -314,17 +311,14 @@ in fixed-size increments.</p> </td> <td class="code">
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">&#182;</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
if-related rules are broken up along these lines in order to avoid
ambiguity.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="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="nx">o</span> <span class="s1">&#39;UNLESS 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">invert</span><span class="o">:</span> <span class="kc">true</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="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">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">statement</span><span class="o">:</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s1">&#39;Statement POST_UNLESS 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">statement</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</span>
<span class="nx">o</span> <span class="s1">&#39;Expression POST_UNLESS 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">statement</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</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="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
@@ -382,13 +376,13 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
<span class="p">[</span><span class="s1">&#39;nonassoc&#39;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;right&#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;COMPOUND_ASSIGN&#39;</span><span class="p">,</span> <span class="s1">&#39;RETURN&#39;</span><span class="p">,</span> <span class="s1">&#39;THROW&#39;</span><span class="p">,</span> <span class="s1">&#39;EXTENDS&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;right&#39;</span><span class="p">,</span> <span class="s1">&#39;FORIN&#39;</span><span class="p">,</span> <span class="s1">&#39;FOROF&#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="p">[</span><span class="s1">&#39;right&#39;</span><span class="p">,</span> <span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#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;UNTIL&#39;</span><span class="p">,</span> <span class="s1">&#39;LOOP&#39;</span><span class="p">,</span> <span class="s1">&#39;SUPER&#39;</span><span class="p">,</span> <span class="s1">&#39;CLASS&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;right&#39;</span><span class="p">,</span> <span class="s1">&#39;POST_IF&#39;</span><span class="p">,</span> <span class="s1">&#39;POST_UNLESS&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;right&#39;</span><span class="p">,</span> <span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;FOR&#39;</span><span class="p">,</span> <span class="s1">&#39;DO&#39;</span><span class="p">,</span> <span class="s1">&#39;WHILE&#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;SUPER&#39;</span><span class="p">,</span> <span class="s1">&#39;CLASS&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;right&#39;</span><span class="p">,</span> <span class="s1">&#39;POST_IF&#39;</span><span class="p">]</span>
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">&#182;</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">&#182;</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
terminals (every symbol which does not appear as the name of a rule above)
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tokens = </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">all</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">alternatives</span> <span class="k">of</span> <span class="nx">grammar</span>
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">alternatives</span> <span class="k">of</span> <span class="nx">grammar</span>
<span class="nx">grammar</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="k">for</span> <span class="nx">alt</span> <span class="k">in</span> <span class="nx">alternatives</span>
<span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">alt</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">split</span> <span class="s1">&#39; &#39;</span>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span> <span class="nx">unless</span> <span class="nx">grammar</span><span class="p">[</span><span class="nx">token</span><span class="p">]</span>

View File

@@ -4,14 +4,15 @@ arrays, count characters, that sort of thing.</p> </td>
<span class="nx">literal</span> <span class="o">is</span> <span class="nx">string</span><span class="p">.</span><span class="nx">substr</span> <span class="nx">start</span><span class="p">,</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</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>Peek at the end of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.ends = </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">back</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">len = </span><span class="nx">literal</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">literal</span> <span class="o">is</span> <span class="nx">string</span><span class="p">.</span><span class="nx">substr</span> <span class="nx">string</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">len</span> <span class="o">-</span> <span class="p">(</span><span class="nx">back</span> <span class="o">or</span> <span class="mi">0</span><span class="p">),</span> <span class="nx">len</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>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.compact = </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Count the number of occurrences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.count = </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Count the number of occurrences of a string in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.count = </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">substr</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">num = pos = </span><span class="mi">0</span>
<span class="nx">num</span><span class="o">++</span> <span class="k">while</span> <span class="nv">pos = </span><span class="mi">1</span> <span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span>
<span class="k">return</span> <span class="mi">1</span><span class="o">/</span><span class="mi">0</span> <span class="nx">unless</span> <span class="nx">substr</span><span class="p">.</span><span class="nx">length</span>
<span class="nx">num</span><span class="o">++</span> <span class="k">while</span> <span class="nv">pos = </span><span class="mi">1</span> <span class="o">+</span> <span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">substr</span><span class="p">,</span> <span class="nx">pos</span>
<span class="nx">num</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>Merge objects, returning a fresh copy with attributes from both sides.
Used every time <code>Base#compile</code> is called, to allow properties in the
options hash to propagate down the tree without polluting other branches.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.merge = </span><span class="p">(</span><span class="nx">options</span><span class="p">,</span> <span class="nx">overrides</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">extend</span> <span class="p">(</span><span class="nx">extend</span> <span class="p">{},</span> <span class="nx">options</span><span class="p">),</span> <span class="nx">overrides</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>Extend a source object with the properties of another object (shallow copy).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">extend = exports.extend = </span><span class="p">(</span><span class="nx">object</span><span class="p">,</span> <span class="nx">properties</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">for</span> <span class="nx">all</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span>
<span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span>
<span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">val</span>
<span class="nx">object</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>Return a flattened version of an array.
Handy for getting a list of <code>children</code> from the nodes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.flatten = flatten = </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-&gt;</span>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -14,12 +14,17 @@ option) list, and all subsequent arguments are left unparsed.</p> </
<p>Along with an an optional banner for the usage help.</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">rules</span><span class="p">,</span> <span class="nx">@banner</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="vi">@rules = </span><span class="nx">buildRules</span> <span class="nx">rules</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>Parse the list of arguments, populating an <code>options</code> object with all of the
specified options, and returning it. <code>options.arguments</code> will be an array
containing the remaining non-option arguments. This is a simpler API than
many option parsers that allow you to attach callback actions for every
flag. Instead, you're responsible for interpreting the options object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">parse</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">options = </span><span class="nx">arguments</span><span class="o">:</span> <span class="p">[]</span>
containing the remaining non-option arguments. <code>options.literals</code> will be
an array of options that are meant to be passed through directly to the
executing script. This is a simpler API than many option parsers that allow
you to attach callback actions for every flag. Instead, you're responsible
for interpreting the options object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">parse</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">options = </span><span class="nx">arguments</span><span class="o">:</span> <span class="p">[],</span> <span class="nx">literals</span><span class="o">:</span> <span class="p">[]</span>
<span class="nv">args = </span><span class="nx">normalizeArguments</span> <span class="nx">args</span>
<span class="k">for</span> <span class="nx">arg</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">args</span>
<span class="k">if</span> <span class="nx">arg</span> <span class="o">is</span> <span class="s1">&#39;--&#39;</span>
<span class="nv">options.literals = </span><span class="nx">args</span><span class="p">[(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)..]</span>
<span class="k">break</span>
<span class="nv">isOption = </span><span class="o">!!</span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LONG_FLAG</span><span class="p">)</span> <span class="o">or</span> <span class="nx">arg</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SHORT_FLAG</span><span class="p">))</span>
<span class="nv">matchedRule = </span><span class="kc">no</span>
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>

View File

@@ -5,15 +5,16 @@ 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>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-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#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></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.
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">console</span><span class="p">.</span><span class="nx">error</span> <span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</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>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>
<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>
<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>

View File

@@ -71,13 +71,13 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
<span class="nv">start = </span><span class="kc">null</span>
<span class="nv">startIndent = </span><span class="mi">0</span>
<span class="nv">condition = </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="p">{(</span><span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">:</span> <span class="nx">one</span><span class="p">,</span> <span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">:</span> <span class="nx">two</span><span class="p">,</span> <span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">3</span><span class="p">)</span><span class="o">:</span> <span class="nx">three</span><span class="p">}</span> <span class="o">=</span> <span class="nx">@tokens</span>
<span class="p">[</span><span class="nx">one</span><span class="p">,</span> <span class="nx">two</span><span class="p">,</span> <span class="nx">three</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">..</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">]</span>
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="s1">&#39;HERECOMMENT&#39;</span> <span class="o">is</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="p">[</span><span class="nx">tag</span><span class="p">]</span> <span class="o">=</span> <span class="nx">token</span>
<span class="p">(</span><span class="nx">tag</span> <span class="k">in</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="o">and</span>
<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="s1">&#39;(&#39;</span><span class="p">])</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="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>
@@ -87,17 +87,10 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
<span class="nv">start = </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">&#39;:&#39;</span> <span class="o">and</span>
<span class="p">((</span><span class="nv">ago2 = </span><span class="nx">@tag</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;:&#39;</span> <span class="o">or</span>
<span class="p">(</span><span class="nv">ago1 = </span><span class="nx">@tag</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="o">and</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">start</span><span class="p">[</span><span class="mi">1</span><span class="p">]</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="o">or</span>
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;{&#39;</span><span class="p">)</span>
<span class="p">((</span><span class="nv">ago = </span><span class="nx">@tag</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;:&#39;</span> <span class="o">or</span> <span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;{&#39;</span><span class="p">)</span>
<span class="nx">stack</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="nv">idx = </span><span class="k">if</span> <span class="nx">ago1</span> <span class="o">is</span> <span class="s1">&#39;)&#39;</span>
<span class="nx">start</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">ago2</span> <span class="o">is</span> <span class="s1">&#39;@&#39;</span>
<span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span>
<span class="k">else</span>
<span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nx">idx</span> <span class="o">-=</span> <span class="mi">2</span> <span class="k">if</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">idx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;HERECOMMENT&#39;</span>
<span class="nv">idx = </span> <span class="k">if</span> <span class="nx">ago</span> <span class="o">is</span> <span class="s1">&#39;@&#39;</span> <span class="k">then</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span> <span class="k">else</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span>
<span class="nx">idx</span> <span class="o">-=</span> <span class="mi">2</span> <span class="k">while</span> <span class="nx">@tag</span><span class="p">(</span><span class="nx">idx</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;HERECOMMENT&#39;</span>
<span class="nv">value = </span><span class="k">new</span> <span class="nb">String</span><span class="p">(</span><span class="s1">&#39;{&#39;</span><span class="p">)</span>
<span class="nv">value.generated = </span><span class="kc">yes</span>
<span class="nv">tok = </span><span class="p">[</span><span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
@@ -113,22 +106,22 @@ deal with them.</p> </td> <td class="code">
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">idx</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;CALL_END&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="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="nv">tag = </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nv">noCall = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;CLASS&#39;</span><span class="p">,</span> <span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#39;</span><span class="p">]</span>
<span class="p">{(</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">:</span> <span class="nx">prev</span><span class="p">,</span> <span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">:</span> <span class="nx">next</span><span class="p">}</span> <span class="o">=</span> <span class="nx">tokens</span>
<span class="nv">noCall = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;CLASS&#39;</span><span class="p">,</span> <span class="s1">&#39;IF&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">current</span><span class="p">,</span> <span class="nx">next</span><span class="p">]</span> <span class="o">=</span> <span class="nx">tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">..</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
<span class="nv">callObject = </span><span class="o">not</span> <span class="nx">noCall</span> <span class="o">and</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">next</span> <span class="o">and</span> <span class="nx">next</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">next</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">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="nx">IMPLICIT_FUNC</span>
<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">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="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>
<span class="nx">tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;CALL_START&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="nx">@detectEnd</span> <span class="nx">i</span> <span class="o">+</span> <span class="p">(</span><span class="k">if</span> <span class="nx">callObject</span> <span class="k">then</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">1</span><span class="p">),</span> <span class="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="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">seenSingle</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</span>
<span class="nx">@detectEnd</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</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="p">[</span><span class="nx">tag</span><span class="p">]</span> <span class="o">=</span> <span class="nx">token</span>
<span class="nv">seenSingle = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#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="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">seenSingle</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</span>
<span class="nv">seenSingle = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">]</span>
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="nx">tag</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">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;OUTDENT&#39;</span>
<span class="o">not</span> <span class="nx">token</span><span class="p">.</span><span class="nx">generated</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">isnt</span> <span class="s1">&#39;,&#39;</span> <span class="o">and</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_END</span> <span class="o">and</span>
<span class="p">(</span><span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">&#39;INDENT&#39;</span> <span class="o">or</span>
@@ -170,7 +163,7 @@ but we need to make sure it's balanced.</p> </td> <td cl
different precedence.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">tagPostfixConditionals</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nv">condition = </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">token</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;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">]</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="o">-&gt;</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#39;</span><span class="p">]</span>
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">&#39;IF&#39;</span>
<span class="nv">original = </span><span class="nx">token</span>
<span class="nx">@detectEnd</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">condition</span><span class="p">,</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">original</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;POST_&#39;</span> <span class="o">+</span> <span class="nx">original</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">&#39;INDENT&#39;</span>
@@ -186,7 +179,7 @@ the course of the token stream.</p> </td> <td class="cod
<span class="nx">openLine</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">=</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span><span class="o">++</span> <span class="o">is</span> <span class="mi">0</span>
<span class="k">else</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">close</span> <span class="o">and</span> <span class="o">--</span><span class="nx">levels</span><span class="p">[</span><span class="nx">open</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span>
<span class="k">throw</span> <span class="nb">Error</span> <span class="s2">&quot;too many #{token[1]} on line #{token[2] + 1}&quot;</span>
<span class="k">for</span> <span class="nx">all</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">level</span> <span class="k">of</span> <span class="nx">levels</span> <span class="k">when</span> <span class="nx">level</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="k">for</span> <span class="nx">open</span><span class="p">,</span> <span class="nx">level</span> <span class="k">of</span> <span class="nx">levels</span> <span class="k">when</span> <span class="nx">level</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="k">throw</span> <span class="nb">Error</span> <span class="s2">&quot;unclosed #{ open } on line #{openLine[open] + 1}&quot;</span>
<span class="k">this</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>We'd like to support syntax like this:</p>
@@ -209,7 +202,7 @@ rewriting.</li>
</ol> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">rewriteClosingParens</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nv">stack = </span><span class="p">[]</span>
<span class="nv">debt = </span><span class="p">{}</span>
<span class="nx">debt</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">for</span> <span class="nx">all</span> <span class="nx">key</span> <span class="k">of</span> <span class="nx">INVERSES</span>
<span class="nx">debt</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">for</span> <span class="nx">key</span> <span class="k">of</span> <span class="nx">INVERSES</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="nx">token</span>
@@ -247,11 +240,11 @@ look things up from either end.</p> </td> <td class="cod
<span class="nx">EXPRESSION_START</span><span class="p">.</span><span class="nx">push</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">rite</span><span class="p">]</span> <span class="o">=</span> <span class="nx">left</span>
<span class="nx">EXPRESSION_END</span> <span class="p">.</span><span class="nx">push</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">left</span><span class="p">]</span> <span class="o">=</span> <span class="nx">rite</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>Tokens that indicate the close of a clause of an expression.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_CLOSE = </span><span class="p">[</span><span class="s1">&#39;CATCH&#39;</span><span class="p">,</span> <span class="s1">&#39;WHEN&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;FINALLY&#39;</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_FUNC = </span><span class="p">[</span><span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;SUPER&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;CALL_END&#39;</span><span class="p">,</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="s1">&#39;INDEX_END&#39;</span><span class="p">,</span> <span class="s1">&#39;@&#39;</span><span class="p">,</span> <span class="s1">&#39;THIS&#39;</span><span class="p">]</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>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_CALL = </span><span class="p">[</span>
<span class="s1">&#39;IDENTIFIER&#39;</span><span class="p">,</span> <span class="s1">&#39;NUMBER&#39;</span><span class="p">,</span> <span class="s1">&#39;STRING&#39;</span><span class="p">,</span> <span class="s1">&#39;JS&#39;</span><span class="p">,</span> <span class="s1">&#39;REGEX&#39;</span><span class="p">,</span> <span class="s1">&#39;NEW&#39;</span><span class="p">,</span> <span class="s1">&#39;PARAM_START&#39;</span><span class="p">,</span> <span class="s1">&#39;CLASS&#39;</span>
<span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;UNLESS&#39;</span><span class="p">,</span> <span class="s1">&#39;TRY&#39;</span><span class="p">,</span> <span class="s1">&#39;SWITCH&#39;</span><span class="p">,</span> <span class="s1">&#39;THIS&#39;</span><span class="p">,</span> <span class="s1">&#39;BOOL&#39;</span><span class="p">,</span> <span class="s1">&#39;UNARY&#39;</span><span class="p">,</span>
<span class="s1">&#39;IF&#39;</span><span class="p">,</span> <span class="s1">&#39;TRY&#39;</span><span class="p">,</span> <span class="s1">&#39;SWITCH&#39;</span><span class="p">,</span> <span class="s1">&#39;THIS&#39;</span><span class="p">,</span> <span class="s1">&#39;BOOL&#39;</span><span class="p">,</span> <span class="s1">&#39;UNARY&#39;</span><span class="p">,</span> <span class="s1">&#39;SUPER&#39;</span>
<span class="s1">&#39;@&#39;</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">,</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;--&#39;</span><span class="p">,</span> <span class="s1">&#39;++&#39;</span>
<span class="p">]</span>
<span class="nv">IMPLICIT_UNSPACED_CALL = </span><span class="p">[</span><span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;-&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK = </span><span class="p">[</span><span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;,&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END = </span><span class="p">[</span><span class="s1">&#39;POST_IF&#39;</span><span class="p">,</span> <span class="s1">&#39;POST_UNLESS&#39;</span><span class="p">,</span> <span class="s1">&#39;FOR&#39;</span><span class="p">,</span> <span class="s1">&#39;WHILE&#39;</span><span class="p">,</span> <span class="s1">&#39;UNTIL&#39;</span><span class="p">,</span> <span class="s1">&#39;WHEN&#39;</span><span class="p">,</span> <span class="s1">&#39;BY&#39;</span><span class="p">,</span> <span class="s1">&#39;LOOP&#39;</span><span class="p">,</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
<span class="nv">IMPLICIT_UNSPACED_CALL = </span><span class="p">[</span><span class="s1">&#39;+&#39;</span><span class="p">,</span> <span class="s1">&#39;-&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK = </span><span class="p">[</span><span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span> <span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;,&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END = </span><span class="p">[</span><span class="s1">&#39;POST_IF&#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;UNTIL&#39;</span><span class="p">,</span> <span class="s1">&#39;WHEN&#39;</span><span class="p">,</span> <span class="s1">&#39;BY&#39;</span><span class="p">,</span> <span class="s1">&#39;LOOP&#39;</span><span class="p">,</span> <span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
The grammar can't disambiguate them, so we insert the implicit indentation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SINGLE_LINERS = </span><span class="p">[</span><span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;-&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;=&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;TRY&#39;</span><span class="p">,</span> <span class="s1">&#39;FINALLY&#39;</span><span class="p">,</span> <span class="s1">&#39;THEN&#39;</span><span class="p">]</span>
<span class="nv">SINGLE_CLOSERS = </span><span class="p">[</span><span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;CATCH&#39;</span><span class="p">,</span> <span class="s1">&#39;FINALLY&#39;</span><span class="p">,</span> <span class="s1">&#39;ELSE&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;LEADING_WHEN&#39;</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>Tokens that end a line.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LINEBREAKS = </span><span class="p">[</span><span class="s1">&#39;TERMINATOR&#39;</span><span class="p">,</span> <span class="s1">&#39;INDENT&#39;</span><span class="p">,</span> <span class="s1">&#39;OUTDENT&#39;</span><span class="p">]</span>

View File

@@ -11,58 +11,44 @@ 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>
<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="k">if</span> <span class="nx">@parent</span>
<span class="vi">@garbage = </span><span class="nx">@parent</span><span class="p">.</span><span class="nx">garbage</span>
<span class="k">else</span>
<span class="vi">@garbage = </span><span class="p">[]</span>
<span class="nv">Scope.root = </span><span class="k">this</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="o">-&gt;</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>
<span class="k">return</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">add</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="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">immediate</span>
<span class="k">if</span> <span class="k">typeof</span> <span class="p">(</span><span class="nv">pos = </span><span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">])</span> <span class="o">is</span> <span class="s1">&#39;number&#39;</span>
<span class="nx">@variables</span><span class="p">[</span><span class="nx">pos</span><span class="p">].</span><span class="nv">type = </span><span class="nx">type</span>
<span class="k">else</span>
<span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variables</span><span class="p">.</span><span class="nx">push</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="o">-</span> <span class="mi">1</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>Create a new garbage level</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">startLevel</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@garbage</span><span class="p">.</span><span class="nx">push</span> <span class="p">[]</span>
<span class="k">this</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>Return to the previous garbage level and erase referenced temporary
variables in current level from scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">endLevel</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">&#39;reuse&#39;</span> <span class="k">for</span> <span class="nx">name</span> <span class="k">in</span> <span class="nx">@garbage</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">when</span> <span class="nx">@type</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">is</span> <span class="s1">&#39;var&#39;</span>
<span class="k">this</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>Look up a variable name in lexical scope, and declare it if it does not
<span class="nx">@positions</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variables</span><span class="p">.</span><span class="nx">push</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="o">-</span> <span class="mi">1</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>Look up a variable name in lexical scope, and declare it if it does not
already exist.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">find</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">true</span> <span class="k">if</span> <span class="nx">@check</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">options</span>
<span class="k">return</span> <span class="kc">yes</span> <span class="k">if</span> <span class="nx">@check</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">options</span>
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">&#39;var&#39;</span>
<span class="kc">false</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>Test variables and return <code>true</code> the first time <code>fn(v)</code> returns <code>true</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">any</span><span class="o">:</span> <span class="p">(</span><span class="nx">fn</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">return</span> <span class="kc">yes</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">fn</span> <span class="nx">v</span>
<span class="kc">no</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>Reserve a variable name as originating from a function parameter for this
<span class="kc">no</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>Reserve a variable name as originating from a function parameter for this
scope. No <code>var</code> required for internal references.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">parameter</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">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">&#39;param&#39;</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>Just check to see if a variable has already been declared, without reserving,
<span class="k">return</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="nx">@parent</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</span><span class="p">,</span> <span class="kc">yes</span>
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">&#39;param&#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>Just check to see if a variable has already been declared, without reserving,
walks up to the root scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">check</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">immediate</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">found = </span><span class="o">!!</span><span class="nx">@type</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
<span class="k">return</span> <span class="nx">found</span> <span class="k">if</span> <span class="nx">found</span> <span class="o">or</span> <span class="nx">immediate</span>
<span class="o">!!</span><span class="nx">@parent</span><span class="o">?</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</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>Generate a temporary variable name at the given index.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">temporary</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="o">!!</span><span class="nx">@parent</span><span class="o">?</span><span class="p">.</span><span class="nx">check</span> <span class="nx">name</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>Generate a temporary variable name at the given index.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">temporary</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="k">if</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span>
<span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">index</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">then</span> <span class="nx">index</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span>
<span class="k">else</span>
<span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">name</span><span class="p">,</span> <span class="mi">36</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span> <span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">&#39;a&#39;</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>Gets the type of a variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">type</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">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span> <span class="o">is</span> <span class="nx">name</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span>
<span class="kc">null</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>If we need to store an intermediate result, find an available name for a
<span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="nb">parseInt</span> <span class="nx">name</span><span class="p">,</span> <span class="mi">36</span><span class="p">).</span><span class="nx">toString</span><span class="p">(</span><span class="mi">36</span><span class="p">).</span><span class="nx">replace</span> <span class="sr">/\d/g</span><span class="p">,</span> <span class="s1">&#39;a&#39;</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>Gets the type of a variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">type</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">return</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span> <span class="o">is</span> <span class="nx">name</span>
<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="o">and</span> <span class="nx">@type</span><span class="p">(</span><span class="nx">temp</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">&#39;reuse&#39;</span>
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">&#39;var&#39;</span>
<span class="nx">last</span><span class="p">(</span><span class="nx">@garbage</span><span class="p">)</span><span class="o">?</span><span class="p">.</span><span class="nx">push</span> <span class="nx">temp</span>
<span class="nx">temp</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>Ensure that an assignment is made at the top of this scope
<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">@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>
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">assigned</span><span class="o">:</span> <span class="kc">true</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>Does this scope reference any variables that need to be declared in the
given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasDeclarations</span><span class="o">:</span> <span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">v</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;var&#39;</span><span class="p">,</span> <span class="s1">&#39;reuse&#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>Does this scope reference any assignments that need to be declared at the
top of the given function body?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasAssignments</span><span class="o">:</span> <span class="p">(</span><span class="nx">body</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nx">body</span> <span class="o">is</span> <span class="nx">@expressions</span> <span class="o">and</span> <span class="nx">@any</span> <span class="p">(</span><span class="nx">v</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">assigned</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>Return the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">declaredVariables</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nv">usr = </span><span class="p">[]</span>
<span class="nv">tmp = </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="k">in</span> <span class="p">[</span><span class="s1">&#39;var&#39;</span><span class="p">,</span> <span class="s1">&#39;reuse&#39;</span><span class="p">]</span>
<span class="p">(</span><span class="k">if</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</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="k">then</span> <span class="nx">tmp</span> <span class="k">else</span> <span class="nx">usr</span><span class="p">).</span><span class="nx">push</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">usr</span><span class="p">.</span><span class="nx">sort</span><span class="p">().</span><span class="nx">concat</span> <span class="nx">tmp</span><span class="p">.</span><span class="nx">sort</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>Return the list of assignments that are supposed to be made at the top
<span class="nx">@add</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">assigned</span><span class="o">:</span> <span class="kc">true</span>
<span class="vi">@hasAssignments = </span><span class="kc">yes</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>Does this scope have any declared variables?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasDeclarations</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="o">!!</span><span class="nx">@declaredVariables</span><span class="p">().</span><span class="nx">length</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 the list of variables first declared in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">declaredVariables</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nv">realVars = </span><span class="p">[]</span>
<span class="nv">tempVars = </span><span class="p">[]</span>
<span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">&#39;var&#39;</span>
<span class="p">(</span><span class="k">if</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</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="k">then</span> <span class="nx">tempVars</span> <span class="k">else</span> <span class="nx">realVars</span><span class="p">).</span><span class="nx">push</span> <span class="nx">v</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">realVars</span><span class="p">.</span><span class="nx">sort</span><span class="p">().</span><span class="nx">concat</span> <span class="nx">tempVars</span><span class="p">.</span><span class="nx">sort</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 the list of assignments that are supposed to be made at the top
of this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assignedVariables</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="p">(</span><span class="s2">&quot;#{v.name} = #{v.type.value}&quot;</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">assigned</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>Compile the JavaScript for all of the variable declarations in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compiledDeclarations</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@declaredVariables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</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>Compile the JavaScript for all of the variable assignments in this scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compiledAssignments</span><span class="o">:</span> <span class="o">-&gt;</span>
<span class="nx">@assignedVariables</span><span class="p">().</span><span class="nx">join</span> <span class="s1">&#39;, &#39;</span>
<span class="s2">&quot;#{v.name} = #{v.type.value}&quot;</span> <span class="k">for</span> <span class="nx">v</span> <span class="k">in</span> <span class="nx">@variables</span> <span class="k">when</span> <span class="nx">v</span><span class="p">.</span><span class="nx">type</span><span class="p">.</span><span class="nx">assigned</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,6 @@
var food, lunch, pos, roid, roid2, _i, _j, _len, _len2, _len3, _ref;
var food, _i, _len, _ref;
_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
food = _ref[_i];
lunch = eat(food);
}
for (pos = 0, _len2 = asteroids.length; pos < _len2; pos++) {
roid = asteroids[pos];
for (_j = 0, _len3 = asteroids.length; _j < _len3; _j++) {
roid2 = asteroids[_j];
if (roid !== roid2) {
if (roid.overlaps(roid2)) {
roid.explode();
}
}
}
eat(food);
}

View File

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

View File

@@ -7,7 +7,7 @@ var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, par
child.__super__ = parent.prototype;
return child;
};
Animal = function() {
Animal = (function() {
function Animal(name) {
this.name = name;
}
@@ -15,8 +15,8 @@ Animal = function() {
return alert(this.name + " moved " + meters + "m.");
};
return Animal;
}();
Snake = function() {
})();
Snake = (function() {
function Snake() {
Snake.__super__.constructor.apply(this, arguments);
}
@@ -26,8 +26,8 @@ Snake = function() {
return Snake.__super__.move.call(this, 5);
};
return Snake;
}();
Horse = function() {
})();
Horse = (function() {
function Horse() {
Horse.__super__.constructor.apply(this, arguments);
}
@@ -37,7 +37,7 @@ Horse = function() {
return Horse.__super__.move.call(this, 45);
};
return Horse;
}();
})();
sam = new Snake("Sammy the Python");
tom = new Horse("Tommy the Palomino");
sam.move();

View File

@@ -1,3 +1,3 @@
var cholesterol, healthy;
cholesterol = 127;
healthy = 200 > cholesterol && cholesterol > 60;
healthy = (200 > cholesterol && cholesterol > 60);

10
documentation/js/do.js Normal file
View File

@@ -0,0 +1,10 @@
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);
}

View File

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

View File

@@ -1,10 +1,9 @@
var globals, name, _results;
var __hasProp = Object.prototype.hasOwnProperty;
globals = (function() {
var globals, name;
globals = ((function() {
var _results;
_results = [];
for (name in window) {
if (!__hasProp.call(window, name)) continue;
_results.push(name);
}
return _results;
}()).slice(0, 10);
})()).slice(0, 10);

View File

@@ -1,7 +1,7 @@
alert(function() {
alert((function() {
try {
return nonexistent / void 0;
} catch (error) {
return "And the error is ... " + error;
}
}());
})());

View File

@@ -1,16 +1,15 @@
var age, ages, child, yearsOld, _results;
var __hasProp = Object.prototype.hasOwnProperty;
var age, ages, child, yearsOld;
yearsOld = {
max: 10,
ida: 9,
tim: 11
};
ages = function() {
ages = (function() {
var _results;
_results = [];
for (child in yearsOld) {
if (!__hasProp.call(yearsOld, child)) continue;
age = yearsOld[child];
_results.push(child + " is " + age);
}
return _results;
}();
})();

View File

@@ -1,10 +1,10 @@
var kids, matrix, singers, song;
var bitlist, kids, singers, song;
song = ["do", "re", "mi", "fa", "so"];
singers = {
Jagger: "Rock",
Elvis: "Roll"
};
matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];
kids = {
brother: {
name: "Max",

View File

@@ -1,4 +1,4 @@
var cubes, list, math, num, number, opposite, race, square, _i, _len, _results;
var cubes, list, math, num, number, opposite, race, square;
var __slice = Array.prototype.slice;
number = 42;
opposite = true;
@@ -25,10 +25,11 @@ if (typeof elvis != "undefined" && elvis !== null) {
alert("I knew it!");
}
cubes = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
num = list[_i];
_results.push(math.cube(num));
}
return _results;
}());
})();

View File

@@ -1,8 +1,9 @@
var countdown, num, _results;
var countdown, num;
countdown = (function() {
var _results;
_results = [];
for (num = 10; num >= 1; num--) {
_results.push(num);
}
return _results;
}());
})();

View File

@@ -0,0 +1,4 @@
var copy, middle, numbers;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
copy = numbers.slice(0, numbers.length);
middle = copy.slice(3, 7);

View File

@@ -9,7 +9,7 @@ awardMedals = function() {
return rest = others;
};
contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
awardMedals.apply(awardMedals, contenders);
awardMedals.apply(null, contenders);
alert("Gold: " + gold);
alert("Silver: " + silver);
alert("The Field: " + rest);

View File

@@ -0,0 +1,3 @@
var numbers, _ref;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;

View File

@@ -1,17 +1,18 @@
var lyrics, num, _results;
var lyrics, num;
if (this.studyingEconomics) {
while (supply > demand) {
buy();
}
while (supply <= demand) {
while (!(supply > demand)) {
sell();
}
}
num = 6;
lyrics = function() {
lyrics = (function() {
var _results;
_results = [];
while (num -= 1) {
_results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
}
return _results;
}();
})();

6240
documentation/vendor/jquery-1.4.2.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -85,7 +85,7 @@ _.each = (obj, iterator, context) ->
else if _.isNumber obj.length
iterator.call context, obj[i], i, obj for i in [0...obj.length]
else
iterator.call context, val, key, obj for key, val of obj
iterator.call context, val, key, obj for own key, val of obj
catch e
throw e if e isnt breaker
obj
@@ -176,8 +176,7 @@ _.some = (obj, iterator, context) ->
# based on `===`.
_.include = (obj, target) ->
return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
for key, val of obj
return true if val is target
return true for own key, val of obj when val is target
false
@@ -486,14 +485,14 @@ _.isEqual = (a, b) ->
# Different object sizes?
return false if aKeys.length isnt bKeys.length
# Recursive comparison of contents.
return false for all key, val of a when !(key of b) or !_.isEqual(val, b[key])
return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
true
# Is a given array or object empty?
_.isEmpty = (obj) ->
return obj.length is 0 if _.isArray(obj) or _.isString(obj)
return false for key of obj when hasOwnProperty.call(obj, key)
return false for own key of obj
true
@@ -654,7 +653,7 @@ addToWrapper = (name, func) ->
result func.apply(_, args), this._chain
# Add all of the Underscore functions to the wrapper object.
# Add all ofthe Underscore functions to the wrapper object.
_.mixin _

File diff suppressed because one or more lines are too long

1352
index.html

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
(function() {
var Lexer, compile, fs, lexer, parser, path;
var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref;
fs = require('fs');
path = require('path');
Lexer = require('./lexer').Lexer;
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
parser = require('./parser').parser;
if (require.extensions) {
require.extensions['.coffee'] = function(module, filename) {
@@ -15,7 +15,8 @@
return compile(content);
});
}
exports.VERSION = '0.9.5';
exports.VERSION = '1.0.0';
exports.RESERVED = RESERVED;
exports.helpers = require('./helpers');
exports.compile = compile = function(code, options) {
if (options == null) {

View File

@@ -1,23 +1,31 @@
(function() {
var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printTokens, sources, spawn, usage, version, watch, writeJs, _ref;
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;
fs = require('fs');
path = require('path');
util = require('util');
helpers = require('./helpers');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
EventEmitter = require('events').EventEmitter;
helpers.extend(CoffeeScript, new EventEmitter);
printLine = function(line) {
return process.stdout.write(line + '\n');
};
printWarn = function(line) {
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'], ['-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'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
DEPRECATED_SWITCHES = [['--no-wrap', 'compile without the top-level function wrapper']];
ALL_SWITCHES = SWITCHES.concat(DEPRECATED_SWITCHES);
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']];
opts = {};
sources = [];
contents = [];
optionParser = null;
exports.run = function() {
var flags, separator;
parseOptions();
if (opts.nodejs) {
return forkNode();
}
if (opts.help) {
return usage();
}
@@ -36,22 +44,17 @@
if (!sources.length) {
return require('./repl');
}
separator = sources.indexOf('--');
flags = [];
if (separator >= 0) {
flags = sources.splice(separator + 1);
sources.pop();
}
if (opts.run) {
flags = sources.splice(1).concat(flags);
opts.literals = sources.splice(1).concat(opts.literals);
}
process.ARGV = process.argv = flags;
process.ARGV = process.argv = process.argv.slice(0, 2).concat(opts.literals);
return compileScripts();
};
compileScripts = function() {
var _fn, _i, _len, _results;
_fn = function(source) {
var base, compile;
var base, compile, source, _i, _len, _results;
_results = [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
source = sources[_i];
base = path.join(source);
compile = function(source, topLevel) {
return path.exists(source, function(exists) {
@@ -71,21 +74,23 @@
});
} else if (topLevel || path.extname(source) === '.coffee') {
fs.readFile(source, function(err, code) {
return compileScript(source, code.toString(), base);
if (opts.join) {
contents[sources.indexOf(source)] = code.toString();
if (helpers.compact(contents).length === sources.length) {
return compileJoin();
}
} else {
return compileScript(source, code.toString(), base);
}
});
if (opts.watch) {
if (opts.watch && !opts.join) {
return watch(source, base);
}
}
});
});
};
return _results.push(compile(source, true));
};
_results = [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
source = sources[_i];
_fn(source);
_results.push(compile(source, true));
}
return _results;
};
@@ -110,14 +115,14 @@
if (o.tokens) {
return printTokens(CoffeeScript.tokens(t.input));
} else if (o.nodes) {
return console.log(CoffeeScript.nodes(t.input).toString().trim());
return printLine(CoffeeScript.nodes(t.input).toString().trim());
} else if (o.run) {
return CoffeeScript.run(t.input, t.options);
} else {
t.output = CoffeeScript.compile(t.input, t.options);
CoffeeScript.emit('success', task);
if (o.print) {
return console.log(t.output.trim());
return printLine(t.output.trim());
} else if (o.compile) {
return writeJs(t.file, t.output, base);
} else if (o.lint) {
@@ -130,9 +135,9 @@
return;
}
if (o.watch) {
return console.log(err.message);
return printLine(err.message);
}
console.error(err.stack);
printWarn(err.stack);
return process.exit(1);
}
};
@@ -149,6 +154,11 @@
return compileScript(null, code);
});
};
compileJoin = function() {
var code;
code = contents.join('\n');
return compileScript("concatenation", code, "concatenation");
};
watch = function(source, base) {
return fs.watchFile(source, {
persistent: true,
@@ -169,7 +179,7 @@
var baseDir, compile, dir, filename, jsPath, srcDir;
filename = path.basename(source, path.extname(source)) + '.js';
srcDir = path.dirname(source);
baseDir = srcDir.substring(base.length);
baseDir = base === '.' ? srcDir : srcDir.substring(base.length);
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
jsPath = path.join(dir, filename);
compile = function() {
@@ -178,9 +188,9 @@
}
return fs.writeFile(jsPath, js, function(err) {
if (err) {
return console.log(err.message);
return printLine(err.message);
} else if (opts.compile && opts.watch) {
return console.log("Compiled " + source);
return util.log("compiled " + source);
}
});
};
@@ -195,7 +205,7 @@
lint = function(file, js) {
var conf, jsl, printIt;
printIt = function(buffer) {
return console.log(file + ':\t' + buffer.toString().trim());
return printLine(file + ':\t' + buffer.toString().trim());
};
conf = __dirname + '/../extras/jsl.conf';
jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]);
@@ -205,8 +215,9 @@
return jsl.stdin.end();
};
printTokens = function(tokens) {
var strings, tag, token, value, _i, _len, _ref, _results;
strings = function() {
var strings, tag, token, value;
strings = (function() {
var _i, _len, _ref, _results;
_results = [];
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
token = tokens[_i];
@@ -214,33 +225,41 @@
_results.push("[" + tag + " " + value + "]");
}
return _results;
}();
return console.log(strings.join(' '));
})();
return printLine(strings.join(' '));
};
parseOptions = function() {
var o;
optionParser = new optparse.OptionParser(ALL_SWITCHES, BANNER);
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
o = opts = optionParser.parse(process.argv.slice(2));
o.compile || (o.compile = !!o.output);
o.run = !(o.compile || o.print || o.lint);
o.print = !!(o.print || (o.eval || o.stdio && o.compile));
sources = o.arguments;
if (opts['no-wrap']) {
return console.warn('--no-wrap is deprecated; please use --bare instead.');
}
return sources = o.arguments;
};
compileOptions = function(fileName) {
return {
fileName: fileName,
bare: opts.bare || opts['no-wrap']
bare: opts.bare
};
};
forkNode = function() {
var args, nodeArgs;
nodeArgs = opts.nodejs.split(/\s+/);
args = process.argv.slice(1);
args.splice(args.indexOf('--nodejs'), 2);
return spawn(process.execPath, nodeArgs.concat(args), {
cwd: process.cwd(),
env: process.env,
customFds: [0, 1, 2]
});
};
usage = function() {
console.log((new optparse.OptionParser(SWITCHES, BANNER)).help());
printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
return process.exit(0);
};
version = function() {
console.log("CoffeeScript version " + CoffeeScript.VERSION);
printLine("CoffeeScript version " + CoffeeScript.VERSION);
return process.exit(0);
};
}).call(this);

View File

@@ -1,5 +1,5 @@
(function() {
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap, _i, _j, _len, _len2, _ref, _results;
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
Parser = require('jison').Parser;
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
o = function(patternString, action, options) {
@@ -34,10 +34,10 @@
],
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 Body OUTDENT', function() {
return $2;
}), o('INDENT OUTDENT', function() {
o('INDENT OUTDENT', function() {
return new Expressions;
}), o('INDENT Body OUTDENT', function() {
return $2;
})
],
Identifier: [
@@ -78,7 +78,7 @@
return new Assign(new Value($1), $4, 'object');
}), o('Comment')
],
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('Parenthetical'), o('ThisProperty')],
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('ThisProperty')],
Return: [
o('RETURN Expression', function() {
return new Return($2);
@@ -368,30 +368,30 @@
],
For: [
o('Statement ForBody', function() {
return new For($1, $2, $2.vars[0], $2.vars[1]);
return new For($1, $2);
}), o('Expression ForBody', function() {
return new For($1, $2, $2.vars[0], $2.vars[1]);
return new For($1, $2);
}), o('ForBody Block', function() {
return new For($2, $1, $1.vars[0], $1.vars[1]);
return new For($2, $1);
})
],
ForBody: [
o('FOR Range', function() {
return {
source: new Value($2),
vars: []
source: new Value($2)
};
}), o('ForStart ForSource', function() {
$2.raw = $1.raw;
$2.vars = $1;
$2.own = $1.own;
$2.name = $1[0];
$2.index = $1[1];
return $2;
})
],
ForStart: [
o('FOR ForVariables', function() {
return $2;
}), o('FOR ALL ForVariables', function() {
$3.raw = true;
}), o('FOR OWN ForVariables', function() {
$3.own = true;
return $3;
})
],
@@ -474,13 +474,13 @@
],
IfBlock: [
o('IF Expression Block', function() {
return new If($2, $3);
}), o('UNLESS Expression Block', function() {
return new If($2, $3, {
invert: true
type: $1
});
}), o('IfBlock ELSE IF Expression Block', function() {
return $1.addElse(new If($4, $5));
return $1.addElse(new If($4, $5, {
type: $3
}));
}), o('IfBlock ELSE Block', function() {
return $1.addElse($3);
})
@@ -488,22 +488,14 @@
If: [
o('IfBlock'), o('Statement POST_IF Expression', function() {
return new If($3, Expressions.wrap([$1]), {
type: $2,
statement: true
});
}), o('Expression POST_IF Expression', function() {
return new If($3, Expressions.wrap([$1]), {
type: $2,
statement: true
});
}), o('Statement POST_UNLESS Expression', function() {
return new If($3, Expressions.wrap([$1]), {
statement: true,
invert: true
});
}), o('Expression POST_UNLESS Expression', function() {
return new If($3, Expressions.wrap([$1]), {
statement: true,
invert: true
});
})
],
Operation: [
@@ -556,11 +548,12 @@
})
]
};
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF', 'POST_UNLESS']];
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
tokens = [];
for (name in grammar) {
alternatives = grammar[name];
grammar[name] = function() {
grammar[name] = (function() {
var _i, _j, _len, _len2, _ref, _results;
_results = [];
for (_i = 0, _len = alternatives.length; _i < _len; _i++) {
alt = alternatives[_i];
@@ -577,7 +570,7 @@
_results.push(alt);
}
return _results;
}();
})();
}
exports.parser = new Parser({
tokens: tokens.join(' '),

View File

@@ -19,10 +19,13 @@
}
return _results;
};
exports.count = function(string, letter) {
exports.count = function(string, substr) {
var num, pos;
num = pos = 0;
while (pos = 1 + string.indexOf(letter, pos)) {
if (!substr.length) {
return 1 / 0;
}
while (pos = 1 + string.indexOf(substr, pos)) {
num++;
}
return num;

View File

@@ -1,9 +1,7 @@
(function() {
var key, val, _ref;
var __hasProp = Object.prototype.hasOwnProperty;
_ref = require('./coffee-script');
for (key in _ref) {
if (!__hasProp.call(_ref, key)) continue;
val = _ref[key];
exports[key] = val;
}

View File

@@ -8,7 +8,7 @@
};
Rewriter = require('./rewriter').Rewriter;
_ref = require('./helpers'), count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
exports.Lexer = Lexer = function() {
exports.Lexer = Lexer = (function() {
function Lexer() {}
Lexer.prototype.tokenize = function(code, opts) {
var i;
@@ -39,8 +39,8 @@
return 0;
}
input = match[0], id = match[1], colon = match[2];
if (id === 'all' && this.tag() === 'FOR') {
this.token('ALL', id);
if (id === 'own' && this.tag() === 'FOR') {
this.token('OWN', id);
return id.length;
}
forcedIdentifier = colon || (prev = last(this.tokens)) && !prev.spaced && ((_ref = prev[0]) === '.' || _ref === '?.' || _ref === '@' || _ref === '::');
@@ -51,12 +51,14 @@
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
} else if (tag === 'UNLESS') {
tag = 'IF';
} else if (__indexOf.call(UNARY, tag) >= 0) {
tag = 'UNARY';
} else if (__indexOf.call(RELATION, tag) >= 0) {
if (tag !== 'INSTANCEOF' && this.seenFor) {
this.seenFor = false;
tag = 'FOR' + tag;
this.seenFor = false;
} else {
tag = 'RELATION';
if (this.value() === '!') {
@@ -79,7 +81,7 @@
if (COFFEE_ALIASES.hasOwnProperty(id)) {
id = COFFEE_ALIASES[id];
}
tag = function() {
tag = (function() {
switch (id) {
case '!':
return 'UNARY';
@@ -101,7 +103,7 @@
default:
return tag;
}
}();
})();
}
this.token(tag, id);
if (colon) {
@@ -128,7 +130,7 @@
this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n'));
break;
case '"':
if (!(string = this.balancedString(this.chunk, [['"', '"'], ['#{', '}']]))) {
if (!(string = this.balancedString(this.chunk, '"'))) {
return 0;
}
if (0 < string.indexOf('#{', 1)) {
@@ -208,7 +210,7 @@
return regex.length;
};
Lexer.prototype.heregexToken = function(match) {
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _this;
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _ref4;
heregex = match[0], body = match[1], flags = match[2];
if (0 > body.indexOf('#{')) {
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
@@ -238,7 +240,7 @@
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') {
this.tokens.push(['STRING', '""'], ['+', '+']);
}
(_this = this.tokens).push.apply(_this, tokens);
(_ref4 = this.tokens).push.apply(_ref4, tokens);
if (flags) {
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
}
@@ -447,38 +449,35 @@
Lexer.prototype.assignmentError = function() {
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
};
Lexer.prototype.balancedString = function(str, delimited, options) {
var i, open, pair, stack, _i, _len, _ref;
if (options == null) {
options = {};
}
stack = [delimited[0]];
Lexer.prototype.balancedString = function(str, end) {
var i, letter, prev, stack, _ref;
stack = [end];
for (i = 1, _ref = str.length; (1 <= _ref ? i < _ref : i > _ref); (1 <= _ref ? i += 1 : i -= 1)) {
switch (str.charAt(i)) {
switch (letter = str.charAt(i)) {
case '\\':
i++;
continue;
break;
case stack[stack.length - 1][1]:
case end:
stack.pop();
if (!stack.length) {
return str.slice(0, i + 1);
}
end = stack[stack.length - 1];
continue;
}
for (_i = 0, _len = delimited.length; _i < _len; _i++) {
pair = delimited[_i];
if ((open = pair[0]) === str.substr(i, open.length)) {
stack.push(pair);
i += open.length - 1;
break;
}
if (end === '}' && (letter === '"' || letter === "'")) {
stack.push(end = letter);
} else if (end === '}' && letter === '{') {
stack.push(end = '}');
} else if (end === '"' && prev === '#' && letter === '{') {
stack.push(end = '}');
}
prev = letter;
}
throw new Error("unterminated " + (stack.pop()[0]) + " on line " + (this.line + 1));
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, _this;
var expr, heredoc, i, inner, interpolated, letter, nested, pi, regex, tag, tokens, value, _len, _ref, _ref2, _ref3;
if (options == null) {
options = {};
}
@@ -491,7 +490,7 @@
i += 1;
continue;
}
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), [['{', '}']])))) {
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) {
continue;
}
if (pi < i) {
@@ -516,7 +515,7 @@
i += expr.length;
pi = i + 1;
}
if (i > pi && pi < str.length) {
if ((i > pi && pi < str.length)) {
tokens.push(['NEOSTRING', str.slice(pi)]);
}
if (regex) {
@@ -537,7 +536,7 @@
this.token('+', '+');
}
if (tag === 'TOKENS') {
(_this = this.tokens).push.apply(_this, value);
(_ref3 = this.tokens).push.apply(_ref3, value);
} else {
this.token('STRING', this.makeString(value, '"', heredoc));
}
@@ -580,8 +579,8 @@
return quote + this.escapeLines(body, heredoc) + quote;
};
return Lexer;
}();
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
})();
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 = {
and: '&&',
@@ -596,14 +595,15 @@
}) {
COFFEE_KEYWORDS.push(op);
}
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'do', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice'];
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]*:(?!:))?/;
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
WHITESPACE = /^[^\n\S]+/;
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
CODE = /^[-=]>/;
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
@@ -618,7 +618,7 @@
TRAILING_SPACES = /\s+$/;
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE'];
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
LOGIC = ['&&', '||', '&', '|', '^'];
SHIFT = ['<<', '>>', '>>>'];
COMPARE = ['==', '!=', '<', '>', '<=', '>='];

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
exports.OptionParser = OptionParser = function() {
exports.OptionParser = OptionParser = (function() {
function OptionParser(rules, banner) {
this.banner = banner;
this.rules = buildRules(rules);
@@ -8,11 +8,16 @@
OptionParser.prototype.parse = function(args) {
var arg, i, isOption, matchedRule, options, rule, value, _i, _len, _len2, _ref;
options = {
arguments: []
arguments: [],
literals: []
};
args = normalizeArguments(args);
for (i = 0, _len = args.length; i < _len; i++) {
arg = args[i];
if (arg === '--') {
options.literals = args.slice(i + 1);
break;
}
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
matchedRule = false;
_ref = this.rules;
@@ -52,7 +57,7 @@
return "\n" + (lines.join('\n')) + "\n";
};
return OptionParser;
}();
})();
LONG_FLAG = /^(--\w[\w\-]+)/;
SHORT_FLAG = /^(-\w)/;
MULTI_FLAG = /^-(\w{2,})/;
@@ -65,7 +70,7 @@
if (tuple.length < 3) {
tuple.unshift(null);
}
_results.push(buildRule.apply(buildRule, tuple));
_results.push(buildRule.apply(null, tuple));
}
return _results;
};

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +1,12 @@
(function() {
var CoffeeScript, helpers, readline, repl, run, stdio;
var CoffeeScript, error, helpers, readline, repl, run, stdio;
CoffeeScript = require('./coffee-script');
helpers = require('./helpers');
readline = require('readline');
stdio = process.openStdin();
error = function(err) {
return stdio.write((err.stack || err.toString()) + '\n\n');
};
helpers.extend(global, {
quit: function() {
return process.exit(0);
@@ -21,10 +24,11 @@
console.log(val);
}
} catch (err) {
console.error(err.stack || err.toString());
error(err);
}
return repl.prompt();
};
process.on('uncaughtException', error);
repl = readline.createInterface(stdio);
repl.setPrompt('coffee> ');
stdio.on('data', function(buffer) {

View File

@@ -1,12 +1,12 @@
(function() {
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref;
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref;
var __indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
}
return -1;
}, __slice = Array.prototype.slice;
exports.Rewriter = Rewriter = function() {
exports.Rewriter = (function() {
function Rewriter() {}
Rewriter.prototype.rewrite = function(tokens) {
this.tokens = tokens;
@@ -113,18 +113,18 @@
startIndent = 0;
condition = function(token, i) {
var one, tag, three, two, _ref, _ref2;
_ref = this.tokens, one = _ref[i + 1], two = _ref[i + 2], three = _ref[i + 3];
_ref = this.tokens.slice(i + 1, (i + 3 + 1) || 9e9), one = _ref[0], two = _ref[1], three = _ref[2];
if ('HERECOMMENT' === (one != null ? one[0] : void 0)) {
return false;
}
tag = token[0];
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' && _ref2 !== '('));
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]]);
};
return this.scanTokens(function(token, i, tokens) {
var ago1, ago2, idx, tag, tok, value, _ref, _ref2;
var ago, idx, tag, tok, value, _ref, _ref2;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]);
return 1;
@@ -133,12 +133,12 @@
start = stack.pop();
return 1;
}
if (!(tag === ':' && ((ago2 = this.tag(i - 2)) === ':' || (ago1 = this.tag(i - 1)) === ')' && this.tag(start[1] - 1) === ':' || ((_ref2 = stack[stack.length - 1]) != null ? _ref2[0] : void 0) !== '{'))) {
if (!(tag === ':' && ((ago = this.tag(i - 2)) === ':' || ((_ref2 = stack[stack.length - 1]) != null ? _ref2[0] : void 0) !== '{'))) {
return 1;
}
stack.push(['{']);
idx = ago1 === ')' ? start[1] : ago2 === '@' ? i - 2 : i - 1;
if (this.tag(idx - 2) === 'HERECOMMENT') {
idx = ago === '@' ? i - 2 : i - 1;
while (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2;
}
value = new String('{');
@@ -159,13 +159,13 @@
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
};
return this.scanTokens(function(token, i, tokens) {
var callObject, next, prev, seenSingle, tag, _ref, _ref2;
var callObject, current, next, prev, seenSingle, tag, _ref, _ref2, _ref3;
tag = token[0];
if (tag === 'CLASS' || tag === 'IF' || tag === 'UNLESS') {
if (tag === 'CLASS' || tag === 'IF') {
noCall = true;
}
prev = tokens[i - 1], next = tokens[i + 1];
callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref) >= 0);
_ref = tokens.slice(i - 1, (i + 1 + 1) || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2];
callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0);
seenSingle = false;
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
noCall = false;
@@ -173,17 +173,17 @@
if (prev && !prev.spaced && tag === '?') {
token.call = true;
}
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
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 + (callObject ? 2 : 1), function(token, i) {
this.detectEnd(i + 1, function(token, i) {
var post, _ref;
tag = token[0];
if (!seenSingle && token.fromThen) {
return true;
}
tag = token[0];
if (tag === 'IF' || tag === 'ELSE' || tag === 'UNLESS' || tag === '->' || tag === '=>') {
if (tag === 'IF' || tag === 'ELSE' || tag === '->' || tag === '=>') {
seenSingle = true;
}
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
@@ -244,8 +244,8 @@
return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
};
return this.scanTokens(function(token, i) {
var original, _ref;
if ((_ref = token[0]) !== 'IF' && _ref !== 'UNLESS') {
var original;
if (token[0] !== 'IF') {
return 1;
}
original = token;
@@ -331,7 +331,7 @@
return (_ref = this.tokens[i]) != null ? _ref[0] : void 0;
};
return Rewriter;
}();
})();
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']];
INVERSES = {};
EXPRESSION_START = [];
@@ -343,10 +343,10 @@
}
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', '@', '->', '=>', '[', '(', '{', '--', '++'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
IMPLICIT_UNSPACED_CALL = ['+', '-'];
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'];
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'];
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];

View File

@@ -1,7 +1,8 @@
(function() {
var Scope, extend, last, _ref;
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
exports.Scope = Scope = function() {
exports.Scope = Scope = (function() {
Scope.root = null;
function Scope(parent, expressions, method) {
this.parent = parent;
this.expressions = expressions;
@@ -13,16 +14,15 @@
}
];
this.positions = {};
if (this.parent) {
this.garbage = this.parent.garbage;
} else {
this.garbage = [];
if (!this.parent) {
Scope.root = this;
}
}
Scope.root = null;
Scope.prototype.add = function(name, type) {
Scope.prototype.add = function(name, type, immediate) {
var pos;
if (this.shared && !immediate) {
return this.parent.add(name, type, immediate);
}
if (typeof (pos = this.positions[name]) === 'number') {
return this.variables[pos].type = type;
} else {
@@ -32,21 +32,6 @@
}) - 1;
}
};
Scope.prototype.startLevel = function() {
this.garbage.push([]);
return this;
};
Scope.prototype.endLevel = function() {
var name, _i, _len, _ref;
_ref = this.garbage.pop();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
name = _ref[_i];
if (this.type(name) === 'var') {
this.add(name, 'reuse');
}
}
return this;
};
Scope.prototype.find = function(name, options) {
if (this.check(name, options)) {
return true;
@@ -54,18 +39,10 @@
this.add(name, 'var');
return false;
};
Scope.prototype.any = function(fn) {
var v, _i, _len, _ref;
_ref = this.variables;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
v = _ref[_i];
if (fn(v)) {
return true;
}
}
return false;
};
Scope.prototype.parameter = function(name) {
if (this.shared && this.parent.check(name, true)) {
return;
}
return this.add(name, 'param');
};
Scope.prototype.check = function(name, immediate) {
@@ -95,46 +72,36 @@
return null;
};
Scope.prototype.freeVariable = function(type) {
var index, temp, _ref;
var index, temp;
index = 0;
while (this.check((temp = this.temporary(type, index)), true) && this.type(temp) !== 'reuse') {
while (this.check((temp = this.temporary(type, index)), true)) {
index++;
}
this.add(temp, 'var');
if ((_ref = last(this.garbage)) != null) {
_ref.push(temp);
}
this.add(temp, 'var', true);
return temp;
};
Scope.prototype.assign = function(name, value) {
return this.add(name, {
this.add(name, {
value: value,
assigned: true
});
return this.hasAssignments = true;
};
Scope.prototype.hasDeclarations = function(body) {
return body === this.expressions && this.any(function(v) {
var _ref;
return (_ref = v.type) === 'var' || _ref === 'reuse';
});
};
Scope.prototype.hasAssignments = function(body) {
return body === this.expressions && this.any(function(v) {
return v.type.assigned;
});
Scope.prototype.hasDeclarations = function() {
return !!this.declaredVariables().length;
};
Scope.prototype.declaredVariables = function() {
var tmp, usr, v, _i, _len, _ref, _ref2;
usr = [];
tmp = [];
var realVars, tempVars, v, _i, _len, _ref;
realVars = [];
tempVars = [];
_ref = this.variables;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
v = _ref[_i];
if ((_ref2 = v.type) === 'var' || _ref2 === 'reuse') {
(v.name.charAt(0) === '_' ? tmp : usr).push(v.name);
if (v.type === 'var') {
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
}
}
return usr.sort().concat(tmp.sort());
return realVars.sort().concat(tempVars.sort());
};
Scope.prototype.assignedVariables = function() {
var v, _i, _len, _ref, _results;
@@ -148,12 +115,6 @@
}
return _results;
};
Scope.prototype.compiledDeclarations = function() {
return this.declaredVariables().join(', ');
};
Scope.prototype.compiledAssignments = function() {
return this.assignedVariables().join(', ');
};
return Scope;
}();
})();
}).call(this);

View File

@@ -3,13 +3,13 @@
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language", "coffeescript", "compiler"],
"author": "Jeremy Ashkenas",
"version": "0.9.5",
"version": "1.0.0",
"licenses": [{
"type": "MIT",
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
}],
"engines": {
"node": ">=0.1.99"
"node": ">=0.2.5"
},
"directories" : {
"lib" : "./lib"

View File

@@ -56,7 +56,7 @@ exports.run = ->
# Display the list of Cake tasks in a format similar to `rake -T`
printTasks = ->
console.log ''
for all name, task of tasks
for name, task of tasks
spaces = 20 - name.length
spaces = if spaces > 0 then Array(spaces + 1).join(' ') else ''
desc = if task.description then "# #{task.description}" else ''

View File

@@ -6,10 +6,10 @@
# If included on a webpage, it will automatically sniff out, compile, and
# execute all scripts present in `text/coffeescript` tags.
fs = require 'fs'
path = require 'path'
{Lexer} = require './lexer'
{parser} = require './parser'
fs = require 'fs'
path = require 'path'
{Lexer,RESERVED} = require './lexer'
{parser} = require './parser'
# TODO: Remove registerExtension when fully deprecated.
if require.extensions
@@ -20,7 +20,10 @@ else if require.registerExtension
require.registerExtension '.coffee', (content) -> compile content
# The current CoffeeScript version number.
exports.VERSION = '0.9.5'
exports.VERSION = '1.0.0'
# Words that cannot be used as identifiers in CoffeeScript code
exports.RESERVED = RESERVED
# Expose helpers for testing.
exports.helpers = require './helpers'

View File

@@ -7,6 +7,7 @@
# External dependencies.
fs = require 'fs'
path = require 'path'
util = require 'util'
helpers = require './helpers'
optparse = require './optparse'
CoffeeScript = require './coffee-script'
@@ -16,6 +17,9 @@ CoffeeScript = require './coffee-script'
# Allow CoffeeScript to emit Node.js events.
helpers.extend CoffeeScript, new EventEmitter
printLine = (line) -> process.stdout.write line + '\n'
printWarn = (line) -> process.binding('stdio').writeError line + '\n'
# The help banner that is printed when `coffee` is called without arguments.
BANNER = '''
Usage: coffee [options] path/to/script.coffee
@@ -26,6 +30,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']
['-w', '--watch', 'watch scripts for changes, and recompile']
['-p', '--print', 'print the compiled JavaScript to stdout']
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
@@ -35,20 +40,15 @@ SWITCHES = [
['-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 that are still supported, but will cause a warning message.
DEPRECATED_SWITCHES = [
['--no-wrap', 'compile without the top-level function wrapper']
]
ALL_SWITCHES = SWITCHES.concat DEPRECATED_SWITCHES
# Top-level objects shared by all the functions.
opts = {}
sources = []
contents = []
optionParser = null
# Run `coffee` by parsing passed options and determining what action to take.
@@ -56,20 +56,16 @@ optionParser = null
# `--` will be passed verbatim to your script as arguments in `process.argv`
exports.run = ->
parseOptions()
return usage() if opts.help
return version() if opts.version
return require './repl' if opts.interactive
return compileStdio() if opts.stdio
return compileScript null, sources[0] if opts.eval
return require './repl' unless sources.length
separator = sources.indexOf '--'
flags = []
if separator >= 0
flags = sources.splice separator + 1
sources.pop()
return forkNode() if opts.nodejs
return usage() if opts.help
return version() if opts.version
return require './repl' if opts.interactive
return compileStdio() if opts.stdio
return compileScript null, sources[0] if opts.eval
return require './repl' unless sources.length
if opts.run
flags = sources.splice(1).concat flags
process.ARGV = process.argv = flags
opts.literals = sources.splice(1).concat opts.literals
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
compileScripts()
# Asynchronously read in each CoffeeScript in a list of source files and
@@ -87,8 +83,13 @@ compileScripts = ->
for file in files
compile path.join(source, file)
else if topLevel or path.extname(source) is '.coffee'
fs.readFile source, (err, code) -> compileScript(source, code.toString(), base)
watch source, base if opts.watch
fs.readFile source, (err, code) ->
if opts.join
contents[sources.indexOf source] = code.toString()
compileJoin() if helpers.compact(contents).length is sources.length
else
compileScript(source, code.toString(), base)
watch source, base if opts.watch and not opts.join
compile source, true
# Compile a single source script, containing the given code, according to the
@@ -103,19 +104,19 @@ compileScript = (file, input, base) ->
t = task = {file, input, options}
CoffeeScript.emit 'compile', task
if o.tokens then printTokens CoffeeScript.tokens t.input
else if o.nodes then console.log CoffeeScript.nodes(t.input).toString().trim()
else if o.nodes then printLine CoffeeScript.nodes(t.input).toString().trim()
else if o.run then CoffeeScript.run t.input, t.options
else
t.output = CoffeeScript.compile t.input, t.options
CoffeeScript.emit 'success', task
if o.print then console.log t.output.trim()
if o.print then printLine t.output.trim()
else if o.compile then writeJs t.file, t.output, base
else if o.lint then lint t.file, t.output
catch err
CoffeeScript.emit 'failure', err, task
return if CoffeeScript.listeners('failure').length
return console.log err.message if o.watch
console.error err.stack
return printLine err.message if o.watch
printWarn err.stack
process.exit 1
# Attach the appropriate listeners to compile scripts incoming over **stdin**,
@@ -128,6 +129,12 @@ compileStdio = ->
stdin.on 'end', ->
compileScript null, code
# After all of the source files are done being read, concatenate and compile
# them together.
compileJoin = ->
code = contents.join '\n'
compileScript "concatenation", code, "concatenation"
# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
# time the file is updated. May be used in combination with other options,
# such as `--lint` or `--print`.
@@ -144,21 +151,21 @@ watch = (source, base) ->
writeJs = (source, js, base) ->
filename = path.basename(source, path.extname(source)) + '.js'
srcDir = path.dirname source
baseDir = srcDir.substring base.length
baseDir = if base is '.' then srcDir else srcDir.substring base.length
dir = if opts.output then path.join opts.output, baseDir else srcDir
jsPath = path.join dir, filename
compile = ->
js = ' ' if js.length <= 0
fs.writeFile jsPath, js, (err) ->
if err then console.log err.message
else if opts.compile and opts.watch then console.log "Compiled #{source}"
if err then printLine err.message
else if opts.compile and opts.watch then util.log "compiled #{source}"
path.exists dir, (exists) ->
if exists then compile() else exec "mkdir -p #{dir}", compile
# Pipe compiled JS through JSLint (requires a working `jsl` command), printing
# any errors or warnings that arise.
lint = (file, js) ->
printIt = (buffer) -> console.log file + ':\t' + buffer.toString().trim()
printIt = (buffer) -> printLine file + ':\t' + buffer.toString().trim()
conf = __dirname + '/../extras/jsl.conf'
jsl = spawn 'jsl', ['-nologo', '-stdin', '-conf', conf]
jsl.stdout.on 'data', printIt
@@ -171,30 +178,39 @@ printTokens = (tokens) ->
strings = for token in tokens
[tag, value] = [token[0], token[1].toString().replace(/\n/, '\\n')]
"[#{tag} #{value}]"
console.log strings.join(' ')
printLine strings.join(' ')
# Use the [OptionParser module](optparse.html) to extract all options from
# `process.argv` that are specified in `SWITCHES`.
parseOptions = ->
optionParser = new optparse.OptionParser ALL_SWITCHES, BANNER
optionParser = new optparse.OptionParser SWITCHES, BANNER
o = opts = optionParser.parse process.argv.slice 2
o.compile or= !!o.output
o.run = not (o.compile or o.print or o.lint)
o.print = !! (o.print or (o.eval or o.stdio and o.compile))
sources = o.arguments
if opts['no-wrap']
console.warn '--no-wrap is deprecated; please use --bare instead.'
# The compile-time options to pass to the CoffeeScript compiler.
compileOptions = (fileName) -> {fileName, bare: opts.bare or opts['no-wrap']}
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.
forkNode = ->
nodeArgs = opts.nodejs.split /\s+/
args = process.argv[1..]
args.splice args.indexOf('--nodejs'), 2
spawn process.execPath, nodeArgs.concat(args),
cwd: process.cwd()
env: process.env
customFds: [0, 1, 2]
# Print the `--help` usage message and exit. Deprecated switches are not
# shown.
usage = ->
console.log (new optparse.OptionParser SWITCHES, BANNER).help()
printLine (new optparse.OptionParser SWITCHES, BANNER).help()
process.exit 0
# Print the `--version` message and exit.
version = ->
console.log "CoffeeScript version #{CoffeeScript.VERSION}"
printLine "CoffeeScript version #{CoffeeScript.VERSION}"
process.exit 0

View File

@@ -104,8 +104,8 @@ grammar =
# will convert some postfix forms into blocks for us, by adjusting the
# token stream.
Block: [
o 'INDENT Body OUTDENT', -> $2
o 'INDENT OUTDENT', -> new Expressions
o 'INDENT Body OUTDENT', -> $2
]
# A literal identifier, a variable name or property.
@@ -149,7 +149,6 @@ grammar =
ObjAssignable: [
o 'Identifier'
o 'AlphaNumeric'
o 'Parenthetical'
o 'ThisProperty'
]
@@ -287,10 +286,8 @@ grammar =
Invocation: [
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
o 'Invocation OptFuncExist Arguments', -> new Call $1, $3, $2
o 'SUPER', ->
new Call 'super', [new Splat new Literal 'arguments']
o 'SUPER Arguments', ->
new Call 'super', $2
o 'SUPER', -> new Call 'super', [new Splat new Literal 'arguments']
o 'SUPER Arguments', -> new Call 'super', $2
]
# An optional existence check on a function.
@@ -418,19 +415,19 @@ grammar =
# Comprehensions can either be normal, with a block of expressions to execute,
# or postfix, with a single expression.
For: [
o 'Statement ForBody', -> new For $1, $2, $2.vars[0], $2.vars[1]
o 'Expression ForBody', -> new For $1, $2, $2.vars[0], $2.vars[1]
o 'ForBody Block', -> new For $2, $1, $1.vars[0], $1.vars[1]
o 'Statement ForBody', -> new For $1, $2
o 'Expression ForBody', -> new For $1, $2
o 'ForBody Block', -> new For $2, $1
]
ForBody: [
o 'FOR Range', -> source: new Value($2), vars: []
o 'ForStart ForSource', -> $2.raw = $1.raw; $2.vars = $1; $2
o 'FOR Range', -> source: new Value($2)
o 'ForStart ForSource', -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2
]
ForStart: [
o 'FOR ForVariables', -> $2
o 'FOR ALL ForVariables', -> $3.raw = yes; $3
o 'FOR OWN ForVariables', -> $3.own = yes; $3
]
# An array of all accepted values for a variable inside the loop.
@@ -484,9 +481,8 @@ grammar =
# if-related rules are broken up along these lines in order to avoid
# ambiguity.
IfBlock: [
o 'IF Expression Block', -> new If $2, $3
o 'UNLESS Expression Block', -> new If $2, $3, invert: true
o 'IfBlock ELSE IF Expression Block', -> $1.addElse new If $4, $5
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
]
@@ -494,10 +490,8 @@ grammar =
# *if* and *unless*.
If: [
o 'IfBlock'
o 'Statement POST_IF Expression', -> new If $3, Expressions.wrap([$1]), statement: true
o 'Expression POST_IF Expression', -> new If $3, Expressions.wrap([$1]), statement: true
o 'Statement POST_UNLESS Expression', -> new If $3, Expressions.wrap([$1]), statement: true, invert: true
o 'Expression POST_UNLESS Expression', -> new If $3, Expressions.wrap([$1]), statement: true, invert: true
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
]
# Arithmetic and logical operators, working on one or more operands.
@@ -566,8 +560,8 @@ operators = [
['nonassoc', 'INDENT', 'OUTDENT']
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
['right', 'FORIN', 'FOROF', 'BY', 'WHEN']
['right', 'IF', 'UNLESS', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
['right', 'POST_IF', 'POST_UNLESS']
['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
['right', 'POST_IF']
]
# Wrapping Up
@@ -578,7 +572,7 @@ operators = [
# terminals (every symbol which does not appear as the name of a rule above)
# as "tokens".
tokens = []
for all name, alternatives of grammar
for name, alternatives of grammar
grammar[name] = for alt in alternatives
for token in alt[0].split ' '
tokens.push token unless grammar[token]

View File

@@ -15,10 +15,11 @@ exports.ends = (string, literal, back) ->
exports.compact = (array) ->
item for item in array when item
# Count the number of occurrences of a character in a string.
exports.count = (string, letter) ->
# Count the number of occurrences of a string in a string.
exports.count = (string, substr) ->
num = pos = 0
num++ while pos = 1 + string.indexOf letter, pos
return 1/0 unless substr.length
num++ while pos = 1 + string.indexOf substr, pos
num
# Merge objects, returning a fresh copy with attributes from both sides.
@@ -29,7 +30,7 @@ exports.merge = (options, overrides) ->
# Extend a source object with the properties of another object (shallow copy).
extend = exports.extend = (object, properties) ->
for all key, val of properties
for key, val of properties
object[key] = val
object

View File

@@ -75,8 +75,8 @@ exports.Lexer = class Lexer
return 0 unless match = IDENTIFIER.exec @chunk
[input, id, colon] = match
if id is 'all' and @tag() is 'FOR'
@token 'ALL', id
if id is 'own' and @tag() is 'FOR'
@token 'OWN', id
return id.length
forcedIdentifier = colon or
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
@@ -89,12 +89,14 @@ exports.Lexer = class Lexer
tag = 'LEADING_WHEN'
else if tag is 'FOR'
@seenFor = yes
else if tag is 'UNLESS'
tag = 'IF'
else if tag in UNARY
tag = 'UNARY'
else if tag in RELATION
if tag isnt 'INSTANCEOF' and @seenFor
@seenFor = no
tag = 'FOR' + tag
@seenFor = no
else
tag = 'RELATION'
if @value() is '!'
@@ -139,7 +141,7 @@ exports.Lexer = class Lexer
return 0 unless match = SIMPLESTR.exec @chunk
@token 'STRING', (string = match[0]).replace MULTILINER, '\\\n'
when '"'
return 0 unless string = @balancedString @chunk, [['"', '"'], ['#{', '}']]
return 0 unless string = @balancedString @chunk, '"'
if 0 < string.indexOf '#{', 1
@interpolateString string.slice 1, -1
else
@@ -387,22 +389,27 @@ exports.Lexer = class Lexer
# a series of delimiters, all of which must be nested correctly within the
# contents of the string. This method allows us to have strings within
# interpolations within strings, ad infinitum.
balancedString: (str, delimited, options = {}) ->
stack = [delimited[0]]
balancedString: (str, end) ->
stack = [end]
for i in [1...str.length]
switch str.charAt i
switch letter = str.charAt i
when '\\'
i++
continue
when stack[stack.length - 1][1]
when end
stack.pop()
return str.slice 0, i + 1 unless stack.length
unless stack.length
return str.slice 0, i + 1
end = stack[stack.length - 1]
continue
for pair in delimited when (open = pair[0]) is str.substr i, open.length
stack.push pair
i += open.length - 1
break
throw new Error "unterminated #{ stack.pop()[0] } on line #{ @line + 1 }"
if end is '}' and letter in ['"', "'"]
stack.push end = letter
else if end is '}' and letter is '{'
stack.push end = '}'
else if end is '"' and prev is '#' and letter is '{'
stack.push end = '}'
prev = letter
throw new Error "missing #{ stack.pop() }, starting on line #{ @line + 1 }"
# Expand variables and expressions inside double-quoted strings using
@@ -423,7 +430,7 @@ exports.Lexer = class Lexer
i += 1
continue
unless letter is '#' and str.charAt(i+1) is '{' and
(expr = @balancedString str.slice(i+1), [['{', '}']])
(expr = @balancedString str.slice(i + 1), '}')
continue
tokens.push ['NEOSTRING', str.slice(pi, i)] if pi < i
inner = expr.slice(1, -1)
@@ -493,13 +500,13 @@ JS_KEYWORDS = [
'true', 'false', 'null', 'this'
'new', 'delete', 'typeof', 'in', 'instanceof'
'return', 'throw', 'break', 'continue', 'debugger'
'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally'
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
'class', 'extends', 'super'
]
# CoffeeScript-only keywords.
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']
COFFEE_KEYWORDS.push op for all op of COFFEE_ALIASES =
COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
and : '&&'
or : '||'
is : '=='
@@ -514,15 +521,17 @@ COFFEE_KEYWORDS.push op for all op of COFFEE_ALIASES =
# used by CoffeeScript internally. We throw an error when these are encountered,
# to avoid having a JavaScript error at runtime.
RESERVED = [
'case', 'default', 'function', 'var', 'void', 'with', 'do'
'case', 'default', 'function', 'var', 'void', 'with'
'const', 'let', 'enum', 'export', 'import', 'native'
'__hasProp', '__extends', '__slice'
'__hasProp', '__extends', '__slice', '__bind', '__indexOf'
]
# The superset of both JavaScript keywords and reserved words, none of which may
# be used as identifiers or properties.
JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
# Token matching regexes.
IDENTIFIER = /// ^
( [$A-Za-z_][$\w]* )
@@ -548,7 +557,7 @@ OPERATOR = /// ^ (
WHITESPACE = /^[^\n\S]+/
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
CODE = /^[-=]>/
@@ -600,7 +609,7 @@ COMPOUND_ASSIGN = [
]
# Unary tokens.
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE']
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']
# Logical tokens.
LOGIC = ['&&', '||', '&', '|', '^']

View File

@@ -40,7 +40,7 @@ exports.Base = class Base
o.level = lvl if lvl
node = @unfoldSoak(o) or this
node.tab = o.indent
if o.level is LEVEL_TOP or node.isPureStatement() or not node.isStatement(o)
if o.level is LEVEL_TOP or not node.isStatement(o)
node.compileNode o
else
node.compileClosure o
@@ -48,9 +48,9 @@ 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 @containsPureStatement()
throw SyntaxError 'cannot include a pure statement in an expression.'
o.sharedScope = o.scope
if @jumps()
throw SyntaxError 'cannot use a pure statement in an expression.'
o.sharedScope = yes
Closure.wrap(this).compileNode o
# If the code generation wishes to use the result of a complex expression
@@ -94,10 +94,11 @@ exports.Base = class Base
containsType: (type) ->
this instanceof type or @contains (node) -> node instanceof type
# Convenience for the most common use of contains. Does the node contain
# a pure statement?
containsPureStatement: ->
@isPureStatement() or @contains (node) -> node.isPureStatement()
# Pull out the last non-comment node of a node list.
lastNonComment: (list) ->
i = list.length
return list[i] while i-- when list[i] not instanceof Comment
null
# `toString` representation of the node, for inspecting the parse tree.
# This is what `coffee --nodes` prints out.
@@ -133,7 +134,7 @@ exports.Base = class Base
children: []
isStatement : NO
isPureStatement : NO
jumps : NO
isComplex : YES
isChainable : NO
isAssignable : NO
@@ -179,10 +180,14 @@ exports.Expressions = class Expressions extends Base
not @expressions.length
isStatement: (o) ->
for exp in @expressions when exp.isPureStatement() or exp.isStatement o
for exp in @expressions when exp.isStatement o
return yes
no
jumps: (o) ->
for exp in @expressions
return exp if exp.jumps o
# An Expressions node does not return its entire body, rather it
# ensures that the final expression is returned.
makeReturn: ->
@@ -237,17 +242,18 @@ exports.Expressions = class Expressions extends Base
for exp, i in @expressions
exp = exp.unwrap()
break unless exp instanceof Comment or exp instanceof Literal
o.level = LEVEL_TOP
o = merge(o, level: LEVEL_TOP)
if i
rest = @expressions.splice i, @expressions.length
code = @compileNode o
@expressions = rest
post = @compileNode o
{scope} = o
if not o.globals and o.scope.hasDeclarations this
code += "#{@tab}var #{ scope.compiledDeclarations() };\n"
if scope.hasAssignments this
code += "#{@tab}var #{ multident scope.compiledAssignments(), @tab };\n"
if scope.expressions is this
if not o.globals and 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
@@ -265,23 +271,26 @@ exports.Literal = class Literal extends Base
constructor: (@value) ->
makeReturn: ->
if @isPureStatement() then this else new Return this
# Break and continue must be treated as pure statements -- they lose their
# meaning when wrapped in a closure.
isPureStatement: ->
@value in ['break', 'continue', 'debugger']
if @isStatement() then this else new Return this
isAssignable: ->
IDENTIFIER.test @value
isStatement: ->
@value in ['break', 'continue', 'debugger']
isComplex: NO
assigns: (name) ->
name is @value
compile: ->
if @value.reserved then "\"#{@value}\"" else @value
jumps: (o) ->
return no unless @isStatement()
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
if @isStatement() then "#{@tab}#{code};" else code
toString: ->
' "' + @value + '"'
@@ -296,16 +305,15 @@ exports.Return = class Return extends Base
children: ['expression']
isStatement: YES
isPureStatement: YES
makeReturn: THIS
jumps: THIS
compile: (o, level) ->
expr = @expression?.makeReturn()
if expr and expr not instanceof Return then expr.compile o, level else super o, level
compileNode: (o) ->
o.level = LEVEL_PAREN
@tab + "return#{ if @expression then ' ' + @expression.compile o else '' };"
@tab + "return#{ if @expression then ' ' + @expression.compile(o, LEVEL_PAREN) else '' };"
#### Value
@@ -341,6 +349,7 @@ exports.Value = class Value extends Base
isStatement : (o) -> not @properties.length and @base.isStatement o
assigns : (name) -> not @properties.length and @base.assigns name
jumps : (o) -> not @properties.length and @base.jumps o
isObject: (onlyGenerated) ->
return no if @properties.length
@@ -410,7 +419,6 @@ exports.Value = class Value extends Base
exports.Comment = class Comment extends Base
constructor: (@comment) ->
isPureStatement: YES
isStatement: YES
makeReturn: THIS
@@ -433,7 +441,11 @@ exports.Call = class Call extends Base
# Tag this invocation as creating a new instance.
newInstance: ->
@isNew = true
base = @variable.base or @variable
if base instanceof Call
base.newInstance()
else
@isNew = true
this
# Grab the reference to the superclass's implementation of the current
@@ -487,7 +499,7 @@ exports.Call = class Call extends Base
return @compileSplat o, code
args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
if @isSuper
@compileSuper args, o
@superReference(o) + ".call(this#{ args and ', ' + args })"
else
(if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})"
@@ -502,23 +514,27 @@ exports.Call = class Call extends Base
# inner constructor in order to be able to pass the varargs.
compileSplat: (o, splatArgs) ->
return "#{ @superReference o }.apply(this, #{splatArgs})" if @isSuper
unless @isNew
base = new Value @variable
if (name = base.properties.pop()) and base.isComplex()
ref = o.scope.freeVariable 'this'
fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
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() {})
"""
base = new Value @variable
if (name = base.properties.pop()) and base.isComplex()
ref = o.scope.freeVariable 'ref'
fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
else
fun = base.compile o, LEVEL_ACCESS
if name
ref = fun
fun += name.compile o
else
fun = ref = base.compile o, LEVEL_ACCESS
fun += name.compile o if name
return "#{fun}.apply(#{ref}, #{splatArgs})"
idt = @tab + TAB
"""
(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() {})
"""
ref = 'null'
"#{fun}.apply(#{ref}, #{splatArgs})"
#### Extends
@@ -541,6 +557,7 @@ exports.Extends = class Extends extends Base
# an access into the object's prototype.
exports.Access = class Access extends Base
constructor: (@name, tag) ->
@name.asKey = yes
@proto = if tag is 'proto' then '.prototype' else ''
@soak = tag is 'soak'
@@ -648,12 +665,21 @@ exports.Slice = class Slice extends Base
constructor: (@range) ->
super()
# We have to be careful when trying to slice through the end of the array,
# `9e9` is used because not all implementations respect `undefined` or `1/0`.
# `9e9` should be safe because `9e9` > `2**32`, the max array length.
compileNode: (o) ->
from = if @range.from then @range.from.compile(o) else '0'
to = if @range.to then @range.to.compile(o) else ''
to += if not to or @range.exclusive then '' else ' + 1'
to = ', ' + to if to
".slice(#{from}#{to})"
{to, from} = @range
fromStr = from and from.compile(o, LEVEL_PAREN) or '0'
compiled = to and to.compile o, LEVEL_PAREN
if to and not (not @range.exclusive and +compiled is -1)
toStr = ', ' + if @range.exclusive
compiled
else if SIMPLENUM.test compiled
(+compiled + 1).toString()
else
"(#{compiled} + 1) || 9e9"
".slice(#{ fromStr }#{ toStr or '' })"
#### Obj
@@ -667,13 +693,8 @@ exports.Obj = class Obj extends Base
compileNode: (o) ->
props = @properties
return (if @front then '({})' else '{}') unless props.length
for prop, i in props
if prop instanceof Splat or (prop.variable or prop).base instanceof Parens
rest = props.splice i, 1/0
break
idt = o.indent += TAB
nonComments = (prop for prop in @properties when prop not instanceof Comment)
lastNoncom = last nonComments
lastNoncom = @lastNonComment @properties
props = for prop, i in props
join = if i is props.length - 1
''
@@ -684,36 +705,15 @@ exports.Obj = class Obj extends Base
indent = if prop instanceof Comment then '' else idt
if prop instanceof Value and prop.this
prop = new Assign prop.properties[0].name, prop, 'object'
else if prop not instanceof Assign and prop not instanceof Comment
prop = new Assign prop, prop, 'object'
if prop not instanceof Comment
if prop not instanceof Assign
prop = new Assign prop, prop, 'object'
(prop.variable.base or prop.variable).asKey = yes
indent + prop.compile(o, LEVEL_TOP) + join
props = props.join ''
obj = "{#{ props and '\n' + props + '\n' + @tab }}"
return @compileDynamic o, obj, rest if rest
if @front then "(#{obj})" else obj
compileDynamic: (o, code, props) ->
code = "#{ oref = o.scope.freeVariable 'obj' } = #{code}, "
for prop, i in props
if prop instanceof Comment
code += prop.compile(o, LEVEL_LIST) + ' '
continue
if prop instanceof Assign
acc = prop.variable.base
key = acc.compile o, LEVEL_PAREN
val = prop.value.compile o, LEVEL_LIST
else
acc = prop.base
[key, val] = acc.cache o, LEVEL_LIST, ref
ref = val if key isnt val
key = if acc instanceof Literal and IDENTIFIER.test key
'.' + key
else
'[' + key + ']'
code += "#{oref}#{key} = #{val}, "
code += oref
if o.level <= LEVEL_PAREN then code else "(#{code})"
assigns: (name) ->
for prop in @properties when prop.assigns name then return yes
no
@@ -749,6 +749,7 @@ exports.Arr = class Arr extends Base
exports.Class = class Class extends Base
constructor: (@variable, @parent, @body = new Expressions) ->
@boundFuncs = []
@body.classBody = yes
children: ['variable', 'parent', 'body']
@@ -765,6 +766,7 @@ exports.Class = class Class extends Base
# `this` is the Class being constructed.
setContext: (name) ->
@body.traverseChildren false, (node) ->
return false if node.classBody
if node instanceof Literal and node.value is 'this'
node.value = name
else if node instanceof Code
@@ -794,10 +796,9 @@ exports.Class = class Class extends Base
if func.bound
throw new Error 'cannot define a constructor as a bound function'
if func instanceof Code
@ctor = func
assign = @ctor = func
else
@ctor = new Assign(new Value(new Literal name), func)
assign = null
assign = @ctor = new Assign(new Value(new Literal name), func)
else
unless assign.variable.this
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
@@ -809,11 +810,12 @@ exports.Class = class Class extends Base
# Walk the body of the class, looking for prototype properties to be converted.
walkBody: (name) ->
@traverseChildren false, (child) =>
return false if child instanceof Class
if child instanceof Expressions
for node, i in exps = child.expressions
if node instanceof Value and node.isObject(true)
exps[i] = compact @addProperties node, name
child.expressions = exps = compact flatten exps
exps[i] = @addProperties node, name
child.expressions = exps = flatten exps
# Make sure that a constructor is defined for the class, and properly
# configured.
@@ -821,6 +823,7 @@ exports.Class = class Class extends Base
if not @ctor
@ctor = new Code
@ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent
@body.expressions.unshift @ctor
@ctor.ctor = @ctor.name = name
@ctor.klass = null
@ctor.noReturn = yes
@@ -835,14 +838,12 @@ exports.Class = class Class extends Base
@setContext name
@walkBody name
@ensureConstructor name
@body.expressions.unshift new Extends lname, @parent if @parent
@body.expressions.unshift @ctor
@ensureConstructor name
@body.expressions.push lname
@addBoundFunctions o
klass = new Parens new Call(new Code [], @body), true
klass = new Assign new Value(lname), klass if decl and @variable?.isComplex()
klass = new Parens Closure.wrap(@body), true
klass = new Assign @variable, klass if @variable
klass.compile o
@@ -851,7 +852,8 @@ exports.Class = class Class extends Base
# The **Assign** is used to assign a local variable to value, or to set the
# property of an object -- including within object literals.
exports.Assign = class Assign extends Base
constructor: (@variable, @value, @context) ->
constructor: (@variable, @value, @context, options) ->
@param = options and options.param
# Matchers for detecting class/method names
METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/
@@ -881,8 +883,11 @@ exports.Assign = class Assign extends Base
return "#{name}: #{val}" if @context is 'object'
unless @variable.isAssignable()
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
o.scope.find name unless @context or
isValue and (@variable.namespaced or @variable.hasProperties())
unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
if @param
o.scope.add name, 'var'
else
o.scope.find name
val = name + " #{ @context or '=' } " + val
if o.level <= LEVEL_LIST then val else "(#{val})"
@@ -951,7 +956,7 @@ exports.Assign = class Assign extends Base
else
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
assigns.push new Assign(obj, val).compile o, LEVEL_TOP
assigns.push new Assign(obj, val, null, param: @param).compile o, LEVEL_TOP
assigns.push vvar unless top
code = assigns.join ', '
if o.level < LEVEL_LIST then code else "(#{code})"
@@ -966,14 +971,21 @@ exports.Assign = class Assign extends Base
# Compile the assignment from an array splice literal, using JavaScript's
# `Array#splice` method.
compileSplice: (o) ->
{range} = @variable.properties.pop()
name = @variable.compile o
plus = if range.exclusive then '' else ' + 1'
from = if range.from then range.from.compile(o) else '0'
to = if range.to then range.to.compile(o) + ' - ' + from + plus else "#{name}.length"
ref = o.scope.freeVariable 'ref'
val = @value.compile(o)
"([].splice.apply(#{name}, [#{from}, #{to}].concat(#{ref} = #{val})), #{ref})"
{range: {from, to, exclusive}} = @variable.properties.pop()
name = @variable.compile o
[fromDecl, fromRef] = from?.cache(o, LEVEL_OP) or ['0', '0']
if to
if from?.isSimpleNumber() and to.isSimpleNumber()
to = +to.compile(o) - +fromRef
to += 1 unless exclusive
else
to = to.compile(o) + ' - ' + fromRef
to += ' + 1' unless exclusive
else
to = "9e9"
[valDef, valRef] = @value.cache o, LEVEL_LIST
code = "[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}"
if o.level > LEVEL_TOP then "(#{code})" else code
#### Code
@@ -991,15 +1003,17 @@ exports.Code = class Code extends Base
isStatement: -> !!@ctor
jumps: NO
# 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 `arguments` objects. If the function is bound with the `=>`
# arrow, generates a wrapper that saves the current value of `this` through
# a closure.
compileNode: (o) ->
sharedScope = del o, 'sharedScope'
o.scope = scope = sharedScope or new Scope o.scope, @body, this
o.indent += TAB
o.scope = new Scope o.scope, @body, this
o.scope.shared = del o, 'sharedScope'
o.indent += TAB
delete o.bare
delete o.globals
vars = []
@@ -1012,7 +1026,7 @@ exports.Code = class Code extends Base
if param.isComplex()
val = ref = param.asReference o
val = new Op '?', ref, param.value if param.value
exprs.push new Assign new Value(param.name), val, '='
exprs.push new Assign new Value(param.name), val, '=', param: yes
else
ref = param
if param.value
@@ -1020,11 +1034,10 @@ exports.Code = class Code extends Base
val = new Assign new Value(param.name), param.value, '='
exprs.push new If lit, val
vars.push ref unless splats
scope.startLevel()
wasEmpty = @body.isEmpty()
exprs.unshift splats if splats
@body.expressions.unshift exprs... if exprs.length
scope.parameter vars[i] = v.compile o for v, i in vars unless splats
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
@body.makeReturn() unless wasEmpty or @noReturn
idt = o.indent
code = 'function'
@@ -1034,7 +1047,7 @@ exports.Code = class Code extends Base
code += '}'
return @tab + code if @ctor
return utility('bind') + "(#{code}, #{@context})" if @bound
if @front then "(#{code})" else code
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
# unless `crossScope` is `true`.
@@ -1129,13 +1142,12 @@ exports.While = class While extends Base
addBody: (@body) ->
this
containsPureStatement: ->
jumps: ->
{expressions} = @body
i = expressions.length
return true if expressions[--i]?.containsPureStatement()
ret = (node) -> node instanceof Return
return true while i-- when expressions[i].contains ret
false
return no unless expressions.length
for node in expressions
return node if node.jumps loop: yes
no
# The main difference from a JavaScript *while* is that the CoffeeScript
# *while* can be used as a part of a larger expression -- while loops may
@@ -1155,8 +1167,7 @@ exports.While = class While extends Base
body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
if @returns
o.indent = @tab
code += '\n' + new Return(new Literal rvar).compile o
code += "\n#{@tab}return #{rvar};"
code
#### Op
@@ -1166,6 +1177,7 @@ 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 'new'
return first.newInstance() if first instanceof Call
first = new Parens first if first instanceof Code and first.bound
@@ -1185,13 +1197,11 @@ exports.Op = class Op extends Base
INVERSIONS =
'!==': '==='
'===': '!=='
'>': '<='
'<=': '>'
'<': '>='
'>=': '<'
children: ['first', 'second']
isSimpleNumber: NO
isUnary: ->
not @second
@@ -1201,8 +1211,23 @@ exports.Op = class Op extends Base
@operator in ['<', '>', '>=', '<=', '===', '!==']
invert: ->
if op = INVERSIONS[@operator]
if @isChainable() and @first.isChainable()
allInvertable = yes
curr = this
while curr and curr.operator
allInvertable and= (curr.operator of INVERSIONS)
curr = curr.first
return new Parens(this).invert() unless allInvertable
curr = this
while curr and curr.operator
curr.invert = !curr.invert
curr.operator = INVERSIONS[curr.operator]
curr = curr.first
this
else if op = INVERSIONS[@operator]
@operator = op
if @first.unwrap() instanceof Op
@first.invert()
this
else if @second
new Parens(this).invert()
@@ -1231,10 +1256,9 @@ exports.Op = class Op extends Base
# true
compileChain: (o) ->
[@first.second, shared] = @first.second.cache o
fst = @first .compile o, LEVEL_OP
fst = fst.slice 1, -1 if fst.charAt(0) is '('
code = "#{fst} && #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
if o.level < LEVEL_OP then code else "(#{code})"
fst = @first.compile o, LEVEL_OP
code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
"(#{code})"
compileExistence: (o) ->
if @first.isComplex()
@@ -1300,6 +1324,8 @@ exports.Try = class Try extends Base
isStatement: YES
jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)
makeReturn: ->
@attempt = @attempt .makeReturn() if @attempt
@recovery = @recovery.makeReturn() if @recovery
@@ -1329,6 +1355,7 @@ exports.Throw = class Throw extends Base
children: ['expression']
isStatement: YES
jumps: NO
# A **Throw** is already a return, of sorts...
makeReturn: THIS
@@ -1381,8 +1408,9 @@ exports.Parens = class Parens extends Base
if expr instanceof Value and expr.isAtomic()
expr.front = @front
return expr.compile o
bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call)
code = expr.compile o, LEVEL_PAREN
bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or
(expr instanceof For and expr.returns))
if bare then code else "(#{code})"
#### For
@@ -1395,45 +1423,46 @@ exports.Parens = class Parens extends Base
# the current index of the loop as a second parameter. Unlike Ruby blocks,
# you can map and filter in a single pass.
exports.For = class For extends Base
constructor: (body, source, @name, @index) ->
{@source, @guard, @step} = source
constructor: (body, source) ->
{@source, @guard, @step, @name, @index} = source
@body = Expressions.wrap [body]
@raw = !!source.raw
@own = !!source.own
@object = !!source.object
[@name, @index] = [@index, @name] if @object
throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value
@range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length
@pattern = @name instanceof Value
throw SyntaxError 'cannot pattern match a range loop' if @range and @pattern
throw SyntaxError 'indexes do not apply to range loops' if @range and @index
throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern
@returns = false
children: ['body', 'source', 'guard', 'step']
isStatement: YES
jumps: While::jumps
makeReturn: ->
@returns = yes
this
containsPureStatement: While::containsPureStatement
# 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.
compileNode: (o) ->
body = Expressions.wrap [@body]
hasCode = body.contains (node) -> node instanceof Code
hasPure = last(body.expressions)?.containsPureStatement()
lastJumps = last(body.expressions)?.jumps()
@returns = no if lastJumps and lastJumps instanceof Return
source = if @range then @source.base else @source
scope = o.scope
name = @name and @name.compile o, LEVEL_LIST
index = @index and @index.compile o, LEVEL_LIST
unless hasCode
scope.find(name, immediate: yes) if name and not @pattern
scope.find(index, immediate: yes) if index
rvar = scope.freeVariable 'results' if @returns and not hasPure
scope.find(name, immediate: yes) if name and not @pattern
scope.find(index, immediate: yes) if index
rvar = scope.freeVariable 'results' if @returns
ivar = (if @range then name else index) or scope.freeVariable 'i'
name = ivar if @pattern
varPart = ''
guardPart = ''
defPart = ''
@@ -1441,38 +1470,36 @@ exports.For = class For extends Base
if @range
forPart = source.compile merge(o, {index: ivar, @step})
else
svar = @source.compile o, LEVEL_TOP
if (name or not @raw) and not IDENTIFIER.test svar
svar = @source.compile o, LEVEL_LIST
if (name or @own) and not IDENTIFIER.test svar
defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
svar = ref
namePart = if @pattern
new Assign(@name, new Literal "#{svar}[#{ivar}]").compile o, LEVEL_TOP
else if name
"#{name} = #{svar}[#{ivar}]"
if name and not @pattern
namePart = "#{name} = #{svar}[#{ivar}]"
unless @object
lvar = scope.freeVariable 'len'
stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++"
forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
if @returns and not hasPure
if @returns
resultPart = "#{@tab}#{rvar} = [];\n"
returnResult = '\n' + (new Return(new Literal(rvar)).compile o, LEVEL_PAREN)
returnResult = "\n#{@tab}return #{rvar};"
body = Push.wrap rvar, body
if @guard
body = Expressions.wrap [new If @guard, body]
if hasCode
body = Closure.wrap(body, yes)
if @pattern
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
defPart += @pluckDirectCall o, body
varPart = "\n#{idt1}#{namePart};" if namePart
if @object
forPart = "#{ivar} in #{svar}"
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw
defPart += @pluckDirectCall o, body, name, index unless @pattern
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
body = body.compile merge(o, indent: idt1), LEVEL_TOP
body = '\n' + body + '\n' if body
"""
#{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
"""
pluckDirectCall: (o, body, name, index) ->
pluckDirectCall: (o, body) ->
defs = ''
for expr, idx in body.expressions
expr = expr.unwrapAll()
@@ -1486,14 +1513,10 @@ exports.For = class For extends Base
fn = val.base?.unwrapAll() or val
ref = new Literal o.scope.freeVariable 'fn'
base = new Value ref
args = compact [name, index]
args.reverse() if @object
for arg, i in args
fn.params.push new Param args[i] = new Literal arg
if val.base
[val.base, base] = [base, val]
args.unshift new Literal 'this'
body.expressions[idx] = new Call base, args
body.expressions[idx] = new Call base, expr.args
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
defs
@@ -1507,6 +1530,11 @@ exports.Switch = class Switch extends Base
isStatement: YES
jumps: (o = {block: yes}) ->
for [conds, block] in @cases
return block if block.jumps o
@otherwise?.jumps o
makeReturn: ->
pair[1].makeReturn() for pair in @cases
@otherwise?.makeReturn()
@@ -1522,10 +1550,11 @@ exports.Switch = class Switch extends Base
code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n"
code += body + '\n' if body = block.compile o, LEVEL_TOP
break if i is @cases.length - 1 and not @otherwise
for expr in block.expressions by -1 when expr not instanceof Comment
code += idt2 + 'break;\n' unless expr instanceof Return
break
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @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'
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
code + @tab + '}'
#### If
@@ -1537,7 +1566,7 @@ exports.Switch = class Switch extends Base
# because ternaries are already proper expressions, and don't need conversion.
exports.If = class If extends Base
constructor: (condition, @body, options = {}) ->
@condition = if options.invert then condition.invert() else condition
@condition = if options.type is 'unless' then condition.invert() else condition
@elseBody = null
@isChain = false
{@soak} = options
@@ -1562,6 +1591,8 @@ exports.If = class If extends Base
o?.level is LEVEL_TOP or
@bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
jumps: (o) -> @body.jumps(o) or @elseBody?.jumps(o)
compileNode: (o) ->
if @isStatement o then @compileStatement o else @compileExpression o
@@ -1613,7 +1644,7 @@ exports.If = class If extends Base
# which is helpful for recording the result arrays from comprehensions.
Push =
wrap: (name, exps) ->
return exps if exps.isEmpty() or last(exps.expressions).containsPureStatement()
return exps if exps.isEmpty() or last(exps.expressions).jumps()
exps.push new Call new Value(new Literal(name), [new Access new Literal 'push']), [exps.pop()]
#### Closure
@@ -1625,7 +1656,7 @@ Closure =
# in which case, no dice. If the body mentions `this` or `arguments`,
# then make sure that the closure wrapper preserves the original values.
wrap: (expressions, statement, noReturn) ->
return expressions if expressions.containsPureStatement()
return expressions if expressions.jumps()
func = new Code [], Expressions.wrap [expressions]
args = []
if (mentionsArgs = expressions.contains @literalArgs) or
@@ -1634,13 +1665,15 @@ Closure =
args = [new Literal 'this']
args.push new Literal 'arguments' if mentionsArgs
func = new Value func, [new Access meth]
func.noReturn = noReturn
func.noReturn = noReturn
call = new Call func, args
if statement then Expressions.wrap [call] else call
literalArgs: (node) -> node instanceof Literal and node.value is 'arguments'
literalThis: (node) -> node instanceof Literal and node.value is 'this' or
node instanceof Code and node.bound
literalArgs: (node) ->
node instanceof Literal and node.value is 'arguments' and not node.asKey
literalThis: (node) ->
(node instanceof Literal and node.value is 'this' and not node.asKey) or
(node instanceof Code and node.bound)
# Unfold a node's child if soak, then tuck the node under created `If`
unfoldSoak = (o, parent, name) ->

View File

@@ -18,13 +18,18 @@ exports.OptionParser = class OptionParser
# Parse the list of arguments, populating an `options` object with all of the
# specified options, and returning it. `options.arguments` will be an array
# containing the remaining non-option arguments. This is a simpler API than
# many option parsers that allow you to attach callback actions for every
# flag. Instead, you're responsible for interpreting the options object.
# containing the remaining non-option arguments. `options.literals` will be
# an array of options that are meant to be passed through directly to the
# executing script. This is a simpler API than many option parsers that allow
# you to attach callback actions for every flag. Instead, you're responsible
# for interpreting the options object.
parse: (args) ->
options = arguments: []
options = arguments: [], literals: []
args = normalizeArguments args
for arg, i in args
if arg is '--'
options.literals = args[(i + 1)..]
break
isOption = !!(arg.match(LONG_FLAG) or arg.match(SHORT_FLAG))
matchedRule = no
for rule in @rules

View File

@@ -12,6 +12,10 @@ readline = require 'readline'
# Start by opening up **stdio**.
stdio = process.openStdin()
# Log an error.
error = (err) ->
stdio.write (err.stack or err.toString()) + '\n\n'
# Quick alias for quitting the REPL.
helpers.extend global, quit: -> process.exit(0)
@@ -23,9 +27,12 @@ run = (buffer) ->
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
console.log val if val isnt undefined
catch err
console.error err.stack or err.toString()
error err
repl.prompt()
# 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
repl.setPrompt 'coffee> '

View File

@@ -97,13 +97,13 @@ class exports.Rewriter
start = null
startIndent = 0
condition = (token, i) ->
{(i+1): one, (i+2): two, (i+3): three} = @tokens
[one, two, three] = @tokens[i + 1 .. i + 3]
return false if 'HERECOMMENT' is one?[0]
[tag] = token
(tag in ['TERMINATOR', 'OUTDENT'] and
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', '('])
one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
@scanTokens (token, i, tokens) ->
if (tag = token[0]) in EXPRESSION_START
@@ -113,17 +113,10 @@ class exports.Rewriter
start = stack.pop()
return 1
return 1 unless tag is ':' and
((ago2 = @tag i - 2) is ':' or
(ago1 = @tag i - 1) is ')' and @tag(start[1] - 1) is ':' or
stack[stack.length - 1]?[0] isnt '{')
((ago = @tag i - 2) is ':' or stack[stack.length - 1]?[0] isnt '{')
stack.push ['{']
idx = if ago1 is ')'
start[1]
else if ago2 is '@'
i - 2
else
i - 1
idx -= 2 if @tag(idx - 2) is 'HERECOMMENT'
idx = if ago is '@' then i - 2 else i - 1
idx -= 2 while @tag(idx - 2) is 'HERECOMMENT'
value = new String('{')
value.generated = yes
tok = ['{', value, token[2]]
@@ -142,22 +135,22 @@ class exports.Rewriter
@tokens.splice idx, 0, ['CALL_END', ')', token[2]]
@scanTokens (token, i, tokens) ->
tag = token[0]
noCall = yes if tag in ['CLASS', 'IF', 'UNLESS']
{(i-1): prev, (i+1): next} = tokens
noCall = yes if tag in ['CLASS', 'IF']
[prev, current, next] = tokens[i - 1 .. i + 1]
callObject = not noCall and tag is 'INDENT' and
next and next.generated and next[0] is '{' and
prev and prev[0] in IMPLICIT_FUNC
seenSingle = no
noCall = no if tag in LINEBREAKS
noCall = no if tag in LINEBREAKS
token.call = yes if prev and not prev.spaced and tag is '?'
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)
tokens.splice i, 0, ['CALL_START', '(', token[2]]
@detectEnd i + (if callObject then 2 else 1), (token, i) ->
return yes if not seenSingle and token.fromThen
@detectEnd i + 1, (token, i) ->
[tag] = token
seenSingle = yes if tag in ['IF', 'ELSE', 'UNLESS', '->', '=>']
return yes if not seenSingle and token.fromThen
seenSingle = yes if tag in ['IF', 'ELSE', '->', '=>']
return yes if tag in ['.', '?.', '::'] and @tag(i - 1) is 'OUTDENT'
not token.generated and @tag(i - 1) isnt ',' and tag in IMPLICIT_END and
(tag isnt 'INDENT' or
@@ -205,7 +198,7 @@ class exports.Rewriter
tagPostfixConditionals: ->
condition = (token, i) -> token[0] in ['TERMINATOR', 'INDENT']
@scanTokens (token, i) ->
return 1 unless token[0] in ['IF', 'UNLESS']
return 1 unless token[0] is 'IF'
original = token
@detectEnd i + 1, condition, (token, i) ->
original[0] = 'POST_' + original[0] if token[0] isnt 'INDENT'
@@ -224,7 +217,7 @@ class exports.Rewriter
openLine[open] = token[2] if levels[open]++ is 0
else if tag is close and --levels[open] < 0
throw Error "too many #{token[1]} on line #{token[2] + 1}"
for all open, level of levels when level > 0
for open, level of levels when level > 0
throw Error "unclosed #{ open } on line #{openLine[open] + 1}"
this
@@ -247,7 +240,7 @@ class exports.Rewriter
rewriteClosingParens: ->
stack = []
debt = {}
debt[key] = 0 for all key of INVERSES
debt[key] = 0 for key of INVERSES
@scanTokens (token, i, tokens) ->
if (tag = token[0]) in EXPRESSION_START
stack.push token
@@ -312,7 +305,7 @@ IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = [
'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS'
'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY',
'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', 'SUPER'
'@', '->', '=>', '[', '(', '{', '--', '++'
]
@@ -322,7 +315,7 @@ IMPLICIT_UNSPACED_CALL = ['+', '-']
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']
# Tokens that always mark the end of an implicit call for single-liners.
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT']
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT']
# Single-line flavors of block expressions that have unclosed endings.
# The grammar can't disambiguate them, so we insert the implicit indentation.

View File

@@ -20,45 +20,27 @@ exports.Scope = class Scope
constructor:(@parent, @expressions, @method) ->
@variables = [{name: 'arguments', type: 'arguments'}]
@positions = {}
if @parent
@garbage = @parent.garbage
else
@garbage = []
Scope.root = this
Scope.root = this unless @parent
# Adds a new variable or overrides an existing one.
add: (name, type) ->
add: (name, type, immediate) ->
return @parent.add name, type, immediate if @shared and not immediate
if typeof (pos = @positions[name]) is 'number'
@variables[pos].type = type
else
@positions[name] = @variables.push({name, type}) - 1
# Create a new garbage level
startLevel: ->
@garbage.push []
this
# Return to the previous garbage level and erase referenced temporary
# variables in current level from scope.
endLevel: ->
@add name, 'reuse' for name in @garbage.pop() when @type(name) is 'var'
this
# Look up a variable name in lexical scope, and declare it if it does not
# already exist.
find: (name, options) ->
return true if @check name, options
return yes if @check name, options
@add name, 'var'
false
# Test variables and return `true` the first time `fn(v)` returns `true`
any: (fn) ->
return yes for v in @variables when fn v
no
# Reserve a variable name as originating from a function parameter for this
# scope. No `var` required for internal references.
parameter: (name) ->
return if @shared and @parent.check name, yes
@add name, 'param'
# Just check to see if a variable has already been declared, without reserving,
@@ -77,50 +59,36 @@ exports.Scope = class Scope
# Gets the type of a variable.
type: (name) ->
for v in @variables when v.name is name then return v.type
return v.type for v in @variables when v.name is name
null
# If we need to store an intermediate result, find an available name for a
# compiler-generated variable. `_var`, `_var2`, and so on...
freeVariable: (type) ->
index = 0
index++ while @check((temp = @temporary type, index), true) and @type(temp) isnt 'reuse'
@add temp, 'var'
last(@garbage)?.push temp
index++ while @check((temp = @temporary type, index), true)
@add temp, 'var', yes
temp
# Ensure that an assignment is made at the top of this scope
# (or at the top-level scope, if requested).
assign: (name, value) ->
@add name, value: value, assigned: true
@hasAssignments = yes
# Does this scope reference any variables that need to be declared in the
# given function body?
hasDeclarations: (body) ->
body is @expressions and @any (v) -> v.type in ['var', 'reuse']
# Does this scope reference any assignments that need to be declared at the
# top of the given function body?
hasAssignments: (body) ->
body is @expressions and @any (v) -> v.type.assigned
# Does this scope have any declared variables?
hasDeclarations: ->
!!@declaredVariables().length
# Return the list of variables first declared in this scope.
declaredVariables: ->
usr = []
tmp = []
for v in @variables when v.type in ['var', 'reuse']
(if v.name.charAt(0) is '_' then tmp else usr).push v.name
usr.sort().concat tmp.sort()
realVars = []
tempVars = []
for v in @variables when v.type is 'var'
(if v.name.charAt(0) is '_' then tempVars else realVars).push v.name
realVars.sort().concat tempVars.sort()
# Return the list of assignments that are supposed to be made at the top
# of this scope.
assignedVariables: ->
("#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned)
# Compile the JavaScript for all of the variable declarations in this scope.
compiledDeclarations: ->
@declaredVariables().join ', '
# Compile the JavaScript for all of the variable assignments in this scope.
compiledAssignments: ->
@assignedVariables().join ', '
"#{v.name} = #{v.type.value}" for v in @variables when v.type.assigned

127
test/arguments.coffee Normal file
View File

@@ -0,0 +1,127 @@
# Arguments
# ---------
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
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]
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 "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)
#### Parameter List Features
test "splats", ->
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
arrayEq [2, 3], (((_, _, splat...) -> splat) 0, 1, 2, 3)
arrayEq [0, 1], (((splat..., _, _) -> splat) 0, 1, 2, 3)
arrayEq [2], (((_, _, splat..., _) -> splat) 0, 1, 2, 3)
test "@-parameters: automatically assign an argument's value to a property of the context", ->
nonce = {}
((@prop) ->).call context = {}, nonce
eq nonce, context.prop
# allow splats along side the special argument
((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
eq nonce, context.prop
# allow the argument itself to be a splat
((@prop...) ->).call context = {}, 0, nonce, 0
eq nonce, context.prop[1]
# the argument should still be able to be referenced normally
eq nonce, (((@prop) -> prop).call {}, nonce)
test "@-parameters and splats with constructors", ->
a = {}
b = {}
class Klass
constructor: (@first, splat..., @last) ->
obj = new Klass a, 0, 0, b
eq a, obj.first
eq b, obj.last
test "destructuring in function definition", ->
(([{a: [b], c}]...) ->
eq 1, b
eq 2, c
) {a: [1], c: 2}
test "default values", ->
nonceA = {}
nonceB = {}
a = (_,_,arg=nonceA) -> arg
eq nonceA, a()
eq nonceA, a(0)
eq nonceB, a(0,0,nonceB)
eq nonceA, a(0,0,undefined)
eq nonceA, a(0,0,null)
eq false , a(0,0,false)
eq nonceB, a(undefined,undefined,nonceB,undefined)
b = (_,arg=nonceA,_,_) -> arg
eq nonceA, b()
eq nonceA, b(0)
eq nonceB, b(0,nonceB)
eq nonceA, b(0,undefined)
eq nonceA, b(0,null)
eq false , b(0,false)
eq nonceB, b(undefined,nonceB,undefined)
c = (arg=nonceA,_,_) -> arg
eq nonceA, c()
eq 0, c(0)
eq nonceB, c(nonceB)
eq nonceA, c(undefined)
eq nonceA, c(null)
eq false , c(false)
eq nonceB, c(nonceB,undefined,undefined)
test "default values with @-parameters", ->
a = {}
b = {}
obj = f: (q = a, @p = b) -> q
eq a, obj.f()
eq b, obj.p
test "default values with splatted arguments", ->
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
eq 30, withSplats()
eq 15, withSplats(1)
eq 5, withSplats(1,1)
eq 1, withSplats(1,1,1)
eq 2, withSplats(1,1,1,1)

98
test/assignment.coffee Normal file
View File

@@ -0,0 +1,98 @@
# Assignment
# ----------
test "context property assignment (using @)", ->
nonce = {}
addMethod = ->
@method = -> nonce
this
eq nonce, addMethod.call({}).method()
test "unassignable values", ->
nonce = {}
for nonref in ['', '""', '0', 'f()'].concat CoffeeScript.RESERVED
eq nonce, (try CoffeeScript.compile "#{nonref} = v" catch e then nonce)
test "compound assignments should not declare", ->
# TODO: make description more clear
# TODO: remove reference to Math
eq Math, (-> Math or= 0)()
#### Statements as Expressions
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
nonce = {}
if a = nonce then 1
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
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
#### Compound Assignment
test "compound assignment (math operators)", ->
num = 10
num -= 5
eq 5, num
num *= 10
eq 50, num
num /= 10
eq 5, num
num %= 3
eq 2, num
test "more compound assignment", ->
a = {}
val = undefined
val ||= a
val ||= true
eq a, val
b = {}
val &&= true
eq val, true
val &&= b
eq b, val
c = {}
val = null
val ?= c
val ?= true
eq c, val
#### Destructuring Assignment
# NO TESTS?!
# TODO: make tests for destructuring assignment

18
test/break.coffee Normal file
View File

@@ -0,0 +1,18 @@
# 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()

201
test/comments.coffee Normal file
View File

@@ -0,0 +1,201 @@
# Comments
# --------
# Note: awkward spacing seen in some tests is likely intentional.
test "comments in objects", ->
obj1 = {
# comment
# comment
# comment
one: 1
# comment
two: 2
# comment
}
ok Object::hasOwnProperty.call(obj1,'one')
eq obj1.one, 1
ok Object::hasOwnProperty.call(obj1,'two')
eq obj1.two, 2
test "comments in YAML-style objects", ->
obj2 =
# comment
# comment
# comment
three: 3
# comment
four: 4
# comment
ok Object::hasOwnProperty.call(obj2,'three')
eq obj2.three, 3
ok Object::hasOwnProperty.call(obj2,'four')
eq obj2.four, 4
test "comments following operators that continue lines", ->
sum =
1 +
1 + # comment
1
eq 3, sum
test "comments in functions", ->
fn = ->
# comment
false
false # comment
false
# comment
# comment
true
ok fn()
fn2 = -> #comment
fn()
# comment
ok fn2()
test "trailing comment before an outdent", ->
nonce = {}
fn3 = ->
if true
undefined # comment
nonce
eq nonce, fn3()
test "comments in a switch", ->
nonce = {}
result = switch nonce #comment
# comment
when false then undefined
# comment
when null #comment
undefined
else nonce # comment
eq nonce, result
test "comment with conditional statements", ->
nonce = {}
result = if false # comment
undefined
#comment
else # comment
nonce
# comment
eq nonce, result
test "spaced comments with conditional statements", ->
nonce = {}
result = if false
undefined
# comment
else if false
undefined
# comment
else
nonce
eq nonce, result
#### Block Comments
###
This is a here-comment.
Kind of like a heredoc.
###
test "block comments in objects", ->
a = {}
b = {}
obj = {
a: a
###
comment
###
b: b
}
eq a, obj.a
eq b, obj.b
test "block comments in YAML-style", ->
a = {}
b = {}
obj =
a: a
###
comment
###
b: b
eq a, obj.a
eq b, obj.b
test "block comments in functions", ->
nonce = {}
fn1 = ->
true
###
false
###
ok fn1()
fn2 = ->
###
block comment
###
nonce
eq nonce, fn2()
fn3 = ->
nonce
###
block comment
###
eq nonce, fn3()
fn4 = ->
one = ->
###
block comment
###
two = ->
three = ->
nonce
eq nonce, fn4()()()()
test "block comments inside class bodies", ->
class A
a: ->
###
Comment
###
b: ->
ok A.prototype.b instanceof Function
class B
###
Comment
###
a: ->
b: ->
ok B.prototype.a instanceof Function

181
test/conditionals.coffee Normal file
View File

@@ -0,0 +1,181 @@
# 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

View File

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

96
test/helpers.coffee Normal file
View File

@@ -0,0 +1,96 @@
# Helpers
# -------
# pull the helpers from `CoffeeScript.helpers` into local variables
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
#### `starts`
test "the `starts` helper tests if a string starts with another string", ->
ok starts('01234', '012')
ok not starts('01234', '123')
test "the `starts` helper can take an optional offset", ->
ok starts('01234', '34', 3)
ok not starts('01234', '01', 1)
#### `ends`
test "the `ends` helper tests if a string ends with another string", ->
ok ends('01234', '234')
ok not ends('01234', '012')
test "the `ends` helper can take an optional offset", ->
ok ends('01234', '012', 2)
ok not ends('01234', '234', 6)
#### `compact`
test "the `compact` helper removes falsey values from an array, preserves truthy ones", ->
allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true]
truthyValues = [1, obj, [], ' ', -1, true]
arrayEq truthyValues, compact(allValues)
#### `count`
test "the `count` helper counts the number of occurances of a string in another string", ->
eq 1/0, count('abc', '')
eq 0, count('abc', 'z')
eq 1, count('abc', 'a')
eq 1, count('abc', 'b')
eq 2, count('abcdc', 'c')
eq 2, count('abcdabcd','abc')
#### `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]
obj = {}
merged = merge obj, ary
ok merged isnt obj
ok merged isnt ary
for own key, val of ary
eq val, merged[key]
#### `extend`
test "the `extend` helper performs a shallow copy", ->
ary = [0, 1, 2, 3]
obj = {}
# should return the object being extended
eq obj, extend(obj, ary)
# should copy the other object's properties as well (obviously)
eq 2, obj[2]
#### `flatten`
test "the `flatten` helper flattens an array", ->
success = yes
(success and= typeof n is 'number') for n in flatten [0, [[[1]], 2], 3, [4]]
ok success
#### `del`
test "the `del` helper deletes a property from an object and returns the deleted value", ->
obj = [0, 1, 2]
eq 1, del(obj, 1)
ok 1 not of obj
#### `last`
test "the `last` helper returns the last item of an array-like object", ->
ary = [0, 1, 2, 3, 4]
eq 4, last(ary)
test "the `last` helper allows one to specify an optional offset", ->
ary = [0, 1, 2, 3, 4]
eq 2, last(ary, 2)

18
test/importing.coffee Normal file
View File

@@ -0,0 +1,18 @@
# Importing
# ---------
unless window? or testingBrowser?
test "coffeescript modules can be imported and executed", ->
magicKey = __filename
magicValue = 0xFFFF
if global[magicKey]?
if exports?
local = magicValue
exports.method = -> local
else
global[magicKey] = {}
if require?.extensions? or require?.registerExtension?
ok require(__filename).method() is magicValue
delete global[magicKey]

225
test/operators.coffee Normal file
View File

@@ -0,0 +1,225 @@
# Operators
# ---------
test "binary (2-ary) math operators do not require spaces", ->
a = 1
b = -1
eq +1, a*-b
eq -1, a*+b
eq +1, a/-b
eq -1, a/+b
test "operators should respect new lines as spaced", ->
a = 123 +
456
eq 579, a
b = "1#{2}3" +
"456"
eq '123456', b
test "multiple operators should space themselves", ->
eq (+ +1), (- -1)
test "bitwise operators", ->
eq 2, (10 & 3)
eq 11, (10 | 3)
eq 9, (10 ^ 3)
eq 80, (10 << 3)
eq 1, (10 >> 3)
eq 1, (10 >>> 3)
num = 10; eq 2, (num &= 3)
num = 10; eq 11, (num |= 3)
num = 10; eq 9, (num ^= 3)
num = 10; eq 80, (num <<= 3)
num = 10; eq 1, (num >>= 3)
num = 10; eq 1, (num >>>= 3)
test "`instanceof`", ->
ok new String instanceof String
ok new Boolean instanceof Boolean
# `instanceof` supports negation by prefixing the operator with `not`
ok new Number not instanceof String
ok new Array not instanceof Boolean
#### Compound Assignment Operators
test "boolean operators", ->
nonce = {}
a = 0
a or= nonce
eq nonce, a
b = 1
b or= nonce
eq 1, b
c = 0
c and= nonce
eq 0, c
d = 1
d and= nonce
eq nonce, d
# 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
#### `is`,`isnt`,`==`,`!=`
test "`==` and `is` should be interchangeable", ->
a = b = 1
ok a is 1 and b == 1
ok a == b
ok a is b
test "`!=` and `isnt` should be interchangeable", ->
a = 0
b = 1
ok a isnt 1 and b != 0
ok a != b
ok a isnt b
#### `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`
test "in, of", ->
arr = [1]
ok 0 of arr
ok 1 in arr
# prefixing `not` to `in and `of` should negate them
ok 1 not of arr
ok 0 not in arr
test "`in` should be able to operate on an array literal", ->
ok 2 in [0, 1, 2, 3]
ok 4 not in [0, 1, 2, 3]
arr = [0, 1, 2, 3]
ok 2 in arr
ok 4 not in arr
# should cache the value used to test the array
arr = [0]
val = 0
ok val++ in arr
ok val++ not in arr
val = 0
ok val++ of arr
ok val++ not of arr
test "`of` and `in` should be able to operate on instance variables", ->
obj = {
list: [2,3]
in_list: (value) -> value in @list
not_in_list: (value) -> value not in @list
of_list: (value) -> value of @list
not_of_list: (value) -> value not of @list
}
ok obj.in_list 3
ok obj.not_in_list 1
ok obj.of_list 0
ok obj.not_of_list 2
test "#???: `in` with cache and `__indexOf` should work in argument lists", ->
eq 1, [Object() in Array()].length
test "#737: `in` should have higher precedence than logical operators", ->
eq 1, 1 in [1] and 1
test "#768: `in` should preserve evaluation order", ->
share = 0
a = -> share++ if share is 0
b = -> share++ if share is 1
c = -> share++ if share is 2
ok a() not in [b(),c()]
eq 3, share
#### Chainable Operators
test "chainable operators", ->
ok 100 > 10 > 1 > 0 > -1
ok -1 < 0 < 1 < 10 < 100
test "`is` and `isnt` may be chained", ->
ok true is not false is true is not false
ok 0 is 0 isnt 1 is 1
test "different comparison operators (`>`,`<`,`is`,etc.) may be combined", ->
ok 1 < 2 > 1
ok 10 < 20 > 2+3 is 5
test "some chainable operators can be negated by `unless`", ->
ok (true unless 0==10!=100)
test "operator precedence: `|` lower than `<`", ->
eq 1, 1 | 2 < 3 < 4
test "preserve references", ->
a = b = c = 1
# `a == b <= c` should become `a === b && b <= c`
# (this test does not seem to test for this)
ok a == b <= c
test "chained operations should evaluate each value only once", ->
a = 0
ok 1 > a++ < 1
test "#891: incorrect inversion of chained comparisons", ->
ok (true unless 0 > 1 > 2)
ok (true unless (NaN = 0/0) < 0/0 < NaN)

View File

@@ -0,0 +1,186 @@
# Ranges, Slices, and Splices
# ---------------------------
# 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
test "basic slicing", ->
arrayEq [7, 8, 9] , shared[7..9]
arrayEq [2, 3] , shared[2...4]
arrayEq [2, 3, 4, 5], shared[2...6]
test "slicing with variables as endpoints", ->
[a, b] = [1, 4]
arrayEq [1, 2, 3, 4], shared[a..b]
arrayEq [1, 2, 3] , shared[a...b]
test "slicing with expressions as endpoints", ->
[a, b] = [1, 3]
arrayEq [2, 3, 4, 5, 6], shared[(a+1)..2*b]
arrayEq [2, 3, 4, 5] , shared[a+1...(2*b)]
test "unbounded slicing", ->
arrayEq [7, 8, 9] , shared[7..]
arrayEq [8, 9] , shared[-2..]
arrayEq [9] , shared[-1...]
arrayEq [0, 1, 2] , shared[...3]
arrayEq [0, 1, 2, 3], shared[..-7]
arrayEq shared , shared[..-1]
arrayEq shared[0..8], shared[...-1]
for a in [-shared.length..shared.length]
arrayEq shared[a..] , shared[a...]
for a in [-shared.length+1...shared.length]
arrayEq shared[..a][...-1] , shared[...a]
test "#930, #835, #831, #746 #624: inclusive slices to -1 should slice to end", ->
arrayEq shared, shared[0..-1]
arrayEq shared, shared[..-1]
arrayEq shared.slice(1,shared.length), shared[1..-1]
test "string slicing", ->
str = "abcdefghijklmnopqrstuvwxyz"
ok str[1...1] is ""
ok str[1..1] is "b"
ok str[1...5] is "bcde"
ok str[0..4] is "abcde"
ok str[-5..] is "vwxyz"
#### Splices
test "basic splicing", ->
ary = [0..9]
ary[5..9] = [0, 0, 0]
arrayEq [0, 1, 2, 3, 4, 0, 0, 0], ary
ary = [0..9]
ary[2...8] = []
arrayEq [0, 1, 8, 9], ary
test "unbounded splicing", ->
ary = [0..9]
ary[3..] = [9, 8, 7]
arrayEq [0, 1, 2, 9, 8, 7]. ary
ary[...3] = [7, 8, 9]
arrayEq [7, 8, 9, 9, 8, 7], ary
test "splicing with variables as endpoints", ->
[a, b] = [1, 8]
ary = [0..9]
ary[a..b] = [2, 3]
arrayEq [0, 2, 3, 9], ary
ary = [0..9]
ary[a...b] = [5]
arrayEq [0, 5, 8, 9], ary
test "splicing with expressions as endpoints", ->
[a, b] = [1, 3]
ary = [0..9]
ary[ a+1 .. 2*b+1 ] = [4]
arrayEq [0, 1, 4, 8, 9], ary
ary = [0..9]
ary[a+1...2*b+1] = [4]
arrayEq [0, 1, 4, 7, 8, 9], ary
test "splicing to the end, against a one-time function", ->
ary = null
fn = ->
if ary
throw 'err'
else
ary = [1, 2, 3]
fn()[0..] = 1
arrayEq ary, [1]
test "the return value of a splice literal should be the RHS", ->
ary = [0, 0, 0]
eq (ary[0..1] = 2), 2
ary = [0, 0, 0]
eq (ary[0..] = 3), 3
arrayEq [ary[0..0] = 0], [0]

View File

@@ -0,0 +1,56 @@
# Regular Expressions
# -------------------
#TODO: add some rigorous regex interpolation tests
test "basic regular expression literals", ->
ok 'a'.match(/a/)
ok 'a'.match /a/
ok 'a'.match(/a/g)
ok 'a'.match /a/g
test "division is not confused for a regular expression", ->
eq 2, 4 / 2 / 1
a = 4
b = 2
g = 1
eq 2, a / b/g
obj = method: -> 2
two = 2
eq 2, (obj.method()/two + obj.method()/two)
i = 1
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']
test "#584: slashes are allowed unescaped in character classes", ->
ok /^a\/[/]b$/.test 'a//b'
#### Heregexe(n|s)
test "a heregex will ignore whitespace and comments", ->
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
^ I'm \x20+ [a] \s+
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 /(?:)/ + '', /// /// + ''

View File

@@ -34,15 +34,44 @@
stdout.appendChild div
msg
this.ok = (good, msg) ->
@test = (desc, fn) ->
fn()
@ok = (good, msg) ->
++total
if good then ++success else throw Error say msg
this.eq = (x, y, msg) -> ok x is y, msg ? x + ' !== ' + y
@eq = (x, y, msg) -> ok x is y, msg ? x + ' !== ' + y
arrayEqual = (a, b) ->
if a is b
# 0 isnt -0
a isnt 0 or 1/a is 1/b
else if a instanceof Array and b instanceof Array
return no unless a.length is b.length
return no for el, idx in a when not arrayEq el, b[idx]
yes
else
# NaN is NaN
a isnt a and b isnt b
@doesNotThrow = (fn) ->
fn()
ok true
@arrayEq = (a, b, msg) -> ok arrayEqual(a,b), msg
@throws = (fun, err, msg) ->
try
fun()
catch e
if err
eq e, err
else
ok yes
return
ok no
this.throws = (fun, err, msg) ->
try fun(); throw new String 'No Error'
catch e then eq e, err
CoffeeScript.run = (code, cb) ->
try Function(CoffeeScript.compile code, wrap: no)()
@@ -50,7 +79,7 @@
cb yes
run = (name) ->
CoffeeScript.load "test_#{name}.coffee", (yay) ->
CoffeeScript.load "#{name}.coffee", (yay) ->
say "#{ if yay then '\u2714' else '\u3000' } #{name}", yay
++failed unless yay
fin() if ++done is names.length
@@ -66,28 +95,29 @@
'arguments'
'assignment'
'break'
'chaining'
'classes'
'comments'
'compilation'
'comprehensions'
'existence'
'functions'
'exception_handling'
'helpers'
'heredocs'
'if'
'literals'
'operations'
'pattern_matching'
'regexps'
'returns'
'splats'
'strings'
'switch'
'try_catch'
'while'
'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'
]
</script>
</body>
</html>
</html>

View File

@@ -1,63 +0,0 @@
area = (x, y, x1, y1) ->
(x - x1) * (x - y1)
x = y = 10
x1 = y1 = 20
ok area(x, y, x1, y1) is 100
# ok(area(x, y,
# x1, y1) is 100)
ok(area(
x
y
x1
y1
) is 100)
sumOfArgs = ->
sum = 0
sum += val for val in arguments
sum
ok sumOfArgs(1, 2, 3, 4, 5) is 15
((@arg) ->).call context = {}, 1
ok context.arg is 1
((splat..., @arg) ->).call context, 1, 2, 3
eq context.arg, 3
((@arg...) ->).call context, 1, 2, 3
eq context.arg.join(' '), '1 2 3'
class Klass
constructor: (@one, @two) ->
obj = new Klass 1, 2
eq obj.one, 1
eq obj.two, 2
# Destructuring.
(([{a: [b], c}]...) ->
eq b, 123
eq c, 456
) {a: [123], c: 456}
# Default values.
obj = f: (q = 123, @p = 456) -> q
eq obj.f(), 123
eq obj.p , 456
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
eq 30, withSplats()
eq 15, withSplats 1
eq 5, withSplats 1, 1
eq 1, withSplats 1, 1, 1
eq 2, withSplats 1, 1, 1, 1

View File

@@ -1,72 +0,0 @@
# Can assign the result of a try/catch block.
result = try
nonexistent * missing
catch error
true
result2 = try nonexistent * missing catch error then true
ok result is true and result2 is true
# Can assign a conditional statement.
getX = -> 10
if x = getX() then 100
ok x is 10
x = if getX() then 100
ok x is 100
# This-assignment.
tester = ->
@example = -> 'example function'
this
ok tester().example() is 'example function'
try throw CoffeeScript.tokens 'in = 1'
catch e then eq e.message, 'Reserved word "in" on line 1 can\'t be assigned'
num = 10
num -= 5
eq num, 5
num *= 10
eq num, 50
num /= 10
eq num, 5
num %= 3
eq num, 2
val = false
val ||= 'value'
val ||= 'eulav'
eq val, 'value'
val &&= 'rehto'
val &&= 'other'
eq val, 'other'
val = null
val ?= 'value'
val ?= 'eulav'
eq val, 'value'
for nonref in ['""', '0', 'f()']
try
ok not CoffeeScript.compile "{k: #{nonref}} = v"
catch e
eq e.message, "\"#{nonref}\" cannot be assigned."
# Compound assignments should not declare.
eq Math, (-> Math or= 0)()

View File

@@ -1,28 +0,0 @@
# Test with break at the top level.
array = [1,2,3]
callWithLambda = (l) -> null
for i in array
result = callWithLambda(->)
if i == 2
console.log "i = 2"
else
break
ok result is null
# Test with break *not* at the top level.
someFunc = (input) ->
takesLambda = (l) -> null
for i in [1,2]
result = takesLambda(->)
if input == 1
return 1
else
break
return 2
ok someFunc(1) is 1
ok someFunc(2) is 2

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