Compare commits

...

159 Commits
0.9.6 ... 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
Michael Ficarra
5371268f8f Merge branch 'master' of http://github.com/jashkenas/coffee-script into refactorTests 2010-12-05 22:31:28 -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
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
106 changed files with 10521 additions and 3137 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,36 +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
startTime = Date.now()
currentFile = null
passedTests = 0
failures = []
for name, func of require 'assert'
# 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', ->
@@ -182,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,4 +1,6 @@
###
CoffeeScript Compiler v0.9.6
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

@@ -4,3 +4,4 @@ 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

@@ -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;
}
@@ -83,24 +86,28 @@ code, pre, tt, textarea {
}
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;
@@ -121,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;
}
@@ -158,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 {
@@ -252,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

@@ -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.6&#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

@@ -18,6 +18,7 @@ interactive REPL.</p> </td> <td class="code">
<span class="p">[</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--compile&#39;</span><span class="p">,</span> <span class="s1">&#39;compile to JavaScript and save as .js files&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-i&#39;</span><span class="p">,</span> <span class="s1">&#39;--interactive&#39;</span><span class="p">,</span> <span class="s1">&#39;run an interactive CoffeeScript REPL&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-o&#39;</span><span class="p">,</span> <span class="s1">&#39;--output [DIR]&#39;</span><span class="p">,</span> <span class="s1">&#39;set the directory for compiled JavaScript&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-j&#39;</span><span class="p">,</span> <span class="s1">&#39;--join&#39;</span><span class="p">,</span> <span class="s1">&#39;concatenate the scripts before compiling&#39;</span><span class="p">]</span>
<span class="p">[</span><span class="s1">&#39;-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>
@@ -27,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>
@@ -67,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>
@@ -93,14 +93,17 @@ requested options. If evaluating the script directly sets <code>__filename</code
<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">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-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="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>
@@ -112,7 +115,7 @@ 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>
@@ -135,17 +138,23 @@ any errors or warnings that arise.</p> </td> <td class="
<span class="s2">&quot;[#{tag} #{value}]&quot;</span>
<span class="nx">printLine</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
<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">printWarn</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">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-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">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>

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
@@ -185,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>
@@ -262,14 +260,14 @@ 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.own = </span><span class="nx">$1</span><span class="p">.</span><span class="nx">own</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>
@@ -313,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
@@ -381,8 +376,8 @@ 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)

View File

@@ -4,9 +4,10 @@ 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>

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

@@ -106,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="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>
@@ -163,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>
@@ -240,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,7 +11,8 @@ 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="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="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>
@@ -19,10 +20,9 @@ it wraps.</p> </td> <td class="code"> <div
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">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="vi">@hasDeclarations = </span><span class="kc">yes</span>
<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="k">return</span> <span class="k">if</span> <span class="nx">@shared</span> <span class="o">and</span> <span class="nx">@check</span> <span class="nx">name</span><span class="p">,</span> <span class="kc">yes</span>
<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>
@@ -37,17 +37,17 @@ walks up to the root scope.</p> </td> <td class="code">
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">freeVariable</span><span class="o">:</span> <span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="o">-&gt;</span>
<span class="nv">index = </span><span class="mi">0</span>
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">index</span><span class="p">),</span> <span class="kc">true</span><span class="p">)</span>
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">&#39;var&#39;</span>
<span class="vi">@hasDeclarations = </span><span class="kc">yes</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>
<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>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="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-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Return the list of assignments that are supposed to be made at the top
<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="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>

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,4 +1,4 @@
/*
CoffeeScript Compiler v0.9.6
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();

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,8 +1,9 @@
var globals, name, _results;
globals = (function() {
var globals, name;
globals = ((function() {
var _results;
_results = [];
for (name in window) {
_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,14 +1,15 @@
var age, ages, child, yearsOld, _results;
var age, ages, child, yearsOld;
yearsOld = {
max: 10,
ida: 9,
tim: 11
};
ages = function() {
ages = (function() {
var _results;
_results = [];
for (child in yearsOld) {
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

@@ -1,4 +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, 6 + 1);
middle = copy.slice(3, 7);

View File

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

View File

@@ -1,4 +1,4 @@
var lyrics, num, _results;
var lyrics, num;
if (this.studyingEconomics) {
while (supply > demand) {
buy();
@@ -8,10 +8,11 @@ if (this.studyingEconomics) {
}
}
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

File diff suppressed because one or more lines are too long

1293
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.6';
exports.VERSION = '1.0.0';
exports.RESERVED = RESERVED;
exports.helpers = require('./helpers');
exports.compile = compile = function(code, options) {
if (options == null) {

View File

@@ -1,5 +1,5 @@
(function() {
var ALL_SWITCHES, BANNER, CoffeeScript, DEPRECATED_SWITCHES, EventEmitter, SWITCHES, compileOptions, compileScript, compileScripts, compileStdio, exec, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, util, version, watch, writeJs, _ref;
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, 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');
@@ -16,15 +16,16 @@
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();
}
@@ -43,21 +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 base, compile, source, _fn, _i, _len, _results;
_fn = function(source) {
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) {
@@ -77,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;
};
@@ -155,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,
@@ -175,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() {
@@ -211,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];
@@ -220,27 +225,35 @@
_results.push("[" + tag + " " + value + "]");
}
return _results;
}();
})();
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 printWarn('--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() {
printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
return process.exit(0);

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: [
@@ -368,22 +368,22 @@
],
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.own = $1.own;
$2.vars = $1;
$2.name = $1[0];
$2.index = $1[1];
return $2;
})
],
@@ -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

@@ -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;
@@ -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)) {
@@ -447,35 +449,32 @@
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, _ref3;
@@ -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) {
@@ -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,})/;

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
}
return -1;
}, __slice = Array.prototype.slice;
exports.Rewriter = function() {
exports.Rewriter = (function() {
function Rewriter() {}
Rewriter.prototype.rewrite = function(tokens) {
this.tokens = tokens;
@@ -113,7 +113,7 @@
startIndent = 0;
condition = function(token, i) {
var one, tag, three, two, _ref, _ref2;
_ref = this.tokens.slice(i + 1, i + 3 + 1), one = _ref[0], two = _ref[1], three = _ref[2];
_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;
}
@@ -161,10 +161,10 @@
return this.scanTokens(function(token, i, tokens) {
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;
}
_ref = tokens.slice(i - 1, i + 1 + 1), prev = _ref[0], current = _ref[1], next = _ref[2];
_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) {
@@ -177,13 +177,13 @@
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,7 @@
(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;
@@ -18,8 +18,11 @@
Scope.root = this;
}
}
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 {
@@ -34,11 +37,10 @@
return true;
}
this.add(name, 'var');
this.hasDeclarations = true;
return false;
};
Scope.prototype.parameter = function(name) {
if (this.shared && this.check(name, true)) {
if (this.shared && this.parent.check(name, true)) {
return;
}
return this.add(name, 'param');
@@ -75,8 +77,7 @@
while (this.check((temp = this.temporary(type, index)), true)) {
index++;
}
this.add(temp, 'var');
this.hasDeclarations = true;
this.add(temp, 'var', true);
return temp;
};
Scope.prototype.assign = function(name, value) {
@@ -86,6 +87,9 @@
});
return this.hasAssignments = true;
};
Scope.prototype.hasDeclarations = function() {
return !!this.declaredVariables().length;
};
Scope.prototype.declaredVariables = function() {
var realVars, tempVars, v, _i, _len, _ref;
realVars = [];
@@ -112,5 +116,5 @@
return _results;
};
return Scope;
}();
})();
}).call(this);

View File

@@ -3,13 +3,13 @@
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language", "coffeescript", "compiler"],
"author": "Jeremy Ashkenas",
"version": "0.9.6",
"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

@@ -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.6'
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

@@ -30,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']
@@ -39,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.
@@ -60,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
@@ -91,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
@@ -132,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`.
@@ -148,7 +151,7 @@ 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 = ->
@@ -180,17 +183,26 @@ printTokens = (tokens) ->
# 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']
printWarn '--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.

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.
@@ -286,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.
@@ -417,14 +415,14 @@ 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.own = $1.own; $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: [
@@ -483,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
]
@@ -493,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.
@@ -565,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

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.

View File

@@ -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,7 +500,7 @@ 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'
]
@@ -514,15 +521,17 @@ COFFEE_KEYWORDS.push op for 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,7 +242,7 @@ 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
@@ -245,7 +250,7 @@ exports.Expressions = class Expressions extends Base
post = @compileNode o
{scope} = o
if scope.expressions is this
if not o.globals and o.scope.hasDeclarations
if 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"
@@ -266,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 + '"'
@@ -297,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
@@ -342,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
@@ -411,7 +419,6 @@ exports.Value = class Value extends Base
exports.Comment = class Comment extends Base
constructor: (@comment) ->
isPureStatement: YES
isStatement: YES
makeReturn: THIS
@@ -550,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'
@@ -657,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
@@ -677,8 +694,7 @@ exports.Obj = class Obj extends Base
props = @properties
return (if @front then '({})' else '{}') unless props.length
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
''
@@ -689,8 +705,10 @@ 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 }}"
@@ -731,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']
@@ -747,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
@@ -823,7 +843,7 @@ exports.Class = class Class extends Base
@body.expressions.push lname
@addBoundFunctions o
klass = new Parens new Call(new Code [], @body), true
klass = new Parens Closure.wrap(@body), true
klass = new Assign @variable, klass if @variable
klass.compile o
@@ -832,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]*)$/
@@ -862,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})"
@@ -932,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})"
@@ -947,18 +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 = "#{name}.length" unless range.to
unless to
if range.from and range.from.isSimpleNumber() and range.to.isSimpleNumber()
to = (+range.to.compile(o)) - +from + +plus
{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 = range.to.compile(o) + ' - ' + from + plus
val = @value.compile(o)
"[].splice.apply(#{name}, [#{from}, #{to}].concat(#{val}))"
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
@@ -976,15 +1003,16 @@ 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 = sharedScope or new Scope o.scope, @body, this
o.scope.shared = yes if sharedScope
o.scope = new Scope o.scope, @body, this
o.scope.shared = del o, 'sharedScope'
o.indent += TAB
delete o.bare
delete o.globals
@@ -998,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
@@ -1019,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`.
@@ -1114,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
@@ -1140,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
@@ -1151,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
@@ -1173,6 +1200,8 @@ exports.Op = class Op extends Base
children: ['first', 'second']
isSimpleNumber: NO
isUnary: ->
not @second
@@ -1228,7 +1257,6 @@ exports.Op = class Op extends Base
compileChain: (o) ->
[@first.second, shared] = @first.second.cache o
fst = @first.compile o, LEVEL_OP
fst = fst.slice 1, -1 if @first.unwrap() instanceof Op and @first.isChainable() and fst.charAt(0) is '('
code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"
"(#{code})"
@@ -1296,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
@@ -1325,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
@@ -1377,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
@@ -1391,8 +1423,8 @@ 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]
@own = !!source.own
@object = !!source.object
@@ -1408,28 +1440,29 @@ exports.For = class For extends Base
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
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
rvar = scope.freeVariable 'results' if @returns
ivar = (if @range then name else index) or scope.freeVariable 'i'
name = ivar if @pattern
varPart = ''
guardPart = ''
defPart = ''
@@ -1437,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
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;" if @own
defPart += @pluckDirectCall o, body, name, index unless @pattern
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()
@@ -1482,15 +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
o.sharedScope = o.scope
body.expressions[idx] = new Call base, expr.args
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
defs
@@ -1504,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()
@@ -1519,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
@@ -1534,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
@@ -1559,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
@@ -1610,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
@@ -1622,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
@@ -1631,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

@@ -135,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']
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
@@ -198,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'
@@ -305,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'
'@', '->', '=>', '[', '(', '{', '--', '++'
]
@@ -315,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

@@ -23,7 +23,8 @@ exports.Scope = class Scope
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
@@ -34,13 +35,12 @@ exports.Scope = class Scope
find: (name, options) ->
return yes if @check name, options
@add name, 'var'
@hasDeclarations = yes
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 @check name, yes
return if @shared and @parent.check name, yes
@add name, 'param'
# Just check to see if a variable has already been declared, without reserving,
@@ -67,8 +67,7 @@ exports.Scope = class Scope
freeVariable: (type) ->
index = 0
index++ while @check((temp = @temporary type, index), true)
@add temp, 'var'
@hasDeclarations = yes
@add temp, 'var', yes
temp
# Ensure that an assignment is made at the top of this scope
@@ -77,6 +76,10 @@ exports.Scope = class Scope
@add name, value: value, assigned: true
@hasAssignments = yes
# Does this scope have any declared variables?
hasDeclarations: ->
!!@declaredVariables().length
# Return the list of variables first declared in this scope.
declaredVariables: ->
realVars = []

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

View File

@@ -1,3 +1,11 @@
# Chaining
# --------
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
# Basic chained function calls.
identityWrap = (x) ->
-> x
@@ -57,8 +65,6 @@ func(
[[]]]],
[]])
id = (x) -> x
greeting = id(
"""
Hello

View File

@@ -39,17 +39,19 @@ ok result is '9two/three/four'
ok (new ThirdChild).array.join(' ') is '1 2 3'
identity = (f) -> f
class TopClass
constructor: (arg) ->
@prop = 'top-' + arg
class SuperClass extends TopClass
constructor: (arg) ->
super 'super-' + arg
identity super 'super-' + arg
class SubClass extends SuperClass
constructor: ->
super 'sub'
identity super 'sub'
ok (new SubClass).prop is 'top-super-sub'
@@ -346,3 +348,25 @@ class A
a = new A
eq a.captured().x, 10
eq a.captured().y, 2
# Issue #924: Static methods in nested classes.
class A
@B: class
@c = -> 5
eq A.B.c(), 5
# `class extends this` ...
class A
func: -> 'A'
B = null
makeClass = ->
B = class extends this
func: -> super + ' B'
makeClass.call A
eq (new B()).func(), 'A B'

View File

@@ -1,158 +0,0 @@
# comment before a ...
###
... block comment.
###
# comment
func = ->
# comment
false
false # comment
false
# comment
true
switch 'string'
# comment
when false then something()
# comment
when null
somethingElse()
->
code()
# comment
ok func()
func
func
# Line3
obj = {
# comment
# comment
# comment
one: 1
# comment
two: 2
# comment
}
result = if true # comment
false
ok not result
result = if false
false
else # comment
45
ok result is 45
test =
'test ' +
'test ' + # comment
'test'
ok test is 'test test test'
###
This is a here-comment.
Kind of like a heredoc.
###
func = ->
###
Another block comment.
###
code
func = ->
one = ->
two = ->
three = ->
###
block.
###
four = ->
fn1 = ->
oneLevel = null
###
This isn't fine.
###
ok ok
obj = {
a: 'b'
###
comment
###
c: 'd'
}
# Spaced comments in if / elses.
result = if false
1
# comment
else if false
2
# comment
else
3
ok result is 3
result = switch 'z'
when 'z' then 7
# comment
ok result is 7
# Trailing-line comment before an outdent.
func = ->
if true
true # comment
7
ok func() is 7
# Trailing herecomment in a function.
fn = ->
code
###
debug code commented
###
fn2 = ->
class A
b: ->
###
Comment
###
c: ->
ok A.prototype.c instanceof Function
class A
###
Comment
###
b: ->
c: ->
ok A.prototype.b instanceof Function

View File

@@ -13,3 +13,14 @@ catch e then eq e.message, 'unclosed CALL_START on line 1'
eq CoffeeScript.compile('for k of o then', bare: on, globals: on),
'for (k in o) {}'
# Compilations that should fail.
cantCompile = (code) ->
throws -> CoffeeScript.compile code
cantCompile 'a = (break)'
cantCompile 'a = (return 5 for item in list)'
cantCompile 'a = (return 5 while condition)'
cantCompile 'a = for x in y\n return 5'

View File

@@ -76,7 +76,7 @@ all = 1
# Ensure that the closure wrapper preserves local variables.
obj = {}
for method in ['one', 'two', 'three']
for method in ['one', 'two', 'three'] then do (method) ->
obj[method] = ->
"I'm " + method
@@ -84,6 +84,8 @@ ok obj.one() is "I'm one"
ok obj.two() is "I'm two"
ok obj.three() is "I'm three"
# Index values at the end of a loop.
i = 0
for i in [1..3]
-> 'func'
@@ -93,9 +95,10 @@ ok i is 4
# Ensure that local variables are closed over for range comprehensions.
funcs = for i in [1..3]
-> -i
do (i) ->
-> -i
ok (func() for func in funcs).join(' ') is '-1 -2 -3'
eq (func() for func in funcs).join(' '), '-1 -2 -3'
ok i is 4
@@ -103,7 +106,8 @@ ok i is 4
list = ['one', 'two', 'three']
methods = for num, i in list when num isnt 'two' and i isnt 1
-> num + ' ' + i
do (num, i) ->
-> num + ' ' + i
ok methods.length is 2
ok methods[0]() is 'one 0'
@@ -114,18 +118,20 @@ ok methods[1]() is 'three 2'
funcs = []
for i in [1..3]
x = i * 2
((z)->
funcs.push -> z + ' ' + i
)(x)
do (i) ->
x = i * 2
((z)->
funcs.push -> z + ' ' + i
)(x)
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
funcs = []
results = for i in [1..3]
z = (x * 3 for x in [1..i])
((a, b, c) -> [a, b, c].join(' ')).apply this, z
do (i) ->
z = (x * 3 for x in [1..i])
((a, b, c) -> [a, b, c].join(' ')).apply this, z
ok results.join(', ') is '3 , 3 6 , 3 6 9'
@@ -135,6 +141,29 @@ array = [0..10]
ok(num % 2 is 0 for num in array by 2)
# Nested shared scopes.
foo = ->
for i in [0..7]
do (i) ->
for j in [0..7]
do (j) ->
-> i + j
eq foo()[3][4](), 7
# Scoped loop pattern matching.
a = [[0], [1]]
funcs = []
for [v] in a
do (v) ->
funcs.push -> v
eq funcs[0](), 0
eq funcs[1](), 1
# Nested comprehensions.
multiLiner =
for x in [3..5]
@@ -221,23 +250,69 @@ odds = while i--
ok odds.join(', ') is '5, 3, 1'
# Nested shared scopes.
foo = ->
for i in [0..7]
for j in [0..7]
-> i + j
eq foo()[3][4](), 7
# Issue #897: Ensure that plucked function variables aren't leaked.
facets = {}
list = ['one', 'two']
(->
for entity in list
facets[entity] = -> entity
facets[entity] = -> entity
)()
eq typeof entity, 'undefined'
eq facets['two'](), 'two'
# Issue #905. Soaks as the for loop subject.
a = {b: {c: [1, 2, 3]}}
for d in a.b?.c
e = d
eq e, 3
# Issue #948. Capturing loop variables.
funcs = []
list = ->
[1, 2, 3]
for y in list()
do (y) ->
z = y
funcs.push -> "y is #{y} and z is #{z}"
eq funcs[1](), "y is 2 and z is 2"
# Cancel the comprehension if there's a jump inside the loop.
result = try
for i in [0...10]
continue if i < 5
i
eq result, 10
# Comprehensions over break.
arrayEq (break for [1..10]), []
# Comprehensions over continue.
arrayEq (break for [1..10]), []
# Comprehensions over function literals.
a = 0
for f in [-> a = 1]
do (f) ->
do f
eq a, 1
# Comprehensions that mention arguments.
list = [arguments: 10]
args = for f in list
do (f) ->
f.arguments
eq args[0], 10

View File

@@ -22,18 +22,18 @@ obj = {
name: 'Fred'
bound: ->
(=> eq this, obj)()
do (=> eq this, obj)
unbound: ->
(-> ok this isnt obj)()
do (-> ok this isnt obj)
nested: ->
(=>
(=>
do (=>
(=>
eq this, obj
)()
)()
)
)()
}
@@ -366,4 +366,14 @@ class Foo
new Foo().bar([101]...)
eq x, 101
eq x, 101
test "#904: Destructuring function arguments with same-named variables in scope", ->
a = b = nonce = {}
fn = ([a,b]) -> {a:a,b:b}
result = fn([c={},d={}])
eq c, result.a
eq d, result.b
eq nonce, a
eq nonce, b

View File

@@ -1,39 +0,0 @@
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
array = [0, 1, 2, 3, 4]
string = array.join ''
object = {}
# Test `starts`
ok starts string, '012'
ok starts string, '34', 3
ok not starts string, '42'
ok not starts string, '42', 6
# Test `ends`
ok ends string, '234'
ok ends string, '01', 3
ok not ends string, '42'
ok not ends string, '42', 6
# Test `merge`
merged = merge object, array
ok merged isnt object
eq merged[3], 3
# Test `extend`
ok object is extend object, array
eq object[3], 3
# Test `flatten`
ay = yes
(ay and= typeof n is 'number') for n in flatten [0, [[1], 2], 3, [4]]
ok ay
# Test `del`
eq 1, del object, 1
ok 1 not of object
# Test `last`
eq 4, last array
eq 2, last array, 2

View File

@@ -1,149 +0,0 @@
a = b = d = true
c = false
result = if a
if b
if c then false else
if d
true
ok result
first = if false then false else second = if false then false else true
ok first
ok second
result = if false
false
else if NaN
false
else
true
ok result
# Testing unless.
result = unless true
10
else
11
ok result is 11
# Nested inline if statements.
echo = (x) -> x
result = if true then echo((if false then 'xxx' else 'y') + 'a')
ok result is 'ya'
# Testing inline funcs with inline if-elses.
func = -> if 1 < 0.5 then 1 else -1
ok func() is -1
# Testing empty or commented if statements ... should compile:
result = if false
else if false
else
ok result is undefined
result = if false
# comment
else if true
# comment
else
ok result is undefined
# Return an if with no else.
func = ->
return if false then callback()
ok func() is undefined
func = ->
return unless false then 100 else -100
ok func() is 100
ident = (x) -> x
result = ident if false then 300 else 100
ok result is 100
# If-to-ternary with instanceof requires parentheses (no comment).
if {} instanceof Object
ok yes
else
ok no
try
{} + {}
ok yes
catch e
ok no
# If-to-ternary as part of a larger operation requires parens.
x = 1
result = x + if false then 10 else 1
ok result is 2
# If/else indented within an assignment.
func = ->
a =
if false
3
else
5
101
a
ok func() is 5
# Unmatched 'then' should catch implicit calls.
i = 1
isTrue = (x) -> x is true
if isTrue yes then i += 1
ok i is 2
# If/else with a suppressed indentation via assignment.
result =
if false then 10
else if no then 20
else if 0 then 30
else if NaN then 40
else 50 +
if false then 10
else 20
ok result is 70
if 'tight formatting with leading `then` is allowed'
then ok 'yay'
else throw 'boo'
# Issue #738
func = if true then -> 1
eq func(), 1
# Issue #748. Trailing reserved identifiers.
obj = delete: true
result = if obj.delete
101
ok result is 101

View File

@@ -1,3 +0,0 @@
# Check if we can import and execute a CoffeeScript-only module successfully.
if require?.extensions? or require?.registerExtension?
ok require('./test_module').func() is "from over there"

View File

@@ -140,6 +140,7 @@ ok obj.fn() is null
# Implicit arguments to function calls:
func = (obj) -> obj.a
func2 = -> arguments
result = func
a: 10
@@ -159,6 +160,27 @@ obj =
ok obj.one is 'one'
ok obj.two is 'three'
a = b = undefined
result = func
b:1
a
ok result is undefined
result = func
a:
b:2
b:1
ok result.b is 2
result = func2
a:1
b
c:1
ok result.length is 3
ok result[2].c is 1
# Implicit objects with wacky indentation:
obj =

View File

@@ -1,4 +0,0 @@
# This file is imported by `testImporting.coffee`
if exports?
local = "from over there"
exports.func = -> local

View File

@@ -1,184 +0,0 @@
# CoffeeScript's operations should be chainable, like Python's.
ok 500 > 50 > 5 > -5
# Some chainable operators can be negated by `unless`
ok (true unless 0==10!=100)
ok true is not false is true is not false
ok 0 is 0 isnt 50 is 50
ok 10 < 20 > 10
ok 50 > 10 > 5 is parseInt('5', 10)
eq 1, 1 | 2 < 3 < 4
ok 1 == 1 <= 1, '`x == y <= z` should become `x === y && y <= z`'
i = 0
ok 1 > i++ < 1, 'chained operations should evaluate each value only once'
# `==` and `is` should be interchangeable.
a = b = 1
ok a is 1 and b is 1
ok a == b
ok a is b
# Allow "if x not in y"
obj = {a: true}
ok 'a' of obj
ok 'b' not of obj
# And for "a in b" with array presence.
ok 200 in [100, 200, 300]
array = [100, 200, 300]
ok 200 in array
ok 1 not in array
ok array[0]++ in [99, 100], 'should cache testee'
# And with array presence on an instance variable.
obj = {
list: [1, 2, 3, 4, 5]
in_list: (value) -> value in @list
}
ok obj.in_list 4
ok not obj.in_list 0
# Non-spaced values still work.
x = 10
y = -5
ok x*-y is 50
ok x*+y is -50
# Compound operators.
one = 1
two = 0
one or= 2
two or= 2
eq one, 1
eq two, 2
zero = 0
zero and= 'one'
one and= 'one'
eq zero, 0
eq one , 'one'
# Compound assignment should be careful about caching variables.
count = 0
list = []
list[++count] or= 1
eq list[1], 1
eq count, 1
list[++count] ?= 2
eq list[2], 2
eq count, 2
list[count++] and= 'two'
eq list[2], 'two'
eq count, 3
base = -> ++count; base
base().four or= 4
eq base.four, 4
eq count, 4
base().five ?= 5
eq base.five, 5
eq count, 5
# Ensure that RHS is treated as a group.
a = b = false
a and= b or true
ok a is false
# Bitwise operators:
ok (10 & 3) is 2
ok (10 | 3) is 11
ok (10 ^ 3) is 9
ok (10 << 3) is 80
ok (10 >> 3) is 1
ok (10 >>> 3) is 1
num = 10; ok (num <<= 3) is 80
num = 10; ok (num >>= 3) is 1
num = 10; ok (num >>>= 3) is 1
num = 10; ok (num &= 3) is 2
num = 10; ok (num ^= 3) is 9
num = 10; ok (num |= 3) is 11
# Compound assignment with implicit objects.
obj = undefined
obj ?=
one: 1
ok obj.one is 1
obj and=
two: 2
ok not obj.one
ok obj.two is 2
# Compound assignment as a sub expression.
[a, b, c] = [1, 2, 3]
ok (a + b += c) is 6
ok a is 1
ok b is 5
ok c is 3
# Instanceof.
ok new String instanceof String
ok new Number not instanceof String
#737: `in` should have higher precedence than logical operators.
eq 1, 1 in [1] and 1
#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()] and share is 3
# `in` with cache and `__indexOf` should work in commaed lists.
eq [Object() in Array()].length, 1
# Operators should respect new lines as spaced.
a = (123) +
456
ok a is 579
a = "1#{2}3" +
"456"
ok a is '123456'
# Multiple operators should space themselves.
ok + +1 is - -1
#891: incorrect inversion of chained comparisons
(->
ok (true unless 0 > 1 > 2)
ok (true unless (NaN = 0/0) < 0/0 < NaN)
)()

View File

@@ -1,74 +0,0 @@
# # Slice.
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a = array[7..9]
b = array[2...4]
result = a.concat(b).join(' ')
ok result is "7 8 9 2 3"
a = [0, 1, 2, 3, 4, 5, 6, 7]
eq a[2...6].join(' '), '2 3 4 5'
# Ranges.
countdown = [10..1].join(' ')
ok countdown is "10 9 8 7 6 5 4 3 2 1"
a = 1
b = 5
nums = [a...b]
ok nums.join(' ') is '1 2 3 4'
b = -5
nums = [a..b]
ok nums.join(' ') is '1 0 -1 -2 -3 -4 -5'
# Expression-based range.
array = [(1+5)..1+9]
ok array.join(' ') is "6 7 8 9 10"
array = [5..1]
ok array.join(' ') is '5 4 3 2 1'
array = [30...0]
ok (len = array.length) is 30
ok array[len - 1] is 1
# String slicing (at least on Node).
hello = "Hello World"
ok hello[1...1] is ""
ok hello[1..1] is "e"
ok hello[1...5] is "ello"
ok hello[0..4] is "Hello"
# Splice literals.
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
array[5..10] = [0, 0, 0]
ok array.join(' ') is '0 1 2 3 4 0 0 0'
# Slices and splices that omit their beginning or end.
array = [0..10]
ok array[7..].join(' ') is '7 8 9 10'
ok array[-2..].join(' ') is '9 10'
ok array[...3].join(' ') is '0 1 2'
ok array[..-5].join(' ') is '0 1 2 3 4 5 6'
array[3..] = [9, 8, 7]
ok array.join(' ') is '0 1 2 9 8 7'
array[...3] = [7, 8, 9]
ok array.join(' ') is '7 8 9 9 8 7'

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