mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 01:07:55 -05:00
Compare commits
303 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a652a9736 | ||
|
|
1f69200d06 | ||
|
|
9f89a83c27 | ||
|
|
178af9de56 | ||
|
|
e7854bec09 | ||
|
|
9b9612e09c | ||
|
|
d2d02bf91d | ||
|
|
860c5030d2 | ||
|
|
2d54fea90c | ||
|
|
5ee0254ce5 | ||
|
|
37019dab1c | ||
|
|
2b31f28f8f | ||
|
|
8931e31991 | ||
|
|
813efbe1d3 | ||
|
|
7790df0df6 | ||
|
|
c2b32df22b | ||
|
|
479a2e0383 | ||
|
|
471cf1d51a | ||
|
|
ecdaad2fd6 | ||
|
|
3e20622bd5 | ||
|
|
8a4a28bd33 | ||
|
|
8fe59ed888 | ||
|
|
1927213174 | ||
|
|
cb8e147212 | ||
|
|
07baed89ed | ||
|
|
af1cf3400e | ||
|
|
eb53670676 | ||
|
|
709dc73c27 | ||
|
|
14e09d2ca8 | ||
|
|
0353b0ddd3 | ||
|
|
f2ba08f77f | ||
|
|
1d7d8cb4d2 | ||
|
|
6e9cfd8a33 | ||
|
|
2a9fd34a03 | ||
|
|
b1111c96ca | ||
|
|
55383155e5 | ||
|
|
bb1502a9d7 | ||
|
|
40ee30ecde | ||
|
|
4ff00359b6 | ||
|
|
f433fa4187 | ||
|
|
594ead00e8 | ||
|
|
5adf3b8865 | ||
|
|
4fc52cd08e | ||
|
|
4af47f0c26 | ||
|
|
9d3510a1e4 | ||
|
|
18f6ad9583 | ||
|
|
4c70ea5e09 | ||
|
|
d32c060e05 | ||
|
|
caa3d1ab5d | ||
|
|
d3e809da38 | ||
|
|
5ab892d009 | ||
|
|
54dbc0fdf8 | ||
|
|
003f91d43d | ||
|
|
83806a4d77 | ||
|
|
c4324f1db2 | ||
|
|
b9c3e0e640 | ||
|
|
60e51a238d | ||
|
|
fff4c9c672 | ||
|
|
18ab569b2d | ||
|
|
2951d34dc0 | ||
|
|
0cc5379caa | ||
|
|
f6fcfa831c | ||
|
|
c93fc3ec76 | ||
|
|
7b5f012f79 | ||
|
|
22cee5d2d6 | ||
|
|
0f18dff464 | ||
|
|
e38aeefb5c | ||
|
|
baa983ac33 | ||
|
|
cd65c66cf9 | ||
|
|
dc272a680b | ||
|
|
6f64fc266d | ||
|
|
73af3b17b1 | ||
|
|
8b2884e40f | ||
|
|
f0c22f390d | ||
|
|
11f2cd4515 | ||
|
|
5ce7984a2b | ||
|
|
9699059226 | ||
|
|
9941c3f045 | ||
|
|
25e7eeac8f | ||
|
|
277e82bd03 | ||
|
|
a1f1afe3ed | ||
|
|
0f523de212 | ||
|
|
47f12c453a | ||
|
|
dfcff3f0fc | ||
|
|
522f2ee3b3 | ||
|
|
8ce1fdb5bb | ||
|
|
a0efdac8ce | ||
|
|
22bc54f974 | ||
|
|
e240621a72 | ||
|
|
35c2a72ad2 | ||
|
|
10ec1a659f | ||
|
|
1fb34e42a6 | ||
|
|
7082000e66 | ||
|
|
79fff367c2 | ||
|
|
9cbf2a82ec | ||
|
|
6a40807330 | ||
|
|
8d6e33c2cf | ||
|
|
085874d5f3 | ||
|
|
94fb7e32ea | ||
|
|
042f7ec791 | ||
|
|
e4f47a05f6 | ||
|
|
bbf37e5229 | ||
|
|
454aa8433b | ||
|
|
bbf1c6a8df | ||
|
|
8e5eff5e1e | ||
|
|
e64fa71185 | ||
|
|
c8845643e5 | ||
|
|
371ff5e726 | ||
|
|
19520d8d35 | ||
|
|
abb11a7c0e | ||
|
|
2ac74356bd | ||
|
|
004f13f0fc | ||
|
|
395a97ef07 | ||
|
|
01b0cfc8ab | ||
|
|
f3758e4af0 | ||
|
|
2563324ed8 | ||
|
|
d91ccd4003 | ||
|
|
15ddb8e2ea | ||
|
|
c056c93e19 | ||
|
|
9e32a5bfa1 | ||
|
|
cd5c41f351 | ||
|
|
b780d707ab | ||
|
|
84ae563368 | ||
|
|
dddc7c6edb | ||
|
|
bd8d82809b | ||
|
|
51b7142805 | ||
|
|
6c9ef76b95 | ||
|
|
a024ec5b27 | ||
|
|
2212e959ac | ||
|
|
d4d027159f | ||
|
|
a8a581acae | ||
|
|
9e4fa02cdb | ||
|
|
6d6e07604e | ||
|
|
dc499089e9 | ||
|
|
f4b8e19c7f | ||
|
|
1809c0e675 | ||
|
|
d11d69958f | ||
|
|
6d2733405d | ||
|
|
2dc2d162bc | ||
|
|
56b2b02637 | ||
|
|
d031c26229 | ||
|
|
4046fcf971 | ||
|
|
7a4fd2ec01 | ||
|
|
73731ba155 | ||
|
|
8781a148db | ||
|
|
0e978a0d99 | ||
|
|
ac46ede170 | ||
|
|
ad669fc23a | ||
|
|
b9d3bc5b44 | ||
|
|
fa2ed81485 | ||
|
|
ea4a723379 | ||
|
|
71bcdb91c8 | ||
|
|
08294dc4d6 | ||
|
|
09712603c4 | ||
|
|
2fb7ccc8f0 | ||
|
|
31bfe50831 | ||
|
|
9aa3b5b78c | ||
|
|
7480f55e53 | ||
|
|
5fd82e829b | ||
|
|
43ebec1812 | ||
|
|
5cdf02f840 | ||
|
|
824e081005 | ||
|
|
fc992ba380 | ||
|
|
264070bfc7 | ||
|
|
a91509ba72 | ||
|
|
0dfe2429bc | ||
|
|
f1ad2e1fae | ||
|
|
c51679810a | ||
|
|
468ad1a2d5 | ||
|
|
bf8fbc2c0e | ||
|
|
0ed8ae28e7 | ||
|
|
f76ad8912c | ||
|
|
83e7d442fb | ||
|
|
76252659fd | ||
|
|
19036348a5 | ||
|
|
7efea4bb23 | ||
|
|
63ce244359 | ||
|
|
0bdf9538d0 | ||
|
|
b88e23892f | ||
|
|
bcf1e178a1 | ||
|
|
fe889b8428 | ||
|
|
cde7498c8e | ||
|
|
a27feb4157 | ||
|
|
a93c835557 | ||
|
|
5cd5821c18 | ||
|
|
3912e29eb7 | ||
|
|
0bad04d374 | ||
|
|
50c3a64553 | ||
|
|
cd8492dd7b | ||
|
|
79e160a46b | ||
|
|
761b3b3646 | ||
|
|
937f027f3c | ||
|
|
da14538299 | ||
|
|
02fbf766ad | ||
|
|
b13bef7f45 | ||
|
|
5e1aadba80 | ||
|
|
44e0bbf342 | ||
|
|
a7ed3379df | ||
|
|
19849e66d4 | ||
|
|
e9dac2fddc | ||
|
|
e61fe48b4d | ||
|
|
7e8b52ad70 | ||
|
|
d5a5f9572e | ||
|
|
fe4f7f8b0f | ||
|
|
4e3f80749f | ||
|
|
ff8c340330 | ||
|
|
039109ed56 | ||
|
|
f3f34e9ef5 | ||
|
|
2f39102026 | ||
|
|
6793eb383c | ||
|
|
2caceda8c4 | ||
|
|
238dc3a5b6 | ||
|
|
390ff30690 | ||
|
|
e1cf187cfe | ||
|
|
8c01df7828 | ||
|
|
ff8faa4cd7 | ||
|
|
b9aa64fd25 | ||
|
|
8dfd53620c | ||
|
|
0090aee0e5 | ||
|
|
230dea1243 | ||
|
|
3453bfa513 | ||
|
|
d0f047dfe7 | ||
|
|
8e7c454de0 | ||
|
|
68c75c7eb1 | ||
|
|
31ae260282 | ||
|
|
8b443b94ea | ||
|
|
6ec9c844e4 | ||
|
|
3d3b03e1e4 | ||
|
|
4d194cb50c | ||
|
|
b0d2bf4afe | ||
|
|
8f73bc3b4c | ||
|
|
90495b614f | ||
|
|
f03bcc24ad | ||
|
|
6646155712 | ||
|
|
9d72208d9e | ||
|
|
e84e703211 | ||
|
|
0497c0742f | ||
|
|
573e2b0012 | ||
|
|
c4b72fcc79 | ||
|
|
a2d7716331 | ||
|
|
67b5ebdb76 | ||
|
|
4c2ce2b45b | ||
|
|
3b2bade2f2 | ||
|
|
cdeb28a793 | ||
|
|
61918a1efa | ||
|
|
963adb5230 | ||
|
|
8f8a1ecf18 | ||
|
|
b9343b458f | ||
|
|
ac85fa2fc3 | ||
|
|
b7855857b5 | ||
|
|
d957c4373b | ||
|
|
f485d8f548 | ||
|
|
b994e235f3 | ||
|
|
2b1aea80ed | ||
|
|
53d8083343 | ||
|
|
d30c125ab7 | ||
|
|
9e2c75b548 | ||
|
|
aa54b23713 | ||
|
|
dc8e955c4f | ||
|
|
96b22a16eb | ||
|
|
5fbbfbcbe3 | ||
|
|
faf98dacf6 | ||
|
|
86b47a528a | ||
|
|
cf6c21a0d2 | ||
|
|
b1d900210a | ||
|
|
963fc4cebc | ||
|
|
80adaa700c | ||
|
|
dfead460ca | ||
|
|
6f21f8a402 | ||
|
|
abfc99308d | ||
|
|
955c87ef30 | ||
|
|
b4df62bec1 | ||
|
|
14d2fa3895 | ||
|
|
005c5309c4 | ||
|
|
3c9fdde24b | ||
|
|
654c933e30 | ||
|
|
83a86aacb5 | ||
|
|
f231809e22 | ||
|
|
2c8e0a6914 | ||
|
|
496816acff | ||
|
|
78b52f5716 | ||
|
|
2ca108820f | ||
|
|
dc6bd715b2 | ||
|
|
18a1e01d64 | ||
|
|
15e1078d01 | ||
|
|
06b0c7e928 | ||
|
|
3924c2f2bd | ||
|
|
7625d900d3 | ||
|
|
53dc1f2055 | ||
|
|
e706fa4a58 | ||
|
|
65e81e4034 | ||
|
|
4b78790096 | ||
|
|
236e129e7a | ||
|
|
d200619774 | ||
|
|
d0f13223bc | ||
|
|
7ae284f432 | ||
|
|
df872b8223 | ||
|
|
d8823ed45e | ||
|
|
9a63b3147f | ||
|
|
3f586ff4ab | ||
|
|
c4d4cfe9dc | ||
|
|
9faedbf516 | ||
|
|
bb745a8036 |
@@ -5,7 +5,7 @@
|
||||
Cakefile
|
||||
documentation/
|
||||
examples/
|
||||
extras/
|
||||
extras/coffee-script.js
|
||||
raw/
|
||||
src/
|
||||
test/
|
||||
|
||||
58
Cakefile
58
Cakefile
@@ -28,10 +28,12 @@ sources = [
|
||||
]
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run = (args) ->
|
||||
run = (args, cb) ->
|
||||
proc = spawn 'bin/coffee', args
|
||||
proc.stderr.on 'data', (buffer) -> console.log buffer.toString()
|
||||
proc.on 'exit', (status) -> process.exit(1) if status != 0
|
||||
proc.on 'exit', (status) ->
|
||||
process.exit(1) if status != 0
|
||||
cb() if typeof cb is 'function'
|
||||
|
||||
# Log a message with a color.
|
||||
log = (message, color, explanation) ->
|
||||
@@ -59,17 +61,16 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||
)
|
||||
|
||||
|
||||
task 'build', 'build the CoffeeScript language from source', ->
|
||||
task 'build', 'build the CoffeeScript language from source', build = (cb) ->
|
||||
files = fs.readdirSync 'src'
|
||||
files = ('src/' + file for file in files when file.match(/\.coffee$/))
|
||||
run ['-c', '-o', 'lib'].concat(files)
|
||||
run ['-c', '-o', 'lib'].concat(files), cb
|
||||
|
||||
|
||||
task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
exec 'bin/cake build && bin/cake build && bin/cake test', (err, stdout, stderr) ->
|
||||
console.log stdout.trim() if stdout
|
||||
console.log stderr.trim() if stderr
|
||||
throw err if err
|
||||
build ->
|
||||
build ->
|
||||
process.exit 1 unless runTests CoffeeScript
|
||||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
@@ -94,15 +95,16 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
||||
#{fs.readFileSync "lib/#{name}.js"}
|
||||
};
|
||||
"""
|
||||
{parser, uglify} = require 'uglify-js'
|
||||
ast = parser.parse """
|
||||
code = """
|
||||
this.CoffeeScript = function() {
|
||||
function require(path){ return require[path]; }
|
||||
#{code}
|
||||
return require['./coffee-script']
|
||||
}()
|
||||
"""
|
||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle ast, extra: yes
|
||||
unless process.env.MINIFY is 'false'
|
||||
{parser, uglify} = require 'uglify-js'
|
||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code
|
||||
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
|
||||
console.log "built ... running browser tests:"
|
||||
invoke 'test:browser'
|
||||
@@ -151,7 +153,7 @@ runTests = (CoffeeScript) ->
|
||||
passedTests = 0
|
||||
failures = []
|
||||
|
||||
# make "global" reference available to tests
|
||||
# Make "global" reference available to tests
|
||||
global.global = global
|
||||
|
||||
# Mix in the assert module globally, to make it available for tests.
|
||||
@@ -174,7 +176,7 @@ runTests = (CoffeeScript) ->
|
||||
catch e
|
||||
e.description = description if description?
|
||||
e.source = fn.toString() if fn.toString?
|
||||
failures.push file: currentFile, error: e
|
||||
failures.push filename: currentFile, error: e
|
||||
|
||||
# A recursive functional equivalence helper; uses egal for testing equivalence.
|
||||
# See http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
@@ -200,26 +202,28 @@ runTests = (CoffeeScript) ->
|
||||
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')
|
||||
{error, filename} = fail
|
||||
jsFilename = filename.replace(/\.coffee$/,'.js')
|
||||
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
|
||||
match = error.stack?.match(/on line (\d+):/) unless match
|
||||
[match, line, col] = match if match
|
||||
log "\n #{error.toString()}", red
|
||||
console.log ''
|
||||
log " #{error.description}", red if error.description
|
||||
log " #{jsFile}: line #{line or 'unknown'}, column #{col or 'unknown'}", red
|
||||
log " #{error.stack}", red
|
||||
log " #{jsFilename}: line #{line ? 'unknown'}, column #{col ? 'unknown'}", red
|
||||
console.log " #{error.source}" if error.source
|
||||
return
|
||||
|
||||
# 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 e
|
||||
failures.push file: currentFile, error: e
|
||||
files = fs.readdirSync 'test'
|
||||
for file in files when file.match /\.coffee$/i
|
||||
currentFile = filename = path.join 'test', file
|
||||
code = fs.readFileSync filename
|
||||
try
|
||||
CoffeeScript.run code.toString(), {filename}
|
||||
catch error
|
||||
failures.push {filename, error}
|
||||
return !failures.length
|
||||
|
||||
|
||||
task 'test', 'run the CoffeeScript language test suite', ->
|
||||
|
||||
3
README
3
README
@@ -26,7 +26,8 @@
|
||||
sudo bin/cake install
|
||||
|
||||
Or, if you have the Node Package Manager installed:
|
||||
npm install coffee-script
|
||||
npm install -g coffee-script
|
||||
(Leave off the -g if you don't wish to install globally.)
|
||||
|
||||
Compile a script:
|
||||
coffee /path/to/script.coffee
|
||||
|
||||
@@ -8,4 +8,4 @@ if car.speed < limit then accelerate()
|
||||
|
||||
winner = yes if pick in [47, 92, 13]
|
||||
|
||||
print inspect "My name is " + @name
|
||||
print inspect "My name is #{@name}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
###
|
||||
CoffeeScript Compiler v1.0.1
|
||||
CoffeeScript Compiler v1.1.2
|
||||
Released under the MIT License
|
||||
###
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ class Animal
|
||||
constructor: (@name) ->
|
||||
|
||||
move: (meters) ->
|
||||
alert @name + " moved " + meters + "m."
|
||||
alert @name + " moved #{meters}m."
|
||||
|
||||
class Snake extends Animal
|
||||
move: ->
|
||||
|
||||
@@ -2,6 +2,6 @@ alert(
|
||||
try
|
||||
nonexistent / undefined
|
||||
catch error
|
||||
"And the error is ... " + error
|
||||
"And the error is ... #{error}"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
yearsOld = max: 10, ida: 9, tim: 11
|
||||
|
||||
ages = for child, age of yearsOld
|
||||
child + " is " + age
|
||||
"#{child} is #{age}"
|
||||
|
||||
@@ -6,5 +6,5 @@ if this.studyingEconomics
|
||||
# Nursery Rhyme
|
||||
num = 6
|
||||
lyrics = while num -= 1
|
||||
num + " little monkeys, jumping on the bed.
|
||||
"#{num} little monkeys, jumping on the bed.
|
||||
One fell out and bumped his head."
|
||||
|
||||
@@ -85,6 +85,10 @@ code, pre, tt, textarea {
|
||||
font-weight: normal;
|
||||
color: black;
|
||||
}
|
||||
.timestamp small {
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
div.code {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
|
||||
@@ -2,21 +2,32 @@
|
||||
<span class="nv">CoffeeScript.require = </span><span class="nx">require</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>Use standard JavaScript <code>eval</code> to eval code.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.eval = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nb">eval</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Running code does not provide access to this scope.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.run = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">options = </span><span class="p">{})</span> <span class="o">-></span>
|
||||
<span class="nv">options.bare = </span><span class="kc">on</span>
|
||||
<span class="nb">Function</span><span class="p">(</span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>If we're not in a browser environment, we're finished with the public API.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">return</span> <span class="nx">unless</span> <span class="nb">window</span><span class="o">?</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Load a remote script from the current domain via XHR.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.load = </span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nb">Function</span><span class="p">(</span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>If we're not in a browser environment, we're finished with the public API.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">return</span> <span class="nx">unless</span> <span class="nb">window</span><span class="o">?</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Load a remote script from the current domain via XHR.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript.load = </span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">xhr = </span><span class="k">new</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">ActiveXObject</span> <span class="o">or</span> <span class="nx">XMLHttpRequest</span><span class="p">)(</span><span class="s1">'Microsoft.XMLHTTP'</span><span class="p">)</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span> <span class="s1">'GET'</span><span class="p">,</span> <span class="nx">url</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">overrideMimeType</span> <span class="s1">'text/plain'</span> <span class="k">if</span> <span class="s1">'overrideMimeType'</span> <span class="k">of</span> <span class="nx">xhr</span>
|
||||
<span class="nv">xhr.onreadystatechange = </span><span class="o">-></span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span><span class="p">,</span> <span class="nx">options</span> <span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">is</span> <span class="mi">4</span>
|
||||
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">is</span> <span class="mi">4</span>
|
||||
<span class="k">if</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">status</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">]</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"Could not load #{url}"</span>
|
||||
<span class="nx">callback</span><span class="p">()</span> <span class="k">if</span> <span class="nx">callback</span>
|
||||
<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span> <span class="kc">null</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
all script tags with a content-type of <code>text/coffeescript</code>.
|
||||
This happens on page load.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">runScripts = </span><span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">script</span> <span class="k">in</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span> <span class="s1">'script'</span>
|
||||
<span class="k">if</span> <span class="nx">script</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">'text/coffeescript'</span>
|
||||
<span class="nv">scripts = </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span> <span class="s1">'script'</span>
|
||||
<span class="nv">coffees = </span><span class="p">(</span><span class="nx">s</span> <span class="k">for</span> <span class="nx">s</span> <span class="k">in</span> <span class="nx">scripts</span> <span class="k">when</span> <span class="nx">s</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">'text/coffeescript'</span><span class="p">)</span>
|
||||
<span class="nv">index = </span><span class="mi">0</span>
|
||||
<span class="nv">length = </span><span class="nx">coffees</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">do</span> <span class="nv">execute = </span><span class="o">-></span>
|
||||
<span class="nv">script = </span><span class="nx">coffees</span><span class="p">[</span><span class="nx">index</span><span class="o">++</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">script</span><span class="o">?</span><span class="p">.</span><span class="nx">type</span> <span class="o">is</span> <span class="s1">'text/coffeescript'</span>
|
||||
<span class="k">if</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">load</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">load</span> <span class="nx">script</span><span class="p">.</span><span class="nx">src</span><span class="p">,</span> <span class="nx">execute</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">script</span><span class="p">.</span><span class="nx">innerHTML</span>
|
||||
<span class="nx">execute</span><span class="p">()</span>
|
||||
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Listen for window load, both in browsers and in IE.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span>
|
||||
<span class="nx">addEventListener</span> <span class="s1">'DOMContentLoaded'</span><span class="p">,</span> <span class="nx">runScripts</span><span class="p">,</span> <span class="kc">no</span>
|
||||
<span class="k">else</span>
|
||||
|
||||
@@ -36,7 +36,7 @@ If no tasks are passed, print the help screen.</p> </td>
|
||||
<span class="nv">spaces = </span><span class="k">if</span> <span class="nx">spaces</span> <span class="o">></span> <span class="mi">0</span> <span class="k">then</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">spaces</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nv">desc = </span><span class="k">if</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span> <span class="k">then</span> <span class="s2">"# #{task.description}"</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"cake #{name}#{spaces} #{desc}"</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Print an error and exit when attempting to all an undefined task.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">missingTask = </span><span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Print an error and exit when attempting to call an undefined task.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">missingTask = </span><span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"No such task: \"#{task}\""</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span>
|
||||
|
||||
|
||||
@@ -6,13 +6,15 @@ 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">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s1">'path'</span>
|
||||
<span class="p">{</span><span class="nx">Script</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'vm'</span>
|
||||
<span class="nv">Module = </span><span class="nx">require</span> <span class="s1">'module'</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">'./lexer'</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">'./parser'</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</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">'.coffee'</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">-></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">'utf8'</span>
|
||||
<span class="nv">content = </span><span class="nx">compile</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="nx">filename</span><span class="p">,</span> <span class="s1">'utf8'</span><span class="p">),</span> <span class="p">{</span><span class="nx">filename</span><span class="p">}</span>
|
||||
<span class="nx">module</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">content</span><span class="p">,</span> <span class="nx">filename</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span>
|
||||
<span class="nx">require</span><span class="p">.</span><span class="nx">registerExtension</span> <span class="s1">'.coffee'</span><span class="p">,</span> <span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="o">-></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">¶</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">'1.0.1'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</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">¶</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">'./helpers'</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</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">'.coffee'</span><span class="p">,</span> <span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="o">-></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">¶</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">'1.1.2'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</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">¶</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">'./helpers'</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</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">-></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>
|
||||
@@ -26,16 +28,36 @@ or traverse it by using <code>.traverse()</code> with a callback.</p>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">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-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</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">-></span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>We want the root module.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root = </span><span class="nx">module</span>
|
||||
<span class="k">while</span> <span class="nx">root</span><span class="p">.</span><span class="nx">parent</span>
|
||||
<span class="nv">root = </span><span class="nx">root</span><span class="p">.</span><span class="nx">parent</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Set the filename.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.filename = </span><span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</span> <span class="s1">'.'</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</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">¶</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">'.coffee'</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>
|
||||
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">-></span>
|
||||
<span class="nv">mainModule = </span><span class="nx">require</span><span class="p">.</span><span class="nx">main</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Set the filename.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">mainModule.filename = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</span> <span class="s1">'.'</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Clear the module cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">mainModule</span><span class="p">.</span><span class="nx">moduleCache</span> <span class="o">and=</span> <span class="p">{}</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Assign paths for node_modules loading</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">process</span><span class="p">.</span><span class="nx">binding</span><span class="p">(</span><span class="s1">'natives'</span><span class="p">).</span><span class="nx">module</span>
|
||||
<span class="p">{</span><span class="nx">Module</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'module'</span>
|
||||
<span class="nv">mainModule.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</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">mainModule</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'.coffee'</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="nx">mainModule</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">mainModule</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</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">-></span>
|
||||
<span class="nv">__filename = module.filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nv">__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">__filename</span>
|
||||
<span class="nb">eval</span> <span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</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">¶</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
<span class="nx">mainModule</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">mainModule</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">¶</a> </div> <p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
The CoffeeScript REPL uses this to run the input.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.eval = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">options = </span><span class="p">{})</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">createContext</span><span class="p">()</span>
|
||||
<span class="nv">sandbox.global = sandbox.root = sandbox.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span><span class="o">?</span>
|
||||
<span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span> <span class="k">instanceof</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">constructor</span>
|
||||
<span class="nv">sandbox = </span><span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="s1">'eval'</span>
|
||||
<span class="nv">sandbox.__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>define module/require only if they chose not to specify their own</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unless</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">module</span> <span class="o">or</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="nv">Module = </span><span class="nx">require</span> <span class="s1">'module'</span>
|
||||
<span class="nv">sandbox.module = _module = </span><span class="k">new</span> <span class="nx">Module</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">modulename</span> <span class="o">||</span> <span class="s1">'eval'</span><span class="p">)</span>
|
||||
<span class="nv">sandbox.require = _require = </span><span class="p">(</span><span class="nx">path</span><span class="p">)</span> <span class="o">-></span> <span class="nx">Module</span><span class="p">.</span><span class="nx">_load</span> <span class="nx">path</span><span class="p">,</span> <span class="nx">_module</span>
|
||||
<span class="nv">_module.filename = </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span>
|
||||
<span class="nx">_require</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span> <span class="o">=</span> <span class="nx">require</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span> <span class="k">for</span> <span class="nx">r</span> <span class="k">in</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyNames</span> <span class="nx">require</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>use the same hack node currently uses for their own REPL</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">_require.paths = _module.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
|
||||
<span class="nv">_require.resolve = </span><span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">-></span> <span class="nx">Module</span><span class="p">.</span><span class="nx">_resolveFilename</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">_module</span>
|
||||
<span class="nv">o = </span><span class="p">{}</span>
|
||||
<span class="nx">o</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">v</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">k</span><span class="p">,</span> <span class="nx">v</span> <span class="k">of</span> <span class="nx">options</span>
|
||||
<span class="nv">o.bare = </span><span class="kc">on</span> <span class="c1"># ensure return value</span>
|
||||
<span class="nv">js = </span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">o</span>
|
||||
<span class="nx">Script</span><span class="p">.</span><span class="nx">runInContext</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">sandbox</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</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-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</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">-></span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html> <html> <head> <title>command.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="browser.html"> browser.coffee </a> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> command.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">¶</a> </div> <p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
|
||||
into various forms: saved into <code>.js</code> files or printed to stdout, piped to
|
||||
<a href="http://javascriptlint.com/">JSLint</a> or recompiled every time the source is
|
||||
<a href="http://javascriptlint.com/">JavaScript Lint</a> or recompiled every time the source is
|
||||
saved, printed as a token stream or as the syntax tree, or launch an
|
||||
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>External dependencies.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s1">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s1">'path'</span>
|
||||
@@ -17,10 +17,10 @@ interactive REPL.</p> </td> <td class="code">
|
||||
<span class="p">[</span><span class="s1">'-c'</span><span class="p">,</span> <span class="s1">'--compile'</span><span class="p">,</span> <span class="s1">'compile to JavaScript and save as .js files'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-i'</span><span class="p">,</span> <span class="s1">'--interactive'</span><span class="p">,</span> <span class="s1">'run an interactive CoffeeScript REPL'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-o'</span><span class="p">,</span> <span class="s1">'--output [DIR]'</span><span class="p">,</span> <span class="s1">'set the directory for compiled JavaScript'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-j'</span><span class="p">,</span> <span class="s1">'--join'</span><span class="p">,</span> <span class="s1">'concatenate the scripts before compiling'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-j'</span><span class="p">,</span> <span class="s1">'--join [FILE]'</span><span class="p">,</span> <span class="s1">'concatenate the scripts before compiling'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-w'</span><span class="p">,</span> <span class="s1">'--watch'</span><span class="p">,</span> <span class="s1">'watch scripts for changes, and recompile'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-p'</span><span class="p">,</span> <span class="s1">'--print'</span><span class="p">,</span> <span class="s1">'print the compiled JavaScript to stdout'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-l'</span><span class="p">,</span> <span class="s1">'--lint'</span><span class="p">,</span> <span class="s1">'pipe the compiled JavaScript through JSLint'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-l'</span><span class="p">,</span> <span class="s1">'--lint'</span><span class="p">,</span> <span class="s1">'pipe the compiled JavaScript through JavaScript Lint'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-s'</span><span class="p">,</span> <span class="s1">'--stdio'</span><span class="p">,</span> <span class="s1">'listen for and compile scripts over stdio'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-e'</span><span class="p">,</span> <span class="s1">'--eval'</span><span class="p">,</span> <span class="s1">'compile a string from the command line'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'-r'</span><span class="p">,</span> <span class="s1">'--require [FILE*]'</span><span class="p">,</span> <span class="s1">'require a library before executing your script'</span><span class="p">]</span>
|
||||
@@ -48,28 +48,49 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">run</span>
|
||||
<span class="nv">opts.literals = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
|
||||
<span class="nv">process.ARGV = process.argv = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'coffee'</span>
|
||||
<span class="nv">process.execPath = </span><span class="nx">require</span><span class="p">.</span><span class="nx">main</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nx">compileScripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</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">-></span>
|
||||
<span class="nv">unprocessed = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">source</span><span class="p">)]</span><span class="o">=</span><span class="mi">1</span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nv">base = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span>
|
||||
<span class="nv">compile = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">topLevel</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">compile = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">topLevel</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">remaining_files = </span><span class="o">-></span>
|
||||
<span class="nv">total = </span><span class="mi">0</span>
|
||||
<span class="nx">total</span> <span class="o">+=</span> <span class="nx">x</span> <span class="k">for</span> <span class="nx">x</span> <span class="k">in</span> <span class="nx">unprocessed</span>
|
||||
<span class="nx">total</span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">exists</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">topLevel</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">exists</span> <span class="o">and</span> <span class="nx">source</span><span class="p">[</span><span class="o">-</span><span class="mi">7</span><span class="p">..]</span> <span class="o">isnt</span> <span class="s1">'.coffee'</span>
|
||||
<span class="k">return</span> <span class="nx">compile</span> <span class="s2">"#{source}.coffee"</span><span class="p">,</span> <span class="nx">sourceIndex</span><span class="p">,</span> <span class="nx">topLevel</span>
|
||||
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"File not found: #{source}"</span> <span class="k">if</span> <span class="nx">topLevel</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">exists</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">stat</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">stats</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="k">if</span> <span class="nx">stats</span><span class="p">.</span><span class="nx">isDirectory</span><span class="p">()</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readdir</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">files</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">+=</span> <span class="nx">files</span><span class="p">.</span><span class="nx">length</span>
|
||||
<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="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="nx">sourceIndex</span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</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">'.coffee'</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">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="nx">contents</span><span class="p">[</span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">source</span><span class="p">]</span> <span class="o">=</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span> <span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span><span class="p">(</span><span class="nx">contents</span><span class="p">).</span><span class="nx">length</span> <span class="o">is</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">contents</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">=</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">sourceIndex</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">join</span><span class="p">(</span><span class="s1">'\n'</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">></span> <span class="mi">0</span> <span class="o">and</span> <span class="nx">remaining_files</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</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">¶</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
<span class="k">else</span>
|
||||
<span class="nx">unprocessed</span><span class="p">[</span><span class="nx">sourceIndex</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</span>
|
||||
<span class="nx">compile</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</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">¶</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">-></span>
|
||||
<span class="nv">o = </span><span class="nx">opts</span>
|
||||
@@ -101,7 +122,7 @@ and write them back to <strong>stdout</strong>.</p> </td>
|
||||
<span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</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">-></span>
|
||||
<span class="nv">code = </span><span class="nx">contents</span><span class="p">.</span><span class="nx">join</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">compileScript</span> <span class="s2">"concatenation"</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="s2">"concatenation"</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Load files that are to-be-required before compilation occurs.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">loadRequires = </span><span class="o">-></span>
|
||||
<span class="nx">compileScript</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Load files that are to-be-required before compilation occurs.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">loadRequires = </span><span class="o">-></span>
|
||||
<span class="nv">realFilename = </span><span class="nx">module</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nv">module.filename = </span><span class="s1">'.'</span>
|
||||
<span class="nx">require</span> <span class="nx">req</span> <span class="k">for</span> <span class="nx">req</span> <span class="k">in</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">require</span>
|
||||
@@ -126,7 +147,7 @@ directory can be customized with <code>--output</code>.</p> </td>
|
||||
<span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"#{(new Date).toTimeString()} - compiled #{source}"</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"#{(new Date).toLocaleTimeString()} - compiled #{source}"</span>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="nx">dir</span><span class="p">,</span> <span class="p">(</span><span class="nx">exists</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">exists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s2">"mkdir -p #{dir}"</span><span class="p">,</span> <span class="nx">compile</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
|
||||
any errors or warnings that arise.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lint = </span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">js</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
@@ -53,7 +53,7 @@ all parsing must end here.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'STATEMENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>All the different types of expressions in our language. The basic unit of
|
||||
CoffeeScript is the <strong>Expression</strong> -- everything that can be an expression
|
||||
is one. Block serve as the building blocks of many other rules, making
|
||||
is one. Blocks serve as the building blocks of many other rules, making
|
||||
them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Expression</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Invocation'</span>
|
||||
@@ -77,7 +77,7 @@ token stream.</p> </td> <td class="code">
|
||||
they can also serve as keys in object literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">AlphaNumeric</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="o">-></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-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>All of our immediate values. These can (in general), be passed straight
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>All of our immediate values. Generally these can be passed straight
|
||||
through and printed to JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Literal</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'AlphaNumeric'</span>
|
||||
<span class="nx">o</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
@@ -128,53 +128,55 @@ that hoovers up the remaining arguments.</p> </td> <td c
|
||||
<span class="nx">o</span> <span class="s1">'ParamVar'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Param</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'ParamVar ...'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Param</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">on</span>
|
||||
<span class="nx">o</span> <span class="s1">'ParamVar = Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Param</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nx">ParamVar</span><span class="o">:</span> <span class="p">[</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">¶</a> </div> <p>Function Parameters</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ParamVar</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Identifier'</span>
|
||||
<span class="nx">o</span> <span class="s1">'ThisProperty'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Array'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Object'</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">¶</a> </div> <p>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Splat</span><span class="o">:</span> <span class="p">[</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">¶</a> </div> <p>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Splat</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression ...'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Splat</span> <span class="nx">$1</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">¶</a> </div> <p>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">SimpleAssignable</span><span class="o">:</span> <span class="p">[</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">¶</a> </div> <p>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">SimpleAssignable</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Identifier'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value Accessor'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Invocation Accessor'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span><span class="p">,</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'ThisProperty'</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">¶</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Assignable</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">¶</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Assignable</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Array'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Object'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">¶</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">¶</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
|
||||
as functions, indexed into, named as a class, etc.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Value</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Assignable'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Literal'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Parenthetical'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Range'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'This'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">¶</a> </div> <p>The general group of accessors into an object, by property, by prototype
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">¶</a> </div> <p>The general group of accessors into an object, by property, by prototype
|
||||
or by array index or slice.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Accessor</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'. Identifier'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Access</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'?. Identifier'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Access</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'soak'</span>
|
||||
<span class="nx">o</span> <span class="s1">':: Identifier'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Access</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'proto'</span>
|
||||
<span class="nx">o</span> <span class="s1">'::'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'prototype'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Index'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Slice'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Slice</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">¶</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Index</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_START Expression INDEX_END'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Index</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Index</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_START IndexValue INDEX_END'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_SOAK Index'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">extend</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">soak</span> <span class="o">:</span> <span class="kc">yes</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_PROTO Index'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">extend</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">proto</span><span class="o">:</span> <span class="kc">yes</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">¶</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nx">IndexValue</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Index</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Slice'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Slice</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">¶</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'{ AssignList OptComma }'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Obj</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span><span class="p">.</span><span class="nx">generated</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">¶</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">¶</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
comma, as in JavaScript, or simply by newline.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">AssignList</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">''</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignObj'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignList , AssignObj'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignList OptComma TERMINATOR AssignObj'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'AssignList OptComma INDENT AssignList OptComma OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">¶</a> </div> <p>Class definitions have optional bodies of prototype property assignments,
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-35">¶</a> </div> <p>Class definitions have optional bodies of prototype property assignments,
|
||||
and optional references to the superclass.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Class</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
@@ -184,35 +186,35 @@ and optional references to the superclass.</p> </td> <td
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable EXTENDS Value'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'CLASS SimpleAssignable EXTENDS Value Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Class</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$5</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-35">¶</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="p">]</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-36">¶</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">'Value OptFuncExist Arguments'</span><span class="p">,</span> <span class="o">-></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">'Invocation OptFuncExist Arguments'</span><span class="p">,</span> <span class="o">-></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">'SUPER'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Call</span> <span class="s1">'super'</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">'arguments'</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'SUPER Arguments'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Call</span> <span class="s1">'super'</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">¶</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="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-37">¶</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">''</span><span class="p">,</span> <span class="o">-></span> <span class="kc">no</span>
|
||||
<span class="nx">o</span> <span class="s1">'FUNC_EXIST'</span><span class="p">,</span> <span class="o">-></span> <span class="kc">yes</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-37">¶</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arguments</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-38">¶</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arguments</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'CALL_START CALL_END'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'CALL_START ArgList OptComma CALL_END'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-38">¶</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">This</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">¶</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">This</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'this'</span>
|
||||
<span class="nx">o</span> <span class="s1">'@'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'this'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">¶</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ThisProperty</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">¶</a> </div> <p>A reference to a property on <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ThisProperty</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'@ Identifier'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="s1">'this'</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Access</span><span class="p">(</span><span class="nx">$2</span><span class="p">)],</span> <span class="s1">'this'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">¶</a> </div> <p>The array literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Array</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-41">¶</a> </div> <p>The array literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Array</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'[ ]'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Arr</span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s1">'[ ArgList OptComma ]'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Arr</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-41">¶</a> </div> <p>Inclusive and exclusive range dots.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">RangeDots</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</a> </div> <p>Inclusive and exclusive range dots.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">RangeDots</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'..'</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'inclusive'</span>
|
||||
<span class="nx">o</span> <span class="s1">'...'</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'exclusive'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Range</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <p>The CoffeeScript range literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Range</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'[ Expression RangeDots Expression ]'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <p>Array slice literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Slice</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_START Expression RangeDots Expression INDEX_END'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_START Expression RangeDots INDEX_END'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDEX_START RangeDots Expression INDEX_END'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">¶</a> </div> <p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">¶</a> </div> <p>Array slice literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Slice</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression RangeDots Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression RangeDots'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'RangeDots Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Range</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">¶</a> </div> <p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
|
||||
as well as the contents of an array literal
|
||||
(i.e. comma-separated expressions). Newlines work as well.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ArgList</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Arg'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
@@ -220,35 +222,35 @@ as well as the contents of an array literal
|
||||
<span class="nx">o</span> <span class="s1">'ArgList OptComma TERMINATOR Arg'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT ArgList OptComma OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'ArgList OptComma INDENT ArgList OptComma OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">¶</a> </div> <p>Valid arguments are Block or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">¶</a> </div> <p>Valid arguments are Blocks or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Splat'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">¶</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-47">¶</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
this to be separate from the <strong>ArgList</strong> for use in <strong>Switch</strong> blocks, where
|
||||
having the newlines wouldn't make sense.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">SimpleArgs</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleArgs , Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[].</span><span class="nx">concat</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-47">¶</a> </div> <p>The variants of <em>try/catch/finally</em> exception handling blocks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Try</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-48">¶</a> </div> <p>The variants of <em>try/catch/finally</em> exception handling blocks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Try</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block Catch'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block FINALLY Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'TRY Block Catch FINALLY Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Try</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">$5</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-48">¶</a> </div> <p>A catch clause names its error and runs a block of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Catch</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-49">¶</a> </div> <p>A catch clause names its error and runs a block of code.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Catch</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'CATCH Identifier Block'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-49">¶</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Throw</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Throw an exception object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Throw</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'THROW Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Throw</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">¶</a> </div> <p>Parenthetical expressions. Note that the <strong>Parenthetical</strong> is a <strong>Value</strong>,
|
||||
not an <strong>Expression</strong>, so if you need to use an expression in a place
|
||||
where only values are accepted, wrapping it in parentheses will always do
|
||||
the trick.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Parenthetical</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'( Body )'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Parens</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'( INDENT Body OUTDENT )'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Parens</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">¶</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">WhileSource</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">WhileSource</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'WHILE Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'WHILE Expression WHEN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">guard</span><span class="o">:</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'UNTIL Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</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">'UNTIL Expression WHEN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">invert</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">guard</span><span class="o">:</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</a> </div> <p>The while loop can either be normal, with a block of expressions to execute,
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">¶</a> </div> <p>The while loop can either be normal, with a block of expressions to execute,
|
||||
or postfix, with a single expression. There is no do..while.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">While</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'WhileSource Block'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement WhileSource'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span><span class="p">.</span><span class="nx">addBody</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
@@ -259,7 +261,7 @@ or postfix, with a single expression. There is no do..while.</p> </t
|
||||
<span class="nx">Loop</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'LOOP Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'true'</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'LOOP Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">While</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'true'</span><span class="p">).</span><span class="nx">addBody</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">¶</a> </div> <p>Array, object, and range comprehensions, at the most generic level.
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">¶</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">'Statement ForBody'</span><span class="p">,</span> <span class="o">-></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>
|
||||
@@ -275,17 +277,17 @@ or postfix, with a single expression.</p> </td> <td clas
|
||||
<span class="nx">ForStart</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'FOR ForVariables'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'FOR OWN ForVariables'</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$3.own = </span><span class="kc">yes</span><span class="p">;</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">¶</a> </div> <p>An array of all accepted values for a variable inside the loop.
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</a> </div> <p>An array of all accepted values for a variable inside the loop.
|
||||
This enables support for pattern matching.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForValue</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Identifier'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Array'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'Object'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Value</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</a> </div> <p>An array or range comprehension has variables for the current element
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">¶</a> </div> <p>An array or range comprehension has variables for the current element
|
||||
and (optional) reference to the current index. Or, <em>key, value</em>, in the case
|
||||
of object comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForVariables</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForValue'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'ForValue , ForValue'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">¶</a> </div> <p>The source of a comprehension is an array or object with an optional guard
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">¶</a> </div> <p>The source of a comprehension is an array or object with an optional guard
|
||||
clause. If it's an array comprehension, you can also choose to step through
|
||||
in fixed-size increments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ForSource</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'FORIN Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">source</span><span class="o">:</span> <span class="nx">$2</span>
|
||||
@@ -307,21 +309,21 @@ in fixed-size increments.</p> </td> <td class="code">
|
||||
<span class="nx">Whens</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'When'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Whens When'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">¶</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">When</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">¶</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">When</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'LEADING_WHEN SimpleArgs Block'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]]</span>
|
||||
<span class="nx">o</span> <span class="s1">'LEADING_WHEN SimpleArgs Block TERMINATOR'</span><span class="p">,</span> <span class="o">-></span> <span class="p">[[</span><span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">¶</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">¶</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">'IF Expression Block'</span><span class="p">,</span> <span class="o">-></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">'IfBlock ELSE IF Expression Block'</span><span class="p">,</span> <span class="o">-></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="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">¶</a> </div> <p>The full complement of <em>if</em> expressions, including postfix one-liner
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">¶</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">'IfBlock'</span>
|
||||
<span class="nx">o</span> <span class="s1">'IfBlock ELSE Block'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">addElse</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement POST_IF Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression POST_IF Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">¶</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">¶</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
|
||||
Here they are grouped by order of precedence. The actual precedence rules
|
||||
are defined at the bottom of the page. It would be shorter if we could
|
||||
combine most of these rules into a single generic <em>Operand OpSymbol Operand</em>
|
||||
@@ -334,7 +336,7 @@ rules are necessary.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'-- SimpleAssignable'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'--'</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'++ SimpleAssignable'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'++'</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable --'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'--'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable ++'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'++'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">¶</a> </div> <p><a href="http://jashkenas.github.com/coffee-script/#existence">The existential operator</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">o</span> <span class="s1">'Expression ?'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Existence</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable ++'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'++'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="kc">true</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">¶</a> </div> <p><a href="http://jashkenas.github.com/coffee-script/#existence">The existential operator</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">o</span> <span class="s1">'Expression ?'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Existence</span> <span class="nx">$1</span>
|
||||
|
||||
<span class="nx">o</span> <span class="s1">'Expression + Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'+'</span> <span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression - Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Op</span> <span class="s1">'-'</span> <span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
@@ -354,7 +356,7 @@ rules are necessary.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable COMPOUND_ASSIGN</span>
|
||||
<span class="s1"> INDENT Expression OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s1">'SimpleAssignable EXTENDS Expression'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Extends</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">¶</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">¶</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">¶</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">¶</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
|
||||
down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
|
||||
<pre><code>2 + (3 * 4)
|
||||
@@ -380,7 +382,7 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'FORIN'</span><span class="p">,</span> <span class="s1">'FOROF'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'DO'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">'CLASS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s1">'right'</span><span class="p">,</span> <span class="s1">'POST_IF'</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">¶</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">¶</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">¶</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">¶</a> </div> <p>Finally, now that we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
|
||||
terminals (every symbol which does not appear as the name of a rule above)
|
||||
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tokens = </span><span class="p">[]</span>
|
||||
@@ -389,7 +391,7 @@ as "tokens".</p> </td> <td class="code"> <
|
||||
<span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">alt</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">split</span> <span class="s1">' '</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span> <span class="nx">unless</span> <span class="nx">grammar</span><span class="p">[</span><span class="nx">token</span><span class="p">]</span>
|
||||
<span class="nx">alt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"return #{alt[1]}"</span> <span class="k">if</span> <span class="nx">name</span> <span class="o">is</span> <span class="s1">'Root'</span>
|
||||
<span class="nx">alt</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">¶</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
<span class="nx">alt</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">¶</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
rules, and the name of the root. Reverse the operators because Jison orders
|
||||
precedence from low to high, and we have it high to low
|
||||
(as in <a href="http://dinosaur.compilertools.net/yacc/index.html">Yacc</a>).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.parser = </span><span class="k">new</span> <span class="nx">Parser</span>
|
||||
|
||||
@@ -58,11 +58,11 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
|
||||
<span class="nx">@token</span> <span class="s1">'OWN'</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="k">return</span> <span class="nx">id</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">forcedIdentifier = </span><span class="nx">colon</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'.'</span><span class="p">,</span> <span class="s1">'?.'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'::'</span><span class="p">]</span>
|
||||
<span class="p">(</span><span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span><span class="p">)</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'.'</span><span class="p">,</span> <span class="s1">'?.'</span><span class="p">,</span> <span class="s1">'::'</span><span class="p">]</span> <span class="o">or</span>
|
||||
<span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'@'</span><span class="p">)</span>
|
||||
<span class="nv">tag = </span><span class="s1">'IDENTIFIER'</span>
|
||||
|
||||
<span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">JS_KEYWORDS</span> <span class="o">or</span>
|
||||
<span class="o">not</span> <span class="nx">forcedIdentifier</span> <span class="o">and</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">COFFEE_KEYWORDS</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">forcedIdentifier</span> <span class="o">and</span> <span class="p">(</span><span class="nx">id</span> <span class="k">in</span> <span class="nx">JS_KEYWORDS</span> <span class="o">or</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">COFFEE_KEYWORDS</span><span class="p">)</span>
|
||||
<span class="nv">tag = </span><span class="nx">id</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'WHEN'</span> <span class="o">and</span> <span class="nx">@tag</span><span class="p">()</span> <span class="k">in</span> <span class="nx">LINE_BREAK</span>
|
||||
<span class="nv">tag = </span><span class="s1">'LEADING_WHEN'</span>
|
||||
@@ -91,7 +91,7 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
|
||||
<span class="nx">@identifierError</span> <span class="nx">id</span>
|
||||
|
||||
<span class="nx">unless</span> <span class="nx">forcedIdentifier</span>
|
||||
<span class="nv">id = </span><span class="nx">COFFEE_ALIASES</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">hasOwnProperty</span> <span class="nx">id</span>
|
||||
<span class="nv">id = </span><span class="nx">COFFEE_ALIAS_MAP</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">COFFEE_ALIASES</span>
|
||||
<span class="nv">tag = </span><span class="k">switch</span> <span class="nx">id</span>
|
||||
<span class="k">when</span> <span class="s1">'!'</span> <span class="k">then</span> <span class="s1">'UNARY'</span>
|
||||
<span class="k">when</span> <span class="s1">'=='</span><span class="p">,</span> <span class="s1">'!='</span> <span class="k">then</span> <span class="s1">'COMPARE'</span>
|
||||
@@ -136,11 +136,11 @@ preserve whitespace, but ignore indentation to the left.</p> </td>
|
||||
<span class="nx">heredoc</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Matches and consumes comments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">commentToken</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">COMMENT</span>
|
||||
<span class="p">[</span><span class="nx">comment</span><span class="p">,</span> <span class="nx">here</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span>
|
||||
<span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">comment</span><span class="p">,</span> <span class="s1">'\n'</span>
|
||||
<span class="k">if</span> <span class="nx">here</span>
|
||||
<span class="nx">@token</span> <span class="s1">'HERECOMMENT'</span><span class="p">,</span> <span class="nx">@sanitizeHeredoc</span> <span class="nx">here</span><span class="p">,</span>
|
||||
<span class="nx">herecomment</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">indent</span><span class="o">:</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">@indent</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span>
|
||||
<span class="nx">@token</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">comment</span><span class="p">,</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">comment</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">jsToken</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'`'</span> <span class="o">and</span> <span class="nv">match = </span><span class="nx">JSTOKEN</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span>
|
||||
<span class="nx">@token</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="p">(</span><span class="nv">script = </span><span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="nx">slice</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span>
|
||||
@@ -148,7 +148,11 @@ preserve whitespace, but ignore indentation to the left.</p> </td>
|
||||
to distinguish from division, so we borrow some basic heuristics from
|
||||
JavaScript and Ruby.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">regexToken</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'/'</span>
|
||||
<span class="k">return</span> <span class="nx">@heregexToken</span> <span class="nx">match</span> <span class="k">if</span> <span class="nv">match = </span><span class="nx">HEREGEX</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span>
|
||||
<span class="k">if</span> <span class="nv">match = </span><span class="nx">HEREGEX</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span>
|
||||
<span class="nv">length = </span><span class="nx">@heregexToken</span> <span class="nx">match</span>
|
||||
<span class="nx">@line</span> <span class="o">+=</span> <span class="nx">count</span> <span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s1">'\n'</span>
|
||||
<span class="k">return</span> <span class="nx">length</span>
|
||||
|
||||
<span class="nv">prev = </span><span class="nx">last</span> <span class="nx">@tokens</span>
|
||||
<span class="k">return</span> <span class="mi">0</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="p">(</span><span class="k">if</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="k">then</span> <span class="nx">NOT_REGEX</span> <span class="k">else</span> <span class="nx">NOT_SPACED_REGEX</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="mi">0</span> <span class="nx">unless</span> <span class="nv">match = </span><span class="nx">REGEX</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">@chunk</span>
|
||||
@@ -277,8 +281,11 @@ parentheses that indicate a method call from regular parentheses, and so on.</p>
|
||||
<span class="nx">value</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">¶</a> </div> <h2>Token Manipulators</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">¶</a> </div> <p>Sanitize a heredoc or herecomment by
|
||||
erasing all external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">sanitizeHeredoc</span><span class="o">:</span> <span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">{</span><span class="nx">indent</span><span class="p">,</span> <span class="nx">herecomment</span><span class="p">}</span> <span class="o">=</span> <span class="nx">options</span>
|
||||
<span class="k">return</span> <span class="nx">doc</span> <span class="k">if</span> <span class="nx">herecomment</span> <span class="o">and</span> <span class="mi">0</span> <span class="o">></span> <span class="nx">doc</span><span class="p">.</span><span class="nx">indexOf</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">unless</span> <span class="nx">herecomment</span>
|
||||
<span class="k">if</span> <span class="nx">herecomment</span>
|
||||
<span class="k">if</span> <span class="nx">HEREDOC_ILLEGAL</span><span class="p">.</span><span class="nx">test</span> <span class="nx">doc</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"block comment cannot contain \"*/\", starting on line #{@line + 1}"</span>
|
||||
<span class="k">return</span> <span class="nx">doc</span> <span class="k">if</span> <span class="nx">doc</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'\n'</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">0</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">while</span> <span class="nv">match = </span><span class="nx">HEREDOC_INDENT</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">doc</span>
|
||||
<span class="nv">attempt = </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">indent = </span><span class="nx">attempt</span> <span class="k">if</span> <span class="nx">indent</span> <span class="o">is</span> <span class="kc">null</span> <span class="o">or</span> <span class="mi">0</span> <span class="o"><</span> <span class="nx">attempt</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
|
||||
@@ -298,9 +305,10 @@ parameters specially in order to make things easier for the parser.</p>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nx">tok</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'CALL_START'</span>
|
||||
<span class="k">if</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="k">then</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'('</span>
|
||||
<span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'PARAM_START'</span>
|
||||
<span class="k">return</span> <span class="k">this</span>
|
||||
<span class="k">else</span> <span class="k">return</span> <span class="k">this</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</a> </div> <p>Close up all remaining open blocks at the end of the file.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">closeIndentation</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@outdentToken</span> <span class="nx">@indent</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</a> </div> <p>The error for when you try to use a forbidden word in JavaScript as
|
||||
an identifier.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">identifierError</span><span class="o">:</span> <span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -324,6 +332,8 @@ interpolations within strings, ad infinitum.</p> </td> <
|
||||
<span class="k">continue</span>
|
||||
<span class="k">if</span> <span class="nx">end</span> <span class="o">is</span> <span class="s1">'}'</span> <span class="o">and</span> <span class="nx">letter</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'"'</span><span class="p">,</span> <span class="s2">"'"</span><span class="p">]</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nv">end = </span><span class="nx">letter</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">end</span> <span class="o">is</span> <span class="s1">'}'</span> <span class="o">and</span> <span class="nx">letter</span> <span class="o">is</span> <span class="s1">'/'</span> <span class="o">and</span> <span class="nv">match = </span><span class="p">(</span><span class="nx">HEREGEX</span><span class="p">.</span><span class="nx">exec</span><span class="p">(</span><span class="nx">str</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span><span class="p">)</span> <span class="o">or</span> <span class="nx">REGEX</span><span class="p">.</span><span class="nx">exec</span><span class="p">(</span><span class="nx">str</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span><span class="p">))</span>
|
||||
<span class="nx">i</span> <span class="o">+=</span> <span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">end</span> <span class="o">is</span> <span class="s1">'}'</span> <span class="o">and</span> <span class="nx">letter</span> <span class="o">is</span> <span class="s1">'{'</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nv">end = </span><span class="s1">'}'</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">end</span> <span class="o">is</span> <span class="s1">'"'</span> <span class="o">and</span> <span class="nx">prev</span> <span class="o">is</span> <span class="s1">'#'</span> <span class="o">and</span> <span class="nx">letter</span> <span class="o">is</span> <span class="s1">'{'</span>
|
||||
@@ -394,7 +404,8 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="s1">'if'</span><span class="p">,</span> <span class="s1">'else'</span><span class="p">,</span> <span class="s1">'switch'</span><span class="p">,</span> <span class="s1">'for'</span><span class="p">,</span> <span class="s1">'while'</span><span class="p">,</span> <span class="s1">'do'</span><span class="p">,</span> <span class="s1">'try'</span><span class="p">,</span> <span class="s1">'catch'</span><span class="p">,</span> <span class="s1">'finally'</span>
|
||||
<span class="s1">'class'</span><span class="p">,</span> <span class="s1">'extends'</span><span class="p">,</span> <span class="s1">'super'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">¶</a> </div> <p>CoffeeScript-only keywords.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">COFFEE_KEYWORDS = </span><span class="p">[</span><span class="s1">'undefined'</span><span class="p">,</span> <span class="s1">'then'</span><span class="p">,</span> <span class="s1">'unless'</span><span class="p">,</span> <span class="s1">'until'</span><span class="p">,</span> <span class="s1">'loop'</span><span class="p">,</span> <span class="s1">'of'</span><span class="p">,</span> <span class="s1">'by'</span><span class="p">,</span> <span class="s1">'when'</span><span class="p">]</span>
|
||||
<span class="nx">COFFEE_KEYWORDS</span><span class="p">.</span><span class="nx">push</span> <span class="nx">op</span> <span class="k">for</span> <span class="nx">op</span> <span class="k">of</span> <span class="nv">COFFEE_ALIASES =</span>
|
||||
|
||||
<span class="nv">COFFEE_ALIAS_MAP =</span>
|
||||
<span class="o">and</span> <span class="o">:</span> <span class="s1">'&&'</span>
|
||||
<span class="o">or</span> <span class="o">:</span> <span class="s1">'||'</span>
|
||||
<span class="o">is</span> <span class="o">:</span> <span class="s1">'=='</span>
|
||||
@@ -403,7 +414,10 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="kc">yes</span> <span class="o">:</span> <span class="s1">'true'</span>
|
||||
<span class="kc">no</span> <span class="o">:</span> <span class="s1">'false'</span>
|
||||
<span class="kc">on</span> <span class="o">:</span> <span class="s1">'true'</span>
|
||||
<span class="kc">off</span> <span class="o">:</span> <span class="s1">'false'</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">¶</a> </div> <p>The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
<span class="kc">off</span> <span class="o">:</span> <span class="s1">'false'</span>
|
||||
|
||||
<span class="nv">COFFEE_ALIASES = </span><span class="p">(</span><span class="nx">key</span> <span class="k">for</span> <span class="nx">key</span> <span class="k">of</span> <span class="nx">COFFEE_ALIAS_MAP</span><span class="p">)</span>
|
||||
<span class="nv">COFFEE_KEYWORDS = </span><span class="nx">COFFEE_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">COFFEE_ALIASES</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">¶</a> </div> <p>The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
to avoid having a JavaScript error at runtime.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">RESERVED = </span><span class="p">[</span>
|
||||
<span class="s1">'case'</span><span class="p">,</span> <span class="s1">'default'</span><span class="p">,</span> <span class="s1">'function'</span><span class="p">,</span> <span class="s1">'var'</span><span class="p">,</span> <span class="s1">'void'</span><span class="p">,</span> <span class="s1">'with'</span>
|
||||
@@ -419,7 +433,7 @@ be used as identifiers or properties.</p> </td> <td clas
|
||||
|
||||
<span class="nv">NUMBER = </span><span class="err">///</span>
|
||||
<span class="o">^</span> <span class="mi">0</span><span class="nx">x</span><span class="p">[</span><span class="err">\</span><span class="nx">da</span><span class="o">-</span><span class="nx">f</span><span class="p">]</span><span class="o">+</span> <span class="o">|</span> <span class="c1"># hex</span>
|
||||
<span class="o">^</span> <span class="p">(</span><span class="o">?:</span> <span class="err">\</span><span class="nx">d</span><span class="o">+</span><span class="p">(</span><span class="err">\</span><span class="p">.</span><span class="err">\</span><span class="nx">d</span><span class="o">+</span><span class="p">)</span><span class="o">?</span> <span class="o">|</span> <span class="err">\</span><span class="p">.</span><span class="err">\</span><span class="nx">d</span><span class="o">+</span> <span class="p">)</span> <span class="p">(</span><span class="o">?:</span><span class="nx">e</span><span class="p">[</span><span class="o">+-</span><span class="p">]</span><span class="o">?</span><span class="err">\</span><span class="nx">d</span><span class="o">+</span><span class="p">)</span><span class="o">?</span> <span class="c1"># decimal</span>
|
||||
<span class="o">^</span> <span class="err">\</span><span class="nx">d</span><span class="o">*</span><span class="err">\</span><span class="p">.</span><span class="o">?</span><span class="err">\</span><span class="nx">d</span><span class="o">+</span> <span class="p">(</span><span class="o">?:</span><span class="nx">e</span><span class="p">[</span><span class="o">+-</span><span class="p">]</span><span class="o">?</span><span class="err">\</span><span class="nx">d</span><span class="o">+</span><span class="p">)</span><span class="o">?</span> <span class="c1"># decimal</span>
|
||||
<span class="err">///i</span>
|
||||
|
||||
<span class="nv">HEREDOC = </span><span class="err">/// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 ///</span>
|
||||
@@ -445,7 +459,7 @@ be used as identifiers or properties.</p> </td> <td clas
|
||||
<span class="nv">SIMPLESTR = </span><span class="sr">/^'[^\\']*(?:\\.[^\\']*)*'/</span>
|
||||
|
||||
<span class="nv">JSTOKEN = </span><span class="sr">/^`[^\\`]*(?:\\.[^\\`]*)*`/</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <p>Regex-matching-regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REGEX = </span><span class="err">/// ^</span>
|
||||
<span class="o">/</span> <span class="p">(</span><span class="o">?!</span> <span class="err">\</span><span class="nx">s</span> <span class="p">)</span> <span class="c1"># disallow leading whitespace</span>
|
||||
<span class="o">/</span> <span class="p">(</span><span class="o">?!</span> <span class="p">[</span><span class="err">\</span><span class="nx">s</span><span class="o">=</span><span class="p">]</span> <span class="p">)</span> <span class="c1"># disallow leading whitespace or equals signs</span>
|
||||
<span class="p">[</span><span class="o">^</span> <span class="p">[</span> <span class="err">/ \n \\ ]* # every other thing</span>
|
||||
<span class="p">(</span><span class="o">?:</span>
|
||||
<span class="p">(</span><span class="o">?:</span> <span class="err">\\</span><span class="p">[</span><span class="err">\</span><span class="nx">s</span><span class="err">\</span><span class="nx">S</span><span class="p">]</span> <span class="c1"># anything escaped</span>
|
||||
@@ -464,9 +478,11 @@ be used as identifiers or properties.</p> </td> <td clas
|
||||
|
||||
<span class="nv">HEREDOC_INDENT = </span><span class="sr">/\n+([^\n\S]*)/g</span>
|
||||
|
||||
<span class="nv">HEREDOC_ILLEGAL = </span><span class="sr">/\*\//</span>
|
||||
|
||||
<span class="nv">ASSIGNED = </span><span class="sr">/^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/</span>
|
||||
|
||||
<span class="nv">LINE_CONTINUER = </span><span class="err">/// ^ \s* (?: , | \??\.(?!\.) | :: ) ///</span>
|
||||
<span class="nv">LINE_CONTINUER = </span><span class="err">/// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///</span>
|
||||
|
||||
<span class="nv">TRAILING_SPACES = </span><span class="sr">/\s+$/</span>
|
||||
|
||||
@@ -482,7 +498,7 @@ a division operator might.</p>
|
||||
<p>See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</p>
|
||||
|
||||
<p>Our list is shorter, due to sans-parentheses method calls.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">NOT_REGEX = </span><span class="p">[</span><span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'BOOL'</span><span class="p">,</span> <span class="s1">'++'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">']'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">¶</a> </div> <p>If the previous token is not spaced, there are more preceding tokens that
|
||||
force a division parse:</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">NOT_SPACED_REGEX = </span><span class="nx">NOT_REGEX</span><span class="p">.</span><span class="nx">concat</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'STRING'</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</a> </div> <p>Tokens which could legitimately be invoked or indexed. A opening
|
||||
force a division parse:</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">NOT_SPACED_REGEX = </span><span class="nx">NOT_REGEX</span><span class="p">.</span><span class="nx">concat</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'STRING'</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</a> </div> <p>Tokens which could legitimately be invoked or indexed. An opening
|
||||
parentheses or bracket following these tokens will be recorded as the start
|
||||
of a function invocation or indexing operation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CALLABLE = </span><span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">']'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="s1">'?'</span><span class="p">,</span> <span class="s1">'::'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">]</span>
|
||||
<span class="nv">INDEXABLE = </span><span class="nx">CALLABLE</span><span class="p">.</span><span class="nx">concat</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'BOOL'</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">¶</a> </div> <p>Tokens that, when immediately preceding a <code>WHEN</code>, indicate that the <code>WHEN</code>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ 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">-></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">¶</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
|
||||
specified options, and return it. <code>options.arguments</code> will be an array
|
||||
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
|
||||
|
||||
@@ -4,26 +4,87 @@ Using it looks like this:</p>
|
||||
|
||||
<pre><code>coffee> console.log "#{num} bottles of beer" for num in [99..1]
|
||||
</code></pre> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>Require the <strong>coffee-script</strong> module to get access to the compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span>
|
||||
<span class="nv">readline = </span><span class="nx">require</span> <span class="s1">'readline'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Start by opening up <code>stdin</code> and <code>stdout</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdin = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
|
||||
<span class="nv">stdout = </span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Log an error.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">error = </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span> <span class="o">+</span> <span class="s1">'\n\n'</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="nx">quit</span><span class="o">:</span> <span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
<span class="nv">readline = </span><span class="nx">require</span> <span class="s1">'readline'</span>
|
||||
<span class="p">{</span><span class="nx">inspect</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'util'</span>
|
||||
<span class="p">{</span><span class="nx">Script</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'vm'</span>
|
||||
<span class="nv">Module = </span><span class="nx">require</span> <span class="s1">'module'</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>REPL Setup</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Config</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REPL_PROMPT = </span><span class="s1">'coffee> '</span>
|
||||
<span class="nv">REPL_PROMPT_CONTINUATION = </span><span class="s1">'......> '</span>
|
||||
<span class="nv">enableColours = </span><span class="kc">no</span>
|
||||
<span class="nx">unless</span> <span class="nx">process</span><span class="p">.</span><span class="nx">platform</span> <span class="o">is</span> <span class="s1">'win32'</span>
|
||||
<span class="nv">enableColours = </span><span class="o">not</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_DISABLE_COLORS</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Start by opening up <code>stdin</code> and <code>stdout</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdin = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
|
||||
<span class="nv">stdout = </span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Log an error.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">error = </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span> <span class="o">+</span> <span class="s1">'\n\n'</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>The current backlog of multi-line code.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">backlog = </span><span class="s1">''</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>The REPL context; must be visible outside <code>run</code> to allow for tab completion</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">sandbox = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">createContext</span><span class="p">()</span>
|
||||
<span class="nv">nonContextGlobals = </span><span class="p">[</span>
|
||||
<span class="s1">'Buffer'</span><span class="p">,</span> <span class="s1">'console'</span><span class="p">,</span> <span class="s1">'process'</span>
|
||||
<span class="s1">'setInterval'</span><span class="p">,</span> <span class="s1">'clearInterval'</span>
|
||||
<span class="s1">'setTimeout'</span><span class="p">,</span> <span class="s1">'clearTimeout'</span>
|
||||
<span class="p">]</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">in</span> <span class="nx">nonContextGlobals</span>
|
||||
<span class="nv">sandbox.global = sandbox.root = sandbox.GLOBAL = </span><span class="nx">sandbox</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
Attempt to evaluate the command. If there's an exception, print it out instead
|
||||
of exiting.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">run = </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="o">!</span><span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span> <span class="o">and</span> <span class="o">!</span><span class="nx">backlog</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
<span class="k">return</span>
|
||||
<span class="nv">code = </span><span class="nx">backlog</span> <span class="o">+=</span> <span class="nx">buffer</span>
|
||||
<span class="k">if</span> <span class="nx">code</span><span class="p">[</span><span class="nx">code</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'\\'</span>
|
||||
<span class="nv">backlog = </span><span class="s2">"#{backlog[...-1]}\n"</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT_CONTINUATION</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
<span class="k">return</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT</span>
|
||||
<span class="nv">backlog = </span><span class="s1">''</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">val = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">bare</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">globals</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">filename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">val</span> <span class="o">+</span> <span class="s1">'\n'</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
|
||||
<span class="nv">_ = </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">_</span>
|
||||
<span class="nv">returnValue = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="s2">"_=(#{code}\n)"</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="nx">sandbox</span><span class="p">,</span>
|
||||
<span class="nx">filename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="nx">modulename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">if</span> <span class="nx">returnValue</span> <span class="o">is</span> <span class="kc">undefined</span>
|
||||
<span class="nv">sandbox._ = </span><span class="nx">_</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">inspect</span><span class="p">(</span><span class="nx">returnValue</span><span class="p">,</span> <span class="kc">no</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">enableColours</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'\n'</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">error</span> <span class="nx">err</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Make sure that uncaught exceptions don't kill the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'uncaughtException'</span><span class="p">,</span> <span class="nx">error</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <h1>Autocompletion</h1> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Regexes to match complete-able bits of text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSOR = </span><span class="sr">/\s*([\w\.]+)(?:\.(\w*))$/</span>
|
||||
<span class="nv">SIMPLEVAR = </span><span class="sr">/\s*(\w*)$/i</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Returns a list of completions, and the completed text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">autocomplete = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">completeAttribute</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">or</span> <span class="nx">completeVariable</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">or</span> <span class="p">[[],</span> <span class="nx">text</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Attempt to autocomplete a chained dotted attribute: <code>one.two.three</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">completeAttribute = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nv">match = </span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span> <span class="nx">ACCESSOR</span>
|
||||
<span class="p">[</span><span class="nx">all</span><span class="p">,</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">prefix</span><span class="p">]</span> <span class="o">=</span> <span class="nx">match</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">val = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInContext</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">sandbox</span>
|
||||
<span class="k">catch</span> <span class="nx">error</span>
|
||||
<span class="k">return</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">prefix</span><span class="p">,</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getOwnPropertyNames</span> <span class="nx">val</span>
|
||||
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">prefix</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Attempt to autocomplete an in-scope free variable: <code>one</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">completeVariable = </span><span class="p">(</span><span class="nx">text</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nv">free = </span><span class="p">(</span><span class="nx">text</span><span class="p">.</span><span class="nx">match</span> <span class="nx">SIMPLEVAR</span><span class="p">)</span><span class="o">?</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">vars = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInContext</span> <span class="s1">'Object.getOwnPropertyNames(this)'</span><span class="p">,</span> <span class="nx">sandbox</span>
|
||||
<span class="nv">possibilities = </span><span class="nx">vars</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">RESERVED</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">free</span><span class="p">,</span> <span class="nx">possibilities</span>
|
||||
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">free</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Return elements of candidates for which <code>prefix</code> is a prefix.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">getCompletions = </span><span class="p">(</span><span class="nx">prefix</span><span class="p">,</span> <span class="nx">candidates</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">el</span> <span class="k">for</span> <span class="nx">el</span> <span class="k">in</span> <span class="nx">candidates</span> <span class="k">when</span> <span class="nx">el</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">prefix</span><span class="p">)</span> <span class="o">is</span> <span class="mi">0</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Make sure that uncaught exceptions don't kill the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'uncaughtException'</span><span class="p">,</span> <span class="nx">error</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">autocomplete</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'data'</span><span class="p">,</span> <span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">repl</span><span class="p">.</span><span class="nx">write</span> <span class="nx">buffer</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">stdout</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span><span class="p">,</span> <span class="nx">stdout</span><span class="p">,</span> <span class="nx">autocomplete</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="s1">'coffee> '</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'close'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">stdin</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'line'</span><span class="p">,</span> <span class="nx">run</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'attemptClose'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">backlog</span>
|
||||
<span class="nv">backlog = </span><span class="s1">''</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">close</span><span class="p">()</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'close'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="s1">'\n'</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'line'</span><span class="p">,</span> <span class="nx">run</span>
|
||||
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">setPrompt</span> <span class="nx">REPL_PROMPT</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -78,7 +78,10 @@ Insert the missing braces here, so that the parser doesn't have to.</p>
|
||||
<span class="o">not</span> <span class="p">(</span><span class="nx">two</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">':'</span> <span class="o">or</span> <span class="nx">one</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'@'</span> <span class="o">and</span> <span class="nx">three</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">':'</span><span class="p">))</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">','</span> <span class="o">and</span> <span class="nx">one</span> <span class="o">and</span>
|
||||
<span class="nx">one</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">not</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">])</span>
|
||||
<span class="nv">action = </span><span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></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">'}'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nv">action = </span><span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">tok = </span><span class="p">[</span><span class="s1">'}'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nv">tok.generated = </span><span class="kc">yes</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">tok</span>
|
||||
<span class="nx">@scanTokens</span> <span class="p">(</span><span class="nx">token</span><span class="p">,</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">tokens</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nv">tag = </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">in</span> <span class="nx">EXPRESSION_START</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="p">[(</span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</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">'{'</span> <span class="k">then</span> <span class="s1">'{'</span> <span class="k">else</span> <span class="nx">tag</span><span class="p">),</span> <span class="nx">i</span><span class="p">]</span>
|
||||
@@ -108,12 +111,14 @@ deal with them.</p> </td> <td class="code">
|
||||
<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">'CLASS'</span><span class="p">,</span> <span class="s1">'IF'</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">'INDENT'</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">'{'</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">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">'?'</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">'INDENT'</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">'{'</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">seenControl = </span><span class="kc">no</span>
|
||||
<span class="nv">noCall = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">LINEBREAKS</span>
|
||||
<span class="nv">token.call = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'?'</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">token</span><span class="p">.</span><span class="nx">fromThen</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">callObject</span> <span class="o">or</span>
|
||||
<span class="nx">prev</span><span class="o">?</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="p">(</span><span class="nx">prev</span><span class="p">.</span><span class="nx">call</span> <span class="o">or</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">in</span> <span class="nx">IMPLICIT_FUNC</span><span class="p">)</span> <span class="o">and</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_CALL</span> <span class="o">or</span> <span class="o">not</span> <span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">or</span> <span class="nx">token</span><span class="p">.</span><span class="nx">newLine</span><span class="p">)</span> <span class="o">and</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_UNSPACED_CALL</span><span class="p">)</span>
|
||||
@@ -121,9 +126,11 @@ deal with them.</p> </td> <td class="code">
|
||||
<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">-></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="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">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">]</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">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">]</span>
|
||||
<span class="nv">seenControl = </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">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'SWITCH'</span><span class="p">,</span> <span class="s1">'TRY'</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">'.'</span><span class="p">,</span> <span class="s1">'?.'</span><span class="p">,</span> <span class="s1">'::'</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">'OUTDENT'</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">','</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="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">','</span> <span class="o">and</span> <span class="p">(</span><span class="nx">tag</span> <span class="k">in</span> <span class="nx">IMPLICIT_END</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">seenControl</span><span class="p">))</span> <span class="o">and</span>
|
||||
<span class="p">(</span><span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">'INDENT'</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">@tag</span><span class="p">(</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'CLASS'</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">not</span> <span class="k">in</span> <span class="nx">IMPLICIT_BLOCK</span> <span class="o">and</span>
|
||||
<span class="o">not</span> <span class="p">((</span><span class="nv">post = </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="o">and</span> <span class="nx">post</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'{'</span><span class="p">)))</span>
|
||||
@@ -244,7 +251,7 @@ look things up from either end.</p> </td> <td class="cod
|
||||
<span class="s1">'@'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">'++'</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nv">IMPLICIT_UNSPACED_CALL = </span><span class="p">[</span><span class="s1">'+'</span><span class="p">,</span> <span class="s1">'-'</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">¶</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">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">','</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">¶</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">'POST_IF'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</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">¶</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">'+'</span><span class="p">,</span> <span class="s1">'-'</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">¶</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">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">','</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">¶</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">'POST_IF'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'LOOP'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</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">¶</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">'ELSE'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'TRY'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">,</span> <span class="s1">'THEN'</span><span class="p">]</span>
|
||||
<span class="nv">SINGLE_CLOSERS = </span><span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="s1">'LEADING_WHEN'</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">¶</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">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span>
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ variables are new and need to be declared with <code>var</code>, and which are s
|
||||
with the outside.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>Import the helpers we plan to use.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">extend</span><span class="p">,</span> <span class="nx">last</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span> <span class="s1">'./helpers'</span>
|
||||
|
||||
<span class="nv">exports.Scope = </span><span class="nx">class</span> <span class="nx">Scope</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>The top-level <strong>Scope</strong> object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">@root</span><span class="o">:</span> <span class="kc">null</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Initialize a scope with its parent, for lookups up the chain,
|
||||
as well as a reference to the <strong>Block</strong> node is belongs to, which is
|
||||
as well as a reference to the <strong>Block</strong> node it belongs to, which is
|
||||
where it should declare its variables, and a reference to the function that
|
||||
it wraps.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">constructor</span><span class="o">:</span><span class="p">(</span><span class="nx">@parent</span><span class="p">,</span> <span class="nx">@expressions</span><span class="p">,</span> <span class="nx">@method</span><span class="p">)</span> <span class="o">-></span>
|
||||
it wraps.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@parent</span><span class="p">,</span> <span class="nx">@expressions</span><span class="p">,</span> <span class="nx">@method</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@variables = </span><span class="p">[{</span><span class="nx">name</span><span class="o">:</span> <span class="s1">'arguments'</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">'arguments'</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">¶</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">-></span>
|
||||
@@ -36,7 +36,7 @@ walks up to the root scope.</p> </td> <td class="code">
|
||||
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>If we need to store an intermediate result, find an available name for a
|
||||
compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">freeVariable</span><span class="o">:</span> <span class="p">(</span><span class="nx">type</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">index = </span><span class="mi">0</span>
|
||||
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">index</span><span class="p">),</span> <span class="kc">true</span><span class="p">)</span>
|
||||
<span class="nx">index</span><span class="o">++</span> <span class="k">while</span> <span class="nx">@check</span><span class="p">((</span><span class="nv">temp = </span><span class="nx">@temporary</span> <span class="nx">type</span><span class="p">,</span> <span class="nx">index</span><span class="p">))</span>
|
||||
<span class="nx">@add</span> <span class="nx">temp</span><span class="p">,</span> <span class="s1">'var'</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">¶</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">-></span>
|
||||
|
||||
@@ -80,10 +80,10 @@
|
||||
<div class="screenshadow bl"></div>
|
||||
<div class="screenshadow br"></div>
|
||||
<div id="repl_source_wrap">
|
||||
<textarea id="repl_source" rows="100">alert "Hello CoffeeScript!"</textarea>
|
||||
<textarea id="repl_source" rows="100" spellcheck="false">alert "Hello CoffeeScript!"</textarea>
|
||||
</div>
|
||||
<div id="repl_results_wrap"><pre id="repl_results"></pre></div>
|
||||
<div class="minibutton dark run">Run</div>
|
||||
<div class="minibutton dark run" title="Ctrl-Enter">Run</div>
|
||||
<br class="clear" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.0.1">1.0.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.2">1.1.2</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -166,17 +166,21 @@
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
npm install coffee-script</pre>
|
||||
npm install -g coffee-script</pre>
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
<p>
|
||||
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
sudo bin/cake install</pre>
|
||||
@@ -185,7 +189,9 @@ sudo bin/cake install</pre>
|
||||
If installing on Ubuntu or Debian,
|
||||
<a href="http://opinionated-programmer.com/2010/12/installing-coffeescript-on-debian-or-ubuntu/">be
|
||||
careful not to use the existing out-of-date package</a>. If installing on
|
||||
Windows, your best bet is probably to run Node.js under Cygwin.
|
||||
Windows, your best bet is probably to run Node.js under Cygwin. If you'd
|
||||
just like to experiment, you can try the
|
||||
<a href="https://github.com/alisey/CoffeeScript-Compiler-for-Windows">CoffeeScript Compiler For Windows</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -219,10 +225,11 @@ sudo bin/cake install</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-j, --join</code></td>
|
||||
<td><code>-j, --join [FILE]</code></td>
|
||||
<td>
|
||||
Before compiling, concatenate all scripts together in the order they
|
||||
were passed. Useful for building large projects.
|
||||
were passed, and write them into the specified file.
|
||||
Useful for building large projects.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -261,7 +268,7 @@ sudo bin/cake install</pre>
|
||||
<td><code>-e, --eval</code></td>
|
||||
<td>
|
||||
Compile and print a little snippet of CoffeeScript directly from the
|
||||
command line. For example:<br /><tt>coffee -e "puts num for num in [10..1]"</tt>
|
||||
command line. For example:<br /><tt>coffee -e "console.log num for num in [10..1]"</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -304,7 +311,7 @@ Expressions
|
||||
<td><code>--nodejs</code></td>
|
||||
<td>
|
||||
The <tt>node</tt> executable has some useful options you can set,
|
||||
such as<br /> <tt>--debug</tt> and <tt>--max-stack-size</tt>. Use this
|
||||
such as<br /> <tt>--debug</tt>, <tt>--debug-brk</tt> and <tt>--max-stack-size</tt>. Use this
|
||||
flag to forward options directly to Node.js.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -326,7 +333,7 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
Concatenate a list of files into a single script:<br />
|
||||
<tt>coffee -o lib/ --join --compile src/*.coffee</tt>
|
||||
<tt>coffee --join project.js --compile src/*.coffee</tt>
|
||||
</li>
|
||||
<li>
|
||||
Print out the compiled JS from a one-liner:<br />
|
||||
@@ -362,8 +369,8 @@ Expressions
|
||||
<p>
|
||||
First, the basics: CoffeeScript uses significant whitespace to delimit blocks of code.
|
||||
You don't need to use semicolons <tt>;</tt> to terminate expressions,
|
||||
ending the line will do just as well, (although semicolons can still
|
||||
be used to fit multiple expressions onto a single line.)
|
||||
ending the line will do just as well (although semicolons can still
|
||||
be used to fit multiple expressions onto a single line).
|
||||
Instead of using curly braces
|
||||
<tt>{ }</tt> to surround blocks of code in <a href="#functions">functions</a>,
|
||||
<a href="#conditionals">if-statements</a>,
|
||||
@@ -442,7 +449,7 @@ Expressions
|
||||
If you'd like to create top-level variables for other scripts to use,
|
||||
attach them as properties on <b>window</b>, or on the <b>exports</b>
|
||||
object in CommonJS. The <b>existential operator</b> (covered below), gives you a
|
||||
reliable way to figure out where to add them, if you're targeting both
|
||||
reliable way to figure out where to add them; if you're targeting both
|
||||
CommonJS and the browser: <tt>exports ? this</tt>
|
||||
</p>
|
||||
|
||||
@@ -497,7 +504,7 @@ Expressions
|
||||
each iteration into an array. Sometimes functions end with loops that are
|
||||
intended to run only for their side-effects. Be careful that you're not
|
||||
accidentally returning the results of the comprehension in these cases,
|
||||
by adding a meaningful return value, like <tt>true</tt>, or <tt>null</tt>,
|
||||
by adding a meaningful return value — like <tt>true</tt> — or <tt>null</tt>,
|
||||
to the bottom of your function.
|
||||
</p>
|
||||
<p>
|
||||
@@ -542,7 +549,7 @@ Expressions
|
||||
<b class="header">Array Slicing and Splicing with Ranges</b>
|
||||
Ranges can also be used to extract slices of arrays.
|
||||
With two dots (<tt>3..6</tt>), the range is inclusive (<tt>3, 4, 5, 6</tt>);
|
||||
with three docs (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
with three dots (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
</p>
|
||||
<%= code_for('slices', 'middle') %>
|
||||
<p>
|
||||
@@ -560,7 +567,7 @@ Expressions
|
||||
to CoffeeScript functions, they nonetheless return their final value.
|
||||
The CoffeeScript compiler tries to make sure that all statements in the
|
||||
language can be used as expressions. Watch how the <tt>return</tt> gets
|
||||
pushed down into each possible branch of execution, in the function
|
||||
pushed down into each possible branch of execution in the function
|
||||
below.
|
||||
</p>
|
||||
<%= code_for('expressions', 'eldest') %>
|
||||
@@ -701,20 +708,20 @@ Expressions
|
||||
in a single assignable expression.
|
||||
</p>
|
||||
<p>
|
||||
Constructor functions are named, to better support reflection. In the
|
||||
example below for the first class, <tt>this.constructor.name is "Animal"</tt>.
|
||||
Constructor functions are named, to better support helpful stack traces.
|
||||
</p>
|
||||
<%= code_for('classes', true) %>
|
||||
<p>
|
||||
If structuring your prototypes classically isn't your cup of tea, CoffeeScript
|
||||
provides a couple of lower-level conveniences. The <tt>extends</tt> operator
|
||||
helps with proper prototype setup, <tt>::</tt> gives you
|
||||
quick access to an object's prototype, and <tt>super()</tt>
|
||||
helps with proper prototype setup, and can be used to create an inheritance
|
||||
chain between any pair of constructor functions; <tt>::</tt> gives you
|
||||
quick access to an object's prototype; and <tt>super()</tt>
|
||||
is converted into a call against the immediate ancestor's method of the same name.
|
||||
</p>
|
||||
<%= code_for('prototypes', '"one_two".dasherize()') %>
|
||||
<p>
|
||||
Finally class definitions are blocks of executable code, which make for interesting
|
||||
Finally, class definitions are blocks of executable code, which make for interesting
|
||||
metaprogramming possibilities. Because in the context of a class definition,
|
||||
<tt>this</tt> is the class object itself (the constructor function), you
|
||||
can assign static properties by using <br /><tt>@property: value</tt>, and call
|
||||
@@ -753,7 +760,7 @@ Expressions
|
||||
<b class="header">Function binding</b>
|
||||
In JavaScript, the <tt>this</tt> keyword is dynamically scoped to mean the
|
||||
object that the current function is attached to. If you pass a function as
|
||||
as callback, or attach it to a different object, the original value of <tt>this</tt>
|
||||
a callback or attach it to a different object, the original value of <tt>this</tt>
|
||||
will be lost. If you're not familiar with this behavior,
|
||||
<a href="http://www.digital-web.com/articles/scope_in_javascript/">this Digital Web article</a>
|
||||
gives a good overview of the quirks.
|
||||
@@ -842,7 +849,7 @@ Expressions
|
||||
<p>
|
||||
Sometimes you'd like to pass a block comment through to the generated
|
||||
JavaScript. For example, when you need to embed a licensing header at
|
||||
the top of a file. Block comments, which mirror the synax for heredocs,
|
||||
the top of a file. Block comments, which mirror the syntax for heredocs,
|
||||
are preserved in the generated code.
|
||||
</p>
|
||||
<%= code_for('block_comment') %>
|
||||
@@ -905,7 +912,7 @@ Expressions
|
||||
|
||||
<p>
|
||||
In fact, the little bit of glue script that runs "Try CoffeeScript" above,
|
||||
as well as jQuery for the menu, is implemented in just this way.
|
||||
as well as the jQuery for the menu, is implemented in just this way.
|
||||
View source and look at the bottom of the page to see the example.
|
||||
Including the script also gives you access to <tt>CoffeeScript.compile()</tt>
|
||||
so you can pop open Firebug and try compiling some strings.
|
||||
@@ -923,6 +930,10 @@ Expressions
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
|
||||
a zero-configuration Rack server, with comprehensive annotated source.
|
||||
</li>
|
||||
<li>
|
||||
<b>frank06</b>'s <a href="http://riakjs.org/">riak-js</a>, a Node.js client for
|
||||
<a href="http://www.basho.com/Riak.html">Riak</a>, with support for HTTP
|
||||
@@ -932,6 +943,10 @@ Expressions
|
||||
<b>technoweenie</b>'s <a href="https://github.com/technoweenie/coffee-resque">Coffee-Resque</a>,
|
||||
a port of <a href="https://github.com/defunkt/resque">Resque</a> for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
|
||||
A headless, full-stack, faux-browser testing library for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
|
||||
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
|
||||
@@ -945,10 +960,6 @@ Expressions
|
||||
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
|
||||
<a href="http://rack.rubyforge.org/">Rack</a> server.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://sstephenson.github.com/strscan-js/">StringScanner</a>,
|
||||
a simple tokenizer and lexical scanner for JavaScript strings.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
@@ -971,102 +982,23 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://github.com/jashkenas/coffee-script/issues">CoffeeScript Issues</a><br />
|
||||
Bugs reports, feature requests, and general discussion all belong here.
|
||||
Bug reports, feature proposals, and ideas for changes to the language belong here.
|
||||
</li>
|
||||
<li>
|
||||
If you'd like to chat, stop by <tt>#coffeescript</tt> on Freenode in the
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
<a href="https://groups.google.com/forum/#!forum/coffeescript">CoffeeScript Google Group</a><br />
|
||||
If you'd like to ask a question, the mailing list is a good place to get help.
|
||||
</li>
|
||||
<li>
|
||||
<b>satyr</b>'s <a href="http://github.com/satyr/coco">Coco</a>
|
||||
— An avant-garde dialect of CoffeeScript that frequently pioneers
|
||||
features and optimizations, some of which CoffeeScript later adopts.
|
||||
Check out the <a href="https://github.com/satyr/coco/wiki/additions">list of additions</a>
|
||||
to the language.
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki">The CoffeeScript Wiki</a><br />
|
||||
If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha — share it on the wiki.
|
||||
The wiki also serves as a directory of handy
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/Text-editor-plugins">text editor extensions</a>,
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/Web-framework-plugins">web framework plugins</a>,
|
||||
and general <a href="http://github.com/jashkenas/coffee-script/wiki/Build-tools">CoffeeScript build tools</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
|
||||
— A Java Library that uses Rhino to compile CoffeeScript, allowing
|
||||
compilation within Java projects or on systems that Node.js doesn't support.
|
||||
</li>
|
||||
<li>
|
||||
<b>defunkt</b>'s <a href="http://github.com/defunkt/coffee-mode">CoffeeScript Major Mode</a>
|
||||
— a Emacs major mode that provides syntax highlighting, indentation
|
||||
support, and some bonus commands.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="http://github.com/jashkenas/coffee-script-tmbundle">CoffeeScript TextMate Bundle</a>
|
||||
— which provides syntax highlighting, snippet expansion, and the
|
||||
ability to run bits of CoffeeScript from within TextMate itself.
|
||||
</li>
|
||||
<li>
|
||||
<b>kchmck</b>'s <a href="http://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a>
|
||||
— which adds Vim syntax highlighting and indentation support.
|
||||
</li>
|
||||
<li>
|
||||
<b>wavded</b>'s <a href="http://github.com/wavded/gedit-coffeescript">gedit-coffeescript</a>
|
||||
— a CoffeeScript syntax highlighter for the gedit text editor.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>dhotson</b>'s <a href="https://github.com/dhotson/coffeescript-jedit">coffeescript-jedit</a>
|
||||
— which provides syntax highlighting support in jEdit.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
compiled JavaScript on the fly.
|
||||
</li>
|
||||
<li>
|
||||
<b>jnicklas</b>'s <a href="http://github.com/jnicklas/bistro_car">BistroCar</a>
|
||||
— a plugin that serves and bundles CoffeeScript from within your
|
||||
Rails application.
|
||||
</li>
|
||||
<li>
|
||||
<b>dsc</b>'s <a href="http://github.com/dsc/coffeecup">CoffeeCup</a>
|
||||
— a Python WSGI middleware that compiles CoffeeScript to JavaScript
|
||||
on-demand during development.
|
||||
</li>
|
||||
<li>
|
||||
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
|
||||
— a BistroCar alternative that integrates well with
|
||||
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
|
||||
</li>
|
||||
<li>
|
||||
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
|
||||
— a custom filter for rendering CoffeeScript inline within
|
||||
<a href="http://haml-lang.com/">HAML</a> templates.
|
||||
</li>
|
||||
<li>
|
||||
<b>andrzejsliwa</b>'s <a href="http://github.com/andrzejsliwa/coffeeapp">CoffeeApp</a>
|
||||
— a CoffeeScript wrapper for CouchApps, web applications served
|
||||
directly from CouchDB.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://github.com/sstephenson/eco">Eco</a>
|
||||
— high-performance embedded CoffeeScript templates, after EJS and ERB.
|
||||
</li>
|
||||
<li>
|
||||
<b>mauricemach</b>'s <a href="http://github.com/mauricemach/coffeekup">CoffeeKup</a>
|
||||
— Markup as CoffeeScript. After _why's
|
||||
<a href="http://markaby.github.com/">Markaby</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="http://jashkenas.github.com/docco/">Docco</a>
|
||||
— a quick-and-dirty literate-programming-style documentation generator
|
||||
for CoffeeScript. Used to produce the annotated source.
|
||||
</li>
|
||||
<li>
|
||||
<b>naturalethic</b>'s <a href="http://github.com/naturalethic/coffee-mongo">coffee-mongo</a>
|
||||
— an asynchronous MongoDB ORM, for use with Node.js and CoffeeScript.
|
||||
</li>
|
||||
<li>
|
||||
<b>mauricemach</b>'s <a href="https://github.com/mauricemach/zappa">Zappa</a>
|
||||
— a DSL for building web apps, built on top of Express and Socket.IO.
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/FAQ">The FAQ</a><br />
|
||||
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1090,16 +1022,58 @@ Expressions
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.1...1.1.2">1.1.2</a>
|
||||
<span class="timestamp"> – <small>August 4, 2011</small></span>
|
||||
</b>
|
||||
We now use the native <tt>Function.prototype.bind</tt> for bound function
|
||||
literals where available.
|
||||
Fixes for: block comment formatting, <tt>?=</tt> compilation, implicit calls
|
||||
against control structures, implicit invocation of a try/catch block,
|
||||
variadic arguments leaking from local scope, line numbers in syntax errors
|
||||
following heregexes, property access on parenthesized number literals,
|
||||
bound class methods and super with reserved names, a REPL overhaul,
|
||||
consecutive compiled semicolons, block comments in implicitly called objects,
|
||||
and a Chrome bug.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.1
|
||||
<span class="timestamp"> – <small>May 10, 2011</small></span>
|
||||
</b>
|
||||
Bugfix release for classes with external constructor functions, see
|
||||
issue #1182.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.0
|
||||
<span class="timestamp"> – <small>May 1, 2011</small></span>
|
||||
</b>
|
||||
When running via the <tt>coffee</tt> executable, <tt>process.argv</tt> and
|
||||
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
|
||||
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
|
||||
The output in the REPL is now colorized, like Node's is.
|
||||
Giving your concatenated CoffeeScripts a name when using <tt>--join</tt> is now mandatory.
|
||||
Fix for lexing compound division <tt>/=</tt> as a regex accidentally.
|
||||
All <tt>text/coffeescript</tt> tags should now execute in the order they're included.
|
||||
Fixed an issue with extended subclasses using external constructor functions.
|
||||
Fixed an edge-case infinite loop in <tt>addImplicitParentheses</tt>.
|
||||
Fixed exponential slowdown with long chains of function calls.
|
||||
Globals no longer leak into the CoffeeScript REPL.
|
||||
Splatted parameters are declared local to the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.0.1
|
||||
<span class="timestamp"> – <small>Jan 31, 2011</small></span>
|
||||
</b>
|
||||
Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility
|
||||
with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing
|
||||
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
|
||||
Stopped requiring the core Node.js <tt>"util"</tt> module for
|
||||
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
|
||||
Stopped requiring the core Node.js <tt>"util"</tt> module for
|
||||
back-compatibility with Node.js 0.2.5. Fixed a case where a
|
||||
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
|
||||
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
|
||||
statement. Optimized empty objects in destructuring assignment.
|
||||
</p>
|
||||
|
||||
@@ -1576,7 +1550,7 @@ Expressions
|
||||
$('#repl_source').keyup -> compileSource()
|
||||
|
||||
# Eval the compiled js.
|
||||
$('.minibutton.run').click ->
|
||||
evalJS = ->
|
||||
try
|
||||
eval window.compiledJS
|
||||
catch error then alert error
|
||||
@@ -1592,6 +1566,8 @@ Expressions
|
||||
closeMenus = ->
|
||||
$('.navigation.active').removeClass 'active'
|
||||
|
||||
$('.minibutton.run').click evalJS
|
||||
|
||||
# Bind navigation buttons to open the menus.
|
||||
$('.navigation').click (e) ->
|
||||
return if e.target.tagName.toLowerCase() is 'a'
|
||||
@@ -1603,9 +1579,15 @@ Expressions
|
||||
$(this).addClass 'active'
|
||||
false
|
||||
|
||||
$(document.body).click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
# Dismiss console if Escape pressed or click falls outside console
|
||||
# Trigger Run button on Ctrl-Enter
|
||||
$(document.body)
|
||||
.keydown (e) ->
|
||||
closeMenus() if e.which == 27
|
||||
evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length
|
||||
.click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
|
||||
$('#open_webchat').click ->
|
||||
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
CoffeeScript Compiler v1.0.1
|
||||
CoffeeScript Compiler v1.1.2
|
||||
Released under the MIT License
|
||||
*/
|
||||
@@ -12,15 +12,15 @@ Animal = (function() {
|
||||
this.name = name;
|
||||
}
|
||||
Animal.prototype.move = function(meters) {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
return alert(this.name + (" moved " + meters + "m."));
|
||||
};
|
||||
return Animal;
|
||||
})();
|
||||
Snake = (function() {
|
||||
__extends(Snake, Animal);
|
||||
function Snake() {
|
||||
Snake.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
__extends(Snake, Animal);
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return Snake.__super__.move.call(this, 5);
|
||||
@@ -28,10 +28,10 @@ Snake = (function() {
|
||||
return Snake;
|
||||
})();
|
||||
Horse = (function() {
|
||||
__extends(Horse, Animal);
|
||||
function Horse() {
|
||||
Horse.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
__extends(Horse, Animal);
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return Horse.__super__.move.call(this, 45);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
var footprints, solipsism;
|
||||
if ((typeof mind != "undefined" && mind !== null) && !(typeof world != "undefined" && world !== null)) {
|
||||
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
|
||||
solipsism = true;
|
||||
}
|
||||
typeof speed != "undefined" && speed !== null ? speed : speed = 75;
|
||||
footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";
|
||||
if (typeof speed === "undefined" || speed === null) {
|
||||
speed = 75;
|
||||
}
|
||||
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
|
||||
@@ -9,7 +9,7 @@ ages = (function() {
|
||||
_results = [];
|
||||
for (child in yearsOld) {
|
||||
age = yearsOld[child];
|
||||
_results.push(child + " is " + age);
|
||||
_results.push("" + child + " is " + age);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
@@ -21,7 +21,7 @@ race = function() {
|
||||
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
||||
return print(winner, runners);
|
||||
};
|
||||
if (typeof elvis != "undefined" && elvis !== null) {
|
||||
if (typeof elvis !== "undefined" && elvis !== null) {
|
||||
alert("I knew it!");
|
||||
}
|
||||
cubes = (function() {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
var zip, _ref;
|
||||
zip = typeof lottery.drawWinner == "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
@@ -12,7 +12,7 @@ lyrics = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
while (num -= 1) {
|
||||
_results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
|
||||
_results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
@@ -1,7 +0,0 @@
|
||||
EXTRAS:
|
||||
|
||||
"extras/coffee-script.js" is a concatenated and compressed version of the
|
||||
CoffeeScript compiler. To use it in the browser, include the script after any
|
||||
inline script tags of type "text/coffeescript" on the page. It will compile
|
||||
and evaluate all of the scripts in order.
|
||||
|
||||
File diff suppressed because one or more lines are too long
318
index.html
318
index.html
@@ -58,10 +58,10 @@
|
||||
<div class="screenshadow bl"></div>
|
||||
<div class="screenshadow br"></div>
|
||||
<div id="repl_source_wrap">
|
||||
<textarea id="repl_source" rows="100">alert "Hello CoffeeScript!"</textarea>
|
||||
<textarea id="repl_source" rows="100" spellcheck="false">alert "Hello CoffeeScript!"</textarea>
|
||||
</div>
|
||||
<div id="repl_results_wrap"><pre id="repl_results"></pre></div>
|
||||
<div class="minibutton dark run">Run</div>
|
||||
<div class="minibutton dark run" title="Ctrl-Enter">Run</div>
|
||||
<br class="clear" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.0.1">1.0.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.2">1.1.2</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -170,7 +170,7 @@ math <span class="Keyword">=</span> {
|
||||
winner <span class="Keyword">=</span> arguments[<span class="Number">0</span>], runners <span class="Keyword">=</span> <span class="Number">2</span> <span class="Keyword"><=</span> arguments.<span class="LibraryConstant">length</span> ? __slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">1</span>) : [];
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">print</span>(winner, runners);
|
||||
};
|
||||
<span class="Keyword">if</span> (<span class="Keyword">typeof</span> elvis <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> elvis <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) {
|
||||
<span class="Keyword">if</span> (<span class="Keyword">typeof</span> elvis <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> elvis <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>I knew it!<span class="String">"</span></span>);
|
||||
}
|
||||
cubes <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
@@ -205,7 +205,7 @@ race = function() {
|
||||
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
||||
return print(winner, runners);
|
||||
};
|
||||
if (typeof elvis != "undefined" && elvis !== null) {
|
||||
if (typeof elvis !== "undefined" && elvis !== null) {
|
||||
alert("I knew it!");
|
||||
}
|
||||
cubes = (function() {
|
||||
@@ -241,17 +241,21 @@ cubes = (function() {
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
npm install coffee-script</pre>
|
||||
npm install -g coffee-script</pre>
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
<p>
|
||||
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
sudo bin/cake install</pre>
|
||||
@@ -260,7 +264,9 @@ sudo bin/cake install</pre>
|
||||
If installing on Ubuntu or Debian,
|
||||
<a href="http://opinionated-programmer.com/2010/12/installing-coffeescript-on-debian-or-ubuntu/">be
|
||||
careful not to use the existing out-of-date package</a>. If installing on
|
||||
Windows, your best bet is probably to run Node.js under Cygwin.
|
||||
Windows, your best bet is probably to run Node.js under Cygwin. If you'd
|
||||
just like to experiment, you can try the
|
||||
<a href="https://github.com/alisey/CoffeeScript-Compiler-for-Windows">CoffeeScript Compiler For Windows</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -294,10 +300,11 @@ sudo bin/cake install</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-j, --join</code></td>
|
||||
<td><code>-j, --join [FILE]</code></td>
|
||||
<td>
|
||||
Before compiling, concatenate all scripts together in the order they
|
||||
were passed. Useful for building large projects.
|
||||
were passed, and write them into the specified file.
|
||||
Useful for building large projects.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -336,7 +343,7 @@ sudo bin/cake install</pre>
|
||||
<td><code>-e, --eval</code></td>
|
||||
<td>
|
||||
Compile and print a little snippet of CoffeeScript directly from the
|
||||
command line. For example:<br /><tt>coffee -e "puts num for num in [10..1]"</tt>
|
||||
command line. For example:<br /><tt>coffee -e "console.log num for num in [10..1]"</tt>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -379,7 +386,7 @@ Expressions
|
||||
<td><code>--nodejs</code></td>
|
||||
<td>
|
||||
The <tt>node</tt> executable has some useful options you can set,
|
||||
such as<br /> <tt>--debug</tt> and <tt>--max-stack-size</tt>. Use this
|
||||
such as<br /> <tt>--debug</tt>, <tt>--debug-brk</tt> and <tt>--max-stack-size</tt>. Use this
|
||||
flag to forward options directly to Node.js.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -401,7 +408,7 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
Concatenate a list of files into a single script:<br />
|
||||
<tt>coffee -o lib/ --join --compile src/*.coffee</tt>
|
||||
<tt>coffee --join project.js --compile src/*.coffee</tt>
|
||||
</li>
|
||||
<li>
|
||||
Print out the compiled JS from a one-liner:<br />
|
||||
@@ -437,8 +444,8 @@ Expressions
|
||||
<p>
|
||||
First, the basics: CoffeeScript uses significant whitespace to delimit blocks of code.
|
||||
You don't need to use semicolons <tt>;</tt> to terminate expressions,
|
||||
ending the line will do just as well, (although semicolons can still
|
||||
be used to fit multiple expressions onto a single line.)
|
||||
ending the line will do just as well (although semicolons can still
|
||||
be used to fit multiple expressions onto a single line).
|
||||
Instead of using curly braces
|
||||
<tt>{ }</tt> to surround blocks of code in <a href="#functions">functions</a>,
|
||||
<a href="#conditionals">if-statements</a>,
|
||||
@@ -634,7 +641,7 @@ inner = changeNumbers();;alert(inner);'>run: inner</div><br class='clear' /></di
|
||||
If you'd like to create top-level variables for other scripts to use,
|
||||
attach them as properties on <b>window</b>, or on the <b>exports</b>
|
||||
object in CommonJS. The <b>existential operator</b> (covered below), gives you a
|
||||
reliable way to figure out where to add them, if you're targeting both
|
||||
reliable way to figure out where to add them; if you're targeting both
|
||||
CommonJS and the browser: <tt>exports ? this</tt>
|
||||
</p>
|
||||
|
||||
@@ -797,7 +804,7 @@ countdown = (function() {
|
||||
each iteration into an array. Sometimes functions end with loops that are
|
||||
intended to run only for their side-effects. Be careful that you're not
|
||||
accidentally returning the results of the comprehension in these cases,
|
||||
by adding a meaningful return value, like <tt>true</tt>, or <tt>null</tt>,
|
||||
by adding a meaningful return value — like <tt>true</tt> — or <tt>null</tt>,
|
||||
to the bottom of your function.
|
||||
</p>
|
||||
<p>
|
||||
@@ -813,7 +820,7 @@ countdown = (function() {
|
||||
<div class='code'><pre class="idle">yearsOld <span class="Keyword">=</span> max: <span class="Number">10</span>, ida: <span class="Number">9</span>, tim: <span class="Number">11</span>
|
||||
|
||||
ages <span class="Keyword">=</span> <span class="Keyword">for</span> child, age <span class="Keyword">of</span> yearsOld
|
||||
child <span class="Keyword">+</span> <span class="String"><span class="String">"</span> is <span class="String">"</span></span> <span class="Keyword">+</span> age
|
||||
<span class="String"><span class="String">"</span><span class="String"><span class="String">#{</span>child<span class="String">}</span></span> is <span class="String"><span class="String">#{</span>age<span class="String">}</span></span><span class="String">"</span></span>
|
||||
</pre><pre class="idle"><span class="Storage">var</span> age, ages, child, yearsOld;
|
||||
yearsOld <span class="Keyword">=</span> {
|
||||
max: <span class="Number">10</span>,
|
||||
@@ -825,11 +832,11 @@ ages <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
_results <span class="Keyword">=</span> [];
|
||||
<span class="Keyword">for</span> (child <span class="Keyword">in</span> yearsOld) {
|
||||
age <span class="Keyword">=</span> yearsOld[child];
|
||||
_results.<span class="LibraryFunction">push</span>(child <span class="Keyword">+</span> <span class="String"><span class="String">"</span> is <span class="String">"</span></span> <span class="Keyword">+</span> age);
|
||||
_results.<span class="LibraryFunction">push</span>(<span class="String"><span class="String">"</span><span class="String">"</span></span> <span class="Keyword">+</span> child <span class="Keyword">+</span> <span class="String"><span class="String">"</span> is <span class="String">"</span></span> <span class="Keyword">+</span> age);
|
||||
}
|
||||
<span class="Keyword">return</span> _results;
|
||||
})();
|
||||
</pre><script>window.example11 = "yearsOld = max: 10, ida: 9, tim: 11\n\nages = for child, age of yearsOld\n child + \" is \" + age\n\nalert ages.join(\", \")"</script><div class='minibutton load' onclick='javascript: loadConsole(example11);'>load</div><div class='minibutton ok' onclick='javascript: var age, ages, child, yearsOld;
|
||||
</pre><script>window.example11 = "yearsOld = max: 10, ida: 9, tim: 11\n\nages = for child, age of yearsOld\n \"#{child} is #{age}\"\n\nalert ages.join(\", \")"</script><div class='minibutton load' onclick='javascript: loadConsole(example11);'>load</div><div class='minibutton ok' onclick='javascript: var age, ages, child, yearsOld;
|
||||
yearsOld = {
|
||||
max: 10,
|
||||
ida: 9,
|
||||
@@ -840,7 +847,7 @@ ages = (function() {
|
||||
_results = [];
|
||||
for (child in yearsOld) {
|
||||
age = yearsOld[child];
|
||||
_results.push(child + " is " + age);
|
||||
_results.push("" + child + " is " + age);
|
||||
}
|
||||
return _results;
|
||||
})();;alert(ages.join(", "));'>run: ages.join(", ")</div><br class='clear' /></div>
|
||||
@@ -864,7 +871,7 @@ ages = (function() {
|
||||
<span class="Comment"><span class="Comment">#</span> Nursery Rhyme</span>
|
||||
num <span class="Keyword">=</span> <span class="Number">6</span>
|
||||
lyrics <span class="Keyword">=</span> <span class="Keyword">while</span> num <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">1</span>
|
||||
num <span class="Keyword">+</span> <span class="String"><span class="String">"</span> little monkeys, jumping on the bed.</span>
|
||||
<span class="String"><span class="String">"</span><span class="String"><span class="String">#{</span>num<span class="String">}</span></span> little monkeys, jumping on the bed.</span>
|
||||
<span class="String"> One fell out and bumped his head.<span class="String">"</span></span>
|
||||
</pre><pre class="idle"><span class="Storage">var</span> lyrics, num;
|
||||
<span class="Keyword">if</span> (<span class="Variable">this</span>.studyingEconomics) {
|
||||
@@ -880,11 +887,11 @@ lyrics <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
<span class="Storage">var</span> _results;
|
||||
_results <span class="Keyword">=</span> [];
|
||||
<span class="Keyword">while</span> (num <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">1</span>) {
|
||||
_results.<span class="LibraryFunction">push</span>(num <span class="Keyword">+</span> <span class="String"><span class="String">"</span> little monkeys, jumping on the bed. One fell out and bumped his head.<span class="String">"</span></span>);
|
||||
_results.<span class="LibraryFunction">push</span>(<span class="String"><span class="String">"</span><span class="String">"</span></span> <span class="Keyword">+</span> num <span class="Keyword">+</span> <span class="String"><span class="String">"</span> little monkeys, jumping on the bed. One fell out and bumped his head.<span class="String">"</span></span>);
|
||||
}
|
||||
<span class="Keyword">return</span> _results;
|
||||
})();
|
||||
</pre><script>window.example12 = "# Econ 101\nif this.studyingEconomics\n buy() while supply > demand\n sell() until supply > demand\n\n# Nursery Rhyme\nnum = 6\nlyrics = while num -= 1\n num + \" little monkeys, jumping on the bed.\n One fell out and bumped his head.\"\n\nalert lyrics.join(\"\\n\")"</script><div class='minibutton load' onclick='javascript: loadConsole(example12);'>load</div><div class='minibutton ok' onclick='javascript: var lyrics, num;
|
||||
</pre><script>window.example12 = "# Econ 101\nif this.studyingEconomics\n buy() while supply > demand\n sell() until supply > demand\n\n# Nursery Rhyme\nnum = 6\nlyrics = while num -= 1\n \"#{num} little monkeys, jumping on the bed.\n One fell out and bumped his head.\"\n\nalert lyrics.join(\"\\n\")"</script><div class='minibutton load' onclick='javascript: loadConsole(example12);'>load</div><div class='minibutton ok' onclick='javascript: var lyrics, num;
|
||||
if (this.studyingEconomics) {
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
@@ -898,7 +905,7 @@ lyrics = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
while (num -= 1) {
|
||||
_results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
|
||||
_results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
|
||||
}
|
||||
return _results;
|
||||
})();;alert(lyrics.join("\n"));'>run: lyrics.join("\n")</div><br class='clear' /></div>
|
||||
@@ -934,7 +941,7 @@ lyrics = (function() {
|
||||
<b class="header">Array Slicing and Splicing with Ranges</b>
|
||||
Ranges can also be used to extract slices of arrays.
|
||||
With two dots (<tt>3..6</tt>), the range is inclusive (<tt>3, 4, 5, 6</tt>);
|
||||
with three docs (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
with three dots (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
</p>
|
||||
<div class='code'><pre class="idle">numbers <span class="Keyword">=</span> [<span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>, <span class="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>]
|
||||
|
||||
@@ -976,7 +983,7 @@ numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
to CoffeeScript functions, they nonetheless return their final value.
|
||||
The CoffeeScript compiler tries to make sure that all statements in the
|
||||
language can be used as expressions. Watch how the <tt>return</tt> gets
|
||||
pushed down into each possible branch of execution, in the function
|
||||
pushed down into each possible branch of execution in the function
|
||||
below.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="FunctionName">grade </span><span class="Keyword">=</span> <span class="FunctionArgument">(student)</span> <span class="Storage">-></span>
|
||||
@@ -1069,7 +1076,7 @@ globals = ((function() {
|
||||
<span class="Keyword">try</span>
|
||||
nonexistent <span class="Keyword">/</span> <span class="BuiltInConstant">undefined</span>
|
||||
<span class="Keyword">catch</span> error
|
||||
<span class="String"><span class="String">"</span>And the error is ... <span class="String">"</span></span> <span class="Keyword">+</span> error
|
||||
<span class="String"><span class="String">"</span>And the error is ... <span class="String"><span class="String">#{</span>error<span class="String">}</span></span><span class="String">"</span></span>
|
||||
)
|
||||
|
||||
</pre><pre class="idle"><span class="LibraryFunction">alert</span>((<span class="Storage">function</span>() {
|
||||
@@ -1079,7 +1086,7 @@ globals = ((function() {
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">"</span>And the error is ... <span class="String">"</span></span> <span class="Keyword">+</span> error;
|
||||
}
|
||||
})());
|
||||
</pre><script>window.example19 = "alert(\n try\n nonexistent / undefined\n catch error\n \"And the error is ... \" + error\n)\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example19);'>load</div><div class='minibutton ok' onclick='javascript: alert((function() {
|
||||
</pre><script>window.example19 = "alert(\n try\n nonexistent / undefined\n catch error\n \"And the error is ... #{error}\"\n)\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example19);'>load</div><div class='minibutton ok' onclick='javascript: alert((function() {
|
||||
try {
|
||||
return nonexistent / void 0;
|
||||
} catch (error) {
|
||||
@@ -1158,7 +1165,7 @@ letTheWildRumpusBegin() <span class="Keyword">unless</span> answer <span class="
|
||||
|
||||
winner <span class="Keyword">=</span> <span class="BuiltInConstant">yes</span> <span class="Keyword">if</span> pick <span class="Keyword">in</span> [<span class="Number">47</span>, <span class="Number">92</span>, <span class="Number">13</span>]
|
||||
|
||||
print inspect <span class="String"><span class="String">"</span>My name is <span class="String">"</span></span> <span class="Keyword">+</span> <span class="Variable">@name</span>
|
||||
print inspect <span class="String"><span class="String">"</span>My name is <span class="String"><span class="String">#{</span><span class="Variable">@name</span><span class="String">}</span></span><span class="String">"</span></span>
|
||||
</pre><pre class="idle"><span class="Storage">var</span> volume, winner;
|
||||
<span class="Keyword">if</span> (ignition <span class="Keyword">===</span> <span class="BuiltInConstant">true</span>) {
|
||||
launch();
|
||||
@@ -1176,7 +1183,7 @@ print inspect <span class="String"><span class="String">"</span>My name is
|
||||
winner <span class="Keyword">=</span> <span class="BuiltInConstant">true</span>;
|
||||
}
|
||||
<span class="LibraryFunction">print</span>(inspect(<span class="String"><span class="String">"</span>My name is <span class="String">"</span></span> <span class="Keyword">+</span> <span class="Variable">this</span>.<span class="LibraryConstant">name</span>));
|
||||
</pre><script>window.example20 = "launch() if ignition is on\n\nvolume = 10 if band isnt SpinalTap\n\nletTheWildRumpusBegin() unless answer is no\n\nif car.speed < limit then accelerate()\n\nwinner = yes if pick in [47, 92, 13]\n\nprint inspect \"My name is \" + @name\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example20);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example20 = "launch() if ignition is on\n\nvolume = 10 if band isnt SpinalTap\n\nletTheWildRumpusBegin() unless answer is no\n\nif car.speed < limit then accelerate()\n\nwinner = yes if pick in [47, 92, 13]\n\nprint inspect \"My name is #{@name}\"\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example20);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<b class="header">The Existential Operator</b>
|
||||
@@ -1201,17 +1208,21 @@ footprints <span class="Keyword">=</span> yeti <span class="Keyword">?</span> <s
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Storage">var</span> footprints, solipsism;
|
||||
<span class="Keyword">if</span> ((<span class="Keyword">typeof</span> mind <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) <span class="Keyword">&</span><span class="Keyword">&</span> <span class="Keyword">!</span>(<span class="Keyword">typeof</span> world <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>)) {
|
||||
<span class="Keyword">if</span> ((<span class="Keyword">typeof</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> mind <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>) <span class="Keyword">&</span><span class="Keyword">&</span> <span class="Keyword">!</span>(<span class="Keyword">typeof</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> world <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span>)) {
|
||||
solipsism <span class="Keyword">=</span> <span class="BuiltInConstant">true</span>;
|
||||
}
|
||||
<span class="Keyword">typeof</span> speed <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> speed <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span> ? speed : speed <span class="Keyword">=</span> <span class="Number">75</span>;
|
||||
footprints <span class="Keyword">=</span> <span class="Keyword">typeof</span> yeti <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span> ? yeti : <span class="String"><span class="String">"</span>bear<span class="String">"</span></span>;
|
||||
<span class="Keyword">if</span> (<span class="Keyword">typeof</span> speed <span class="Keyword">===</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">||</span> speed <span class="Keyword">===</span> <span class="BuiltInConstant">null</span>) {
|
||||
speed <span class="Keyword">=</span> <span class="Number">75</span>;
|
||||
}
|
||||
footprints <span class="Keyword">=</span> <span class="Keyword">typeof</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">&</span><span class="Keyword">&</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="BuiltInConstant">null</span> ? yeti : <span class="String"><span class="String">"</span>bear<span class="String">"</span></span>;
|
||||
</pre><script>window.example21 = "solipsism = true if mind? and not world?\n\nspeed ?= 75\n\nfootprints = yeti ? \"bear\"\n\nalert footprints"</script><div class='minibutton load' onclick='javascript: loadConsole(example21);'>load</div><div class='minibutton ok' onclick='javascript: var footprints, solipsism;
|
||||
if ((typeof mind != "undefined" && mind !== null) && !(typeof world != "undefined" && world !== null)) {
|
||||
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
|
||||
solipsism = true;
|
||||
}
|
||||
typeof speed != "undefined" && speed !== null ? speed : speed = 75;
|
||||
footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";;alert(footprints);'>run: footprints</div><br class='clear' /></div>
|
||||
if (typeof speed === "undefined" || speed === null) {
|
||||
speed = 75;
|
||||
}
|
||||
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";;alert(footprints);'>run: footprints</div><br class='clear' /></div>
|
||||
<p>
|
||||
The accessor variant of the existential operator <tt>?.</tt> can be used to soak
|
||||
up null references in a chain of properties. Use it instead
|
||||
@@ -1222,7 +1233,7 @@ footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";;alert(
|
||||
</p>
|
||||
<div class='code'><pre class="idle">zip <span class="Keyword">=</span> lottery.drawWinner<span class="Keyword">?</span>().address<span class="Keyword">?</span>.zipcode
|
||||
</pre><pre class="idle"><span class="Storage">var</span> zip, _ref;
|
||||
zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.drawWinner <span class="Keyword">==</span> <span class="String"><span class="String">"</span>function<span class="String">"</span></span> ? (_ref <span class="Keyword">=</span> lottery.drawWinner().address) <span class="Keyword">!</span><span class="Keyword">=</span> <span class="BuiltInConstant">null</span> ? _ref.zipcode : <span class="Storage">void</span> <span class="Number">0</span> : <span class="Storage">void</span> <span class="Number">0</span>;
|
||||
zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.drawWinner <span class="Keyword">===</span> <span class="String"><span class="String">"</span>function<span class="String">"</span></span> ? (_ref <span class="Keyword">=</span> lottery.drawWinner().address) <span class="Keyword">!</span><span class="Keyword">=</span> <span class="BuiltInConstant">null</span> ? _ref.zipcode : <span class="Storage">void</span> <span class="Number">0</span> : <span class="Storage">void</span> <span class="Number">0</span>;
|
||||
</pre><script>window.example22 = "zip = lottery.drawWinner?().address?.zipcode\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example22);'>load</div><br class='clear' /></div>
|
||||
<p>
|
||||
Soaking up nulls is similar to Ruby's
|
||||
@@ -1253,14 +1264,13 @@ zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.d
|
||||
in a single assignable expression.
|
||||
</p>
|
||||
<p>
|
||||
Constructor functions are named, to better support reflection. In the
|
||||
example below for the first class, <tt>this.constructor.name is "Animal"</tt>.
|
||||
Constructor functions are named, to better support helpful stack traces.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Storage">class</span> <span class="TypeName">Animal</span>
|
||||
<span class="FunctionName">constructor</span><span class="Keyword">:</span> <span class="FunctionArgument">(@name)</span> <span class="Storage">-></span>
|
||||
|
||||
<span class="FunctionName">move</span><span class="Keyword">:</span> <span class="FunctionArgument">(meters)</span> <span class="Storage">-></span>
|
||||
alert <span class="Variable">@name</span> <span class="Keyword">+</span> <span class="String"><span class="String">"</span> moved <span class="String">"</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">"</span>m.<span class="String">"</span></span>
|
||||
alert <span class="Variable">@name</span> <span class="Keyword">+</span> <span class="String"><span class="String">"</span> moved <span class="String"><span class="String">#{</span>meters<span class="String">}</span></span>m.<span class="String">"</span></span>
|
||||
|
||||
<span class="Storage">class</span> <span class="TypeName">Snake</span><span class="InheritedClass"> <span class="Keyword">extends</span> Animal</span>
|
||||
<span class="FunctionName">move</span><span class="Keyword">:</span> <span class="Keyword">-</span><span class="Keyword">></span>
|
||||
@@ -1295,15 +1305,15 @@ Animal <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
|
||||
}
|
||||
<span class="LibraryClassType">Animal</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>(<span class="FunctionArgument">meters</span>) {
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">alert</span>(<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">+</span> <span class="String"><span class="String">"</span> moved <span class="String">"</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">"</span>m.<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">alert</span>(<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">+</span> (<span class="String"><span class="String">"</span> moved <span class="String">"</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">"</span>m.<span class="String">"</span></span>));
|
||||
};
|
||||
<span class="Keyword">return</span> Animal;
|
||||
})();
|
||||
Snake <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
__extends(Snake, Animal);
|
||||
<span class="Storage">function</span> <span class="FunctionName">Snake</span>() {
|
||||
Snake.__super__.<span class="LibraryConstant">constructor</span>.<span class="LibraryFunction">apply</span>(<span class="Variable">this</span>, arguments);
|
||||
}
|
||||
__extends(Snake, Animal);
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>Slithering...<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> Snake.__super__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">5</span>);
|
||||
@@ -1311,10 +1321,10 @@ Snake <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
<span class="Keyword">return</span> Snake;
|
||||
})();
|
||||
Horse <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
__extends(Horse, Animal);
|
||||
<span class="Storage">function</span> <span class="FunctionName">Horse</span>() {
|
||||
Horse.__super__.<span class="LibraryConstant">constructor</span>.<span class="LibraryFunction">apply</span>(<span class="Variable">this</span>, arguments);
|
||||
}
|
||||
__extends(Horse, Animal);
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>Galloping...<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> Horse.__super__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">45</span>);
|
||||
@@ -1325,7 +1335,7 @@ sam <span class="Keyword">=</span> <span class="Keyword">new</span> <span class=
|
||||
tom <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Horse</span>(<span class="String"><span class="String">"</span>Tommy the Palomino<span class="String">"</span></span>);
|
||||
sam.move();
|
||||
tom.move();
|
||||
</pre><script>window.example23 = "class Animal\n constructor: (@name) ->\n\n move: (meters) ->\n alert @name + \" moved \" + meters + \"m.\"\n\nclass Snake extends Animal\n move: ->\n alert \"Slithering...\"\n super 5\n\nclass Horse extends Animal\n move: ->\n alert \"Galloping...\"\n super 45\n\nsam = new Snake \"Sammy the Python\"\ntom = new Horse \"Tommy the Palomino\"\n\nsam.move()\ntom.move()\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example23);'>load</div><div class='minibutton ok' onclick='javascript: var Animal, Horse, Snake, sam, tom;
|
||||
</pre><script>window.example23 = "class Animal\n constructor: (@name) ->\n\n move: (meters) ->\n alert @name + \" moved #{meters}m.\"\n\nclass Snake extends Animal\n move: ->\n alert \"Slithering...\"\n super 5\n\nclass Horse extends Animal\n move: ->\n alert \"Galloping...\"\n super 45\n\nsam = new Snake \"Sammy the Python\"\ntom = new Horse \"Tommy the Palomino\"\n\nsam.move()\ntom.move()\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example23);'>load</div><div class='minibutton ok' onclick='javascript: var Animal, Horse, Snake, sam, tom;
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
|
||||
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
|
||||
function ctor() { this.constructor = child; }
|
||||
@@ -1339,15 +1349,15 @@ Animal = (function() {
|
||||
this.name = name;
|
||||
}
|
||||
Animal.prototype.move = function(meters) {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
return alert(this.name + (" moved " + meters + "m."));
|
||||
};
|
||||
return Animal;
|
||||
})();
|
||||
Snake = (function() {
|
||||
__extends(Snake, Animal);
|
||||
function Snake() {
|
||||
Snake.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
__extends(Snake, Animal);
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return Snake.__super__.move.call(this, 5);
|
||||
@@ -1355,10 +1365,10 @@ Snake = (function() {
|
||||
return Snake;
|
||||
})();
|
||||
Horse = (function() {
|
||||
__extends(Horse, Animal);
|
||||
function Horse() {
|
||||
Horse.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
__extends(Horse, Animal);
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return Horse.__super__.move.call(this, 45);
|
||||
@@ -1372,8 +1382,9 @@ tom.move();;'>run</div><br class='clear' /></div>
|
||||
<p>
|
||||
If structuring your prototypes classically isn't your cup of tea, CoffeeScript
|
||||
provides a couple of lower-level conveniences. The <tt>extends</tt> operator
|
||||
helps with proper prototype setup, <tt>::</tt> gives you
|
||||
quick access to an object's prototype, and <tt>super()</tt>
|
||||
helps with proper prototype setup, and can be used to create an inheritance
|
||||
chain between any pair of constructor functions; <tt>::</tt> gives you
|
||||
quick access to an object's prototype; and <tt>super()</tt>
|
||||
is converted into a call against the immediate ancestor's method of the same name.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="FunctionName">String::dasherize </span><span class="Keyword">=</span> <span class="Keyword">-</span><span class="Keyword">></span>
|
||||
@@ -1386,7 +1397,7 @@ tom.move();;'>run</div><br class='clear' /></div>
|
||||
return this.replace(/_/g, "-");
|
||||
};;alert("one_two".dasherize());'>run: "one_two".dasherize()</div><br class='clear' /></div>
|
||||
<p>
|
||||
Finally class definitions are blocks of executable code, which make for interesting
|
||||
Finally, class definitions are blocks of executable code, which make for interesting
|
||||
metaprogramming possibilities. Because in the context of a class definition,
|
||||
<tt>this</tt> is the class object itself (the constructor function), you
|
||||
can assign static properties by using <br /><tt>@property: value</tt>, and call
|
||||
@@ -1500,7 +1511,7 @@ _ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call
|
||||
<b class="header">Function binding</b>
|
||||
In JavaScript, the <tt>this</tt> keyword is dynamically scoped to mean the
|
||||
object that the current function is attached to. If you pass a function as
|
||||
as callback, or attach it to a different object, the original value of <tt>this</tt>
|
||||
a callback or attach it to a different object, the original value of <tt>this</tt>
|
||||
will be lost. If you're not familiar with this behavior,
|
||||
<a href="http://www.digital-web.com/articles/scope_in_javascript/">this Digital Web article</a>
|
||||
gives a good overview of the quirks.
|
||||
@@ -1708,20 +1719,20 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
<p>
|
||||
Sometimes you'd like to pass a block comment through to the generated
|
||||
JavaScript. For example, when you need to embed a licensing header at
|
||||
the top of a file. Block comments, which mirror the synax for heredocs,
|
||||
the top of a file. Block comments, which mirror the syntax for heredocs,
|
||||
are preserved in the generated code.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">###</span></span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.0.1</span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.1.2</span>
|
||||
<span class="Comment">Released under the MIT License</span>
|
||||
<span class="Comment"><span class="Comment">###</span></span>
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Comment"><span class="Comment">/*</span></span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.0.1</span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.1.2</span>
|
||||
<span class="Comment">Released under the MIT License</span>
|
||||
<span class="Comment"><span class="Comment">*/</span></span>
|
||||
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.0.1\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.1.2\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="regexes" class="bookmark"></span>
|
||||
@@ -1813,7 +1824,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
|
||||
<p>
|
||||
In fact, the little bit of glue script that runs "Try CoffeeScript" above,
|
||||
as well as jQuery for the menu, is implemented in just this way.
|
||||
as well as the jQuery for the menu, is implemented in just this way.
|
||||
View source and look at the bottom of the page to see the example.
|
||||
Including the script also gives you access to <tt>CoffeeScript.compile()</tt>
|
||||
so you can pop open Firebug and try compiling some strings.
|
||||
@@ -1831,6 +1842,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
|
||||
a zero-configuration Rack server, with comprehensive annotated source.
|
||||
</li>
|
||||
<li>
|
||||
<b>frank06</b>'s <a href="http://riakjs.org/">riak-js</a>, a Node.js client for
|
||||
<a href="http://www.basho.com/Riak.html">Riak</a>, with support for HTTP
|
||||
@@ -1840,6 +1855,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<b>technoweenie</b>'s <a href="https://github.com/technoweenie/coffee-resque">Coffee-Resque</a>,
|
||||
a port of <a href="https://github.com/defunkt/resque">Resque</a> for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
|
||||
A headless, full-stack, faux-browser testing library for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
|
||||
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
|
||||
@@ -1853,10 +1872,6 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
|
||||
<a href="http://rack.rubyforge.org/">Rack</a> server.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://sstephenson.github.com/strscan-js/">StringScanner</a>,
|
||||
a simple tokenizer and lexical scanner for JavaScript strings.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
@@ -1879,102 +1894,23 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://github.com/jashkenas/coffee-script/issues">CoffeeScript Issues</a><br />
|
||||
Bugs reports, feature requests, and general discussion all belong here.
|
||||
Bug reports, feature proposals, and ideas for changes to the language belong here.
|
||||
</li>
|
||||
<li>
|
||||
If you'd like to chat, stop by <tt>#coffeescript</tt> on Freenode in the
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
<a href="https://groups.google.com/forum/#!forum/coffeescript">CoffeeScript Google Group</a><br />
|
||||
If you'd like to ask a question, the mailing list is a good place to get help.
|
||||
</li>
|
||||
<li>
|
||||
<b>satyr</b>'s <a href="http://github.com/satyr/coco">Coco</a>
|
||||
— An avant-garde dialect of CoffeeScript that frequently pioneers
|
||||
features and optimizations, some of which CoffeeScript later adopts.
|
||||
Check out the <a href="https://github.com/satyr/coco/wiki/additions">list of additions</a>
|
||||
to the language.
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki">The CoffeeScript Wiki</a><br />
|
||||
If you've ever learned a neat CoffeeScript tip or trick, or ran into a gotcha — share it on the wiki.
|
||||
The wiki also serves as a directory of handy
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/Text-editor-plugins">text editor extensions</a>,
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/Web-framework-plugins">web framework plugins</a>,
|
||||
and general <a href="http://github.com/jashkenas/coffee-script/wiki/Build-tools">CoffeeScript build tools</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
|
||||
— A Java Library that uses Rhino to compile CoffeeScript, allowing
|
||||
compilation within Java projects or on systems that Node.js doesn't support.
|
||||
</li>
|
||||
<li>
|
||||
<b>defunkt</b>'s <a href="http://github.com/defunkt/coffee-mode">CoffeeScript Major Mode</a>
|
||||
— a Emacs major mode that provides syntax highlighting, indentation
|
||||
support, and some bonus commands.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="http://github.com/jashkenas/coffee-script-tmbundle">CoffeeScript TextMate Bundle</a>
|
||||
— which provides syntax highlighting, snippet expansion, and the
|
||||
ability to run bits of CoffeeScript from within TextMate itself.
|
||||
</li>
|
||||
<li>
|
||||
<b>kchmck</b>'s <a href="http://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a>
|
||||
— which adds Vim syntax highlighting and indentation support.
|
||||
</li>
|
||||
<li>
|
||||
<b>wavded</b>'s <a href="http://github.com/wavded/gedit-coffeescript">gedit-coffeescript</a>
|
||||
— a CoffeeScript syntax highlighter for the gedit text editor.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>dhotson</b>'s <a href="https://github.com/dhotson/coffeescript-jedit">coffeescript-jedit</a>
|
||||
— which provides syntax highlighting support in jEdit.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
compiled JavaScript on the fly.
|
||||
</li>
|
||||
<li>
|
||||
<b>jnicklas</b>'s <a href="http://github.com/jnicklas/bistro_car">BistroCar</a>
|
||||
— a plugin that serves and bundles CoffeeScript from within your
|
||||
Rails application.
|
||||
</li>
|
||||
<li>
|
||||
<b>dsc</b>'s <a href="http://github.com/dsc/coffeecup">CoffeeCup</a>
|
||||
— a Python WSGI middleware that compiles CoffeeScript to JavaScript
|
||||
on-demand during development.
|
||||
</li>
|
||||
<li>
|
||||
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
|
||||
— a BistroCar alternative that integrates well with
|
||||
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
|
||||
</li>
|
||||
<li>
|
||||
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
|
||||
— a custom filter for rendering CoffeeScript inline within
|
||||
<a href="http://haml-lang.com/">HAML</a> templates.
|
||||
</li>
|
||||
<li>
|
||||
<b>andrzejsliwa</b>'s <a href="http://github.com/andrzejsliwa/coffeeapp">CoffeeApp</a>
|
||||
— a CoffeeScript wrapper for CouchApps, web applications served
|
||||
directly from CouchDB.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://github.com/sstephenson/eco">Eco</a>
|
||||
— high-performance embedded CoffeeScript templates, after EJS and ERB.
|
||||
</li>
|
||||
<li>
|
||||
<b>mauricemach</b>'s <a href="http://github.com/mauricemach/coffeekup">CoffeeKup</a>
|
||||
— Markup as CoffeeScript. After _why's
|
||||
<a href="http://markaby.github.com/">Markaby</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="http://jashkenas.github.com/docco/">Docco</a>
|
||||
— a quick-and-dirty literate-programming-style documentation generator
|
||||
for CoffeeScript. Used to produce the annotated source.
|
||||
</li>
|
||||
<li>
|
||||
<b>naturalethic</b>'s <a href="http://github.com/naturalethic/coffee-mongo">coffee-mongo</a>
|
||||
— an asynchronous MongoDB ORM, for use with Node.js and CoffeeScript.
|
||||
</li>
|
||||
<li>
|
||||
<b>mauricemach</b>'s <a href="https://github.com/mauricemach/zappa">Zappa</a>
|
||||
— a DSL for building web apps, built on top of Express and Socket.IO.
|
||||
<a href="http://github.com/jashkenas/coffee-script/wiki/FAQ">The FAQ</a><br />
|
||||
Perhaps your CoffeeScript-related question has been asked before. Check the FAQ first.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1998,16 +1934,58 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">
|
||||
<a href="https://github.com/jashkenas/coffee-script/compare/1.1.1...1.1.2">1.1.2</a>
|
||||
<span class="timestamp"> – <small>August 4, 2011</small></span>
|
||||
</b>
|
||||
We now use the native <tt>Function.prototype.bind</tt> for bound function
|
||||
literals where available.
|
||||
Fixes for: block comment formatting, <tt>?=</tt> compilation, implicit calls
|
||||
against control structures, implicit invocation of a try/catch block,
|
||||
variadic arguments leaking from local scope, line numbers in syntax errors
|
||||
following heregexes, property access on parenthesized number literals,
|
||||
bound class methods and super with reserved names, a REPL overhaul,
|
||||
consecutive compiled semicolons, block comments in implicitly called objects,
|
||||
and a Chrome bug.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.1
|
||||
<span class="timestamp"> – <small>May 10, 2011</small></span>
|
||||
</b>
|
||||
Bugfix release for classes with external constructor functions, see
|
||||
issue #1182.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.0
|
||||
<span class="timestamp"> – <small>May 1, 2011</small></span>
|
||||
</b>
|
||||
When running via the <tt>coffee</tt> executable, <tt>process.argv</tt> and
|
||||
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
|
||||
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
|
||||
The output in the REPL is now colorized, like Node's is.
|
||||
Giving your concatenated CoffeeScripts a name when using <tt>--join</tt> is now mandatory.
|
||||
Fix for lexing compound division <tt>/=</tt> as a regex accidentally.
|
||||
All <tt>text/coffeescript</tt> tags should now execute in the order they're included.
|
||||
Fixed an issue with extended subclasses using external constructor functions.
|
||||
Fixed an edge-case infinite loop in <tt>addImplicitParentheses</tt>.
|
||||
Fixed exponential slowdown with long chains of function calls.
|
||||
Globals no longer leak into the CoffeeScript REPL.
|
||||
Splatted parameters are declared local to the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.0.1
|
||||
<span class="timestamp"> – <small>Jan 31, 2011</small></span>
|
||||
</b>
|
||||
Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility
|
||||
with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing
|
||||
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
|
||||
Stopped requiring the core Node.js <tt>"util"</tt> module for
|
||||
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
|
||||
Stopped requiring the core Node.js <tt>"util"</tt> module for
|
||||
back-compatibility with Node.js 0.2.5. Fixed a case where a
|
||||
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
|
||||
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
|
||||
statement. Optimized empty objects in destructuring assignment.
|
||||
</p>
|
||||
|
||||
@@ -2484,7 +2462,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
$('#repl_source').keyup -> compileSource()
|
||||
|
||||
# Eval the compiled js.
|
||||
$('.minibutton.run').click ->
|
||||
evalJS = ->
|
||||
try
|
||||
eval window.compiledJS
|
||||
catch error then alert error
|
||||
@@ -2500,6 +2478,8 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
closeMenus = ->
|
||||
$('.navigation.active').removeClass 'active'
|
||||
|
||||
$('.minibutton.run').click evalJS
|
||||
|
||||
# Bind navigation buttons to open the menus.
|
||||
$('.navigation').click (e) ->
|
||||
return if e.target.tagName.toLowerCase() is 'a'
|
||||
@@ -2511,9 +2491,15 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
$(this).addClass 'active'
|
||||
false
|
||||
|
||||
$(document.body).click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
# Dismiss console if Escape pressed or click falls outside console
|
||||
# Trigger Run button on Ctrl-Enter
|
||||
$(document.body)
|
||||
.keydown (e) ->
|
||||
closeMenus() if e.which == 27
|
||||
evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length
|
||||
.click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
|
||||
$('#open_webchat').click ->
|
||||
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
options.bare = true;
|
||||
return Function(CoffeeScript.compile(code, options))();
|
||||
};
|
||||
if (typeof window == "undefined" || window === null) {
|
||||
if (typeof window === "undefined" || window === null) {
|
||||
return;
|
||||
}
|
||||
CoffeeScript.load = function(url, options) {
|
||||
CoffeeScript.load = function(url, callback) {
|
||||
var xhr;
|
||||
xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP');
|
||||
xhr.open('GET', url, true);
|
||||
@@ -23,25 +23,48 @@
|
||||
xhr.overrideMimeType('text/plain');
|
||||
}
|
||||
xhr.onreadystatechange = function() {
|
||||
var _ref;
|
||||
if (xhr.readyState === 4) {
|
||||
return CoffeeScript.run(xhr.responseText, options);
|
||||
if ((_ref = xhr.status) === 0 || _ref === 200) {
|
||||
CoffeeScript.run(xhr.responseText);
|
||||
} else {
|
||||
throw new Error("Could not load " + url);
|
||||
}
|
||||
if (callback) {
|
||||
return callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
return xhr.send(null);
|
||||
};
|
||||
runScripts = function() {
|
||||
var script, _i, _len, _ref;
|
||||
_ref = document.getElementsByTagName('script');
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
script = _ref[_i];
|
||||
if (script.type === 'text/coffeescript') {
|
||||
if (script.src) {
|
||||
CoffeeScript.load(script.src);
|
||||
} else {
|
||||
CoffeeScript.run(script.innerHTML);
|
||||
var coffees, execute, index, length, s, scripts;
|
||||
scripts = document.getElementsByTagName('script');
|
||||
coffees = (function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
|
||||
s = scripts[_i];
|
||||
if (s.type === 'text/coffeescript') {
|
||||
_results.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
index = 0;
|
||||
length = coffees.length;
|
||||
(execute = function() {
|
||||
var script;
|
||||
script = coffees[index++];
|
||||
if ((script != null ? script.type : void 0) === 'text/coffeescript') {
|
||||
if (script.src) {
|
||||
return CoffeeScript.load(script.src, execute);
|
||||
} else {
|
||||
CoffeeScript.run(script.innerHTML);
|
||||
return execute();
|
||||
}
|
||||
}
|
||||
})();
|
||||
return null;
|
||||
};
|
||||
if (window.addEventListener) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(function() {
|
||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
||||
@@ -7,7 +8,9 @@
|
||||
if (require.extensions) {
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
var content;
|
||||
content = compile(fs.readFileSync(filename, 'utf8'));
|
||||
content = compile(fs.readFileSync(filename, 'utf8'), {
|
||||
filename: filename
|
||||
});
|
||||
return module._compile(content, filename);
|
||||
};
|
||||
} else if (require.registerExtension) {
|
||||
@@ -15,7 +18,7 @@
|
||||
return compile(content);
|
||||
});
|
||||
}
|
||||
exports.VERSION = '1.0.1';
|
||||
exports.VERSION = '1.1.2';
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.helpers = require('./helpers');
|
||||
exports.compile = compile = function(code, options) {
|
||||
@@ -42,32 +45,82 @@
|
||||
}
|
||||
};
|
||||
exports.run = function(code, options) {
|
||||
var root;
|
||||
root = module;
|
||||
while (root.parent) {
|
||||
root = root.parent;
|
||||
var Module, mainModule;
|
||||
mainModule = require.main;
|
||||
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
mainModule.moduleCache && (mainModule.moduleCache = {});
|
||||
if (process.binding('natives').module) {
|
||||
Module = require('module').Module;
|
||||
mainModule.paths = Module._nodeModulePaths(path.dirname(options.filename));
|
||||
}
|
||||
root.filename = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
if (root.moduleCache) {
|
||||
root.moduleCache = {};
|
||||
}
|
||||
if (path.extname(root.filename) !== '.coffee' || require.extensions) {
|
||||
return root._compile(compile(code, options), root.filename);
|
||||
if (path.extname(mainModule.filename) !== '.coffee' || require.extensions) {
|
||||
return mainModule._compile(compile(code, options), mainModule.filename);
|
||||
} else {
|
||||
return root._compile(code, root.filename);
|
||||
return mainModule._compile(code, mainModule.filename);
|
||||
}
|
||||
};
|
||||
exports.eval = function(code, options) {
|
||||
var __dirname, __filename;
|
||||
__filename = module.filename = options.filename;
|
||||
__dirname = path.dirname(__filename);
|
||||
return eval(compile(code, options));
|
||||
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref2, _ref3, _ref4, _require;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
if (!(code = code.trim())) {
|
||||
return;
|
||||
}
|
||||
if (_ref2 = require('vm'), Script = _ref2.Script, _ref2) {
|
||||
sandbox = Script.createContext();
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox;
|
||||
if (options.sandbox != null) {
|
||||
if (options.sandbox instanceof sandbox.constructor) {
|
||||
sandbox = options.sandbox;
|
||||
} else {
|
||||
_ref3 = options.sandbox;
|
||||
for (k in _ref3) {
|
||||
if (!__hasProp.call(_ref3, k)) continue;
|
||||
v = _ref3[k];
|
||||
sandbox[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
sandbox.__filename = options.filename || 'eval';
|
||||
sandbox.__dirname = path.dirname(sandbox.__filename);
|
||||
if (!(sandbox.module || sandbox.require)) {
|
||||
Module = require('module');
|
||||
sandbox.module = _module = new Module(options.modulename || 'eval');
|
||||
sandbox.require = _require = function(path) {
|
||||
return Module._load(path, _module);
|
||||
};
|
||||
_module.filename = sandbox.__filename;
|
||||
_ref4 = Object.getOwnPropertyNames(require);
|
||||
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
|
||||
r = _ref4[_i];
|
||||
_require[r] = require[r];
|
||||
}
|
||||
_require.paths = _module.paths = Module._nodeModulePaths(process.cwd());
|
||||
_require.resolve = function(request) {
|
||||
return Module._resolveFilename(request, _module);
|
||||
};
|
||||
}
|
||||
}
|
||||
o = {};
|
||||
for (k in options) {
|
||||
if (!__hasProp.call(options, k)) continue;
|
||||
v = options[k];
|
||||
o[k] = v;
|
||||
}
|
||||
o.bare = true;
|
||||
js = compile(code, o);
|
||||
if (Script) {
|
||||
return Script.runInContext(js, sandbox);
|
||||
} else {
|
||||
return eval(js);
|
||||
}
|
||||
};
|
||||
lexer = new Lexer;
|
||||
parser.lexer = {
|
||||
lex: function() {
|
||||
var tag, _ref;
|
||||
_ref = this.tokens[this.pos++] || [''], tag = _ref[0], this.yytext = _ref[1], this.yylineno = _ref[2];
|
||||
var tag, _ref2;
|
||||
_ref2 = this.tokens[this.pos++] || [''], tag = _ref2[0], this.yytext = _ref2[1], this.yylineno = _ref2[2];
|
||||
return tag;
|
||||
},
|
||||
setInput: function(tokens) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
return process.binding('stdio').writeError(line + '\n');
|
||||
};
|
||||
BANNER = 'Usage: coffee [options] path/to/script.coffee';
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-j', '--join', 'concatenate the scripts before compiling'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['--nodejs [ARGS]', 'pass options through to the "node" binary'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-j', '--join [FILE]', 'concatenate the scripts before compiling'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-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 = [];
|
||||
@@ -50,35 +50,65 @@
|
||||
opts.literals = sources.splice(1).concat(opts.literals);
|
||||
}
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat(opts.literals);
|
||||
process.argv[0] = 'coffee';
|
||||
process.execPath = require.main.filename;
|
||||
return compileScripts();
|
||||
};
|
||||
compileScripts = function() {
|
||||
var base, compile, source, _i, _len, _results;
|
||||
_results = [];
|
||||
var base, compile, source, unprocessed, _i, _j, _len, _len2, _results;
|
||||
unprocessed = [];
|
||||
for (_i = 0, _len = sources.length; _i < _len; _i++) {
|
||||
source = sources[_i];
|
||||
unprocessed[sources.indexOf(source)] = 1;
|
||||
}
|
||||
_results = [];
|
||||
for (_j = 0, _len2 = sources.length; _j < _len2; _j++) {
|
||||
source = sources[_j];
|
||||
base = path.join(source);
|
||||
compile = function(source, topLevel) {
|
||||
compile = function(source, sourceIndex, topLevel) {
|
||||
var remaining_files;
|
||||
remaining_files = function() {
|
||||
var total, x, _k, _len3;
|
||||
total = 0;
|
||||
for (_k = 0, _len3 = unprocessed.length; _k < _len3; _k++) {
|
||||
x = unprocessed[_k];
|
||||
total += x;
|
||||
}
|
||||
return total;
|
||||
};
|
||||
return path.exists(source, function(exists) {
|
||||
if (topLevel && !exists && source.slice(-7) !== '.coffee') {
|
||||
return compile("" + source + ".coffee", sourceIndex, topLevel);
|
||||
}
|
||||
if (topLevel && !exists) {
|
||||
throw new Error("File not found: " + source);
|
||||
}
|
||||
return fs.stat(source, function(err, stats) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
if (stats.isDirectory()) {
|
||||
return fs.readdir(source, function(err, files) {
|
||||
var file, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
||||
file = files[_i];
|
||||
_results.push(compile(path.join(source, file)));
|
||||
var file, _k, _len3;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
return _results;
|
||||
unprocessed[sourceIndex] += files.length;
|
||||
for (_k = 0, _len3 = files.length; _k < _len3; _k++) {
|
||||
file = files[_k];
|
||||
compile(path.join(source, file), sourceIndex);
|
||||
}
|
||||
return unprocessed[sourceIndex] -= 1;
|
||||
});
|
||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
||||
fs.readFile(source, function(err, code) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
unprocessed[sourceIndex] -= 1;
|
||||
if (opts.join) {
|
||||
contents[sources.indexOf(source)] = code.toString();
|
||||
if (helpers.compact(contents).length === sources.length) {
|
||||
contents[sourceIndex] = helpers.compact([contents[sourceIndex], code.toString()]).join('\n');
|
||||
if (helpers.compact(contents).length > 0 && remaining_files() === 0) {
|
||||
return compileJoin();
|
||||
}
|
||||
} else {
|
||||
@@ -88,11 +118,13 @@
|
||||
if (opts.watch && !opts.join) {
|
||||
return watch(source, base);
|
||||
}
|
||||
} else {
|
||||
return unprocessed[sourceIndex] -= 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
_results.push(compile(source, true));
|
||||
_results.push(compile(source, sources.indexOf(source), true));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
@@ -152,15 +184,15 @@
|
||||
compileJoin = function() {
|
||||
var code;
|
||||
code = contents.join('\n');
|
||||
return compileScript("concatenation", code, "concatenation");
|
||||
return compileScript(opts.join, code, opts.join);
|
||||
};
|
||||
loadRequires = function() {
|
||||
var realFilename, req, _i, _len, _ref;
|
||||
var realFilename, req, _i, _len, _ref2;
|
||||
realFilename = module.filename;
|
||||
module.filename = '.';
|
||||
_ref = opts.require;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
req = _ref[_i];
|
||||
_ref2 = opts.require;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
req = _ref2[_i];
|
||||
require(req);
|
||||
}
|
||||
return module.filename = realFilename;
|
||||
@@ -196,7 +228,7 @@
|
||||
if (err) {
|
||||
return printLine(err.message);
|
||||
} else if (opts.compile && opts.watch) {
|
||||
return console.log("" + ((new Date).toTimeString()) + " - compiled " + source);
|
||||
return console.log("" + ((new Date).toLocaleTimeString()) + " - compiled " + source);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -223,11 +255,11 @@
|
||||
printTokens = function(tokens) {
|
||||
var strings, tag, token, value;
|
||||
strings = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
var _i, _len, _ref2, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
|
||||
token = tokens[_i];
|
||||
_ref = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref[0], value = _ref[1];
|
||||
_ref2 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref2[0], value = _ref2[1];
|
||||
_results.push("[" + tag + " " + value + "]");
|
||||
}
|
||||
return _results;
|
||||
|
||||
@@ -169,13 +169,11 @@
|
||||
return new Access($2, 'proto');
|
||||
}), o('::', function() {
|
||||
return new Access(new Literal('prototype'));
|
||||
}), o('Index'), o('Slice', function() {
|
||||
return new Slice($1);
|
||||
})
|
||||
}), o('Index')
|
||||
],
|
||||
Index: [
|
||||
o('INDEX_START Expression INDEX_END', function() {
|
||||
return new Index($2);
|
||||
o('INDEX_START IndexValue INDEX_END', function() {
|
||||
return $2;
|
||||
}), o('INDEX_SOAK Index', function() {
|
||||
return extend($2, {
|
||||
soak: true
|
||||
@@ -186,6 +184,13 @@
|
||||
});
|
||||
})
|
||||
],
|
||||
IndexValue: [
|
||||
o('Expression', function() {
|
||||
return new Index($1);
|
||||
}), o('Slice', function() {
|
||||
return new Slice($1);
|
||||
})
|
||||
],
|
||||
Object: [
|
||||
o('{ AssignList OptComma }', function() {
|
||||
return new Obj($2, $1.generated);
|
||||
@@ -280,12 +285,12 @@
|
||||
})
|
||||
],
|
||||
Slice: [
|
||||
o('INDEX_START Expression RangeDots Expression INDEX_END', function() {
|
||||
return new Range($2, $4, $3);
|
||||
}), o('INDEX_START Expression RangeDots INDEX_END', function() {
|
||||
return new Range($2, null, $3);
|
||||
}), o('INDEX_START RangeDots Expression INDEX_END', function() {
|
||||
return new Range(null, $3, $2);
|
||||
o('Expression RangeDots Expression', function() {
|
||||
return new Range($1, $3, $2);
|
||||
}), o('Expression RangeDots', function() {
|
||||
return new Range($1, null, $2);
|
||||
}), o('RangeDots Expression', function() {
|
||||
return new Range(null, $2, $1);
|
||||
})
|
||||
],
|
||||
ArgList: [
|
||||
|
||||
102
lib/lexer.js
102
lib/lexer.js
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, last, op, starts, _ref;
|
||||
var ASSIGNED, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref;
|
||||
var __indexOf = Array.prototype.indexOf || function(item) {
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
if (this[i] === item) return i;
|
||||
@@ -37,7 +37,7 @@
|
||||
return (new Rewriter).rewrite(this.tokens);
|
||||
};
|
||||
Lexer.prototype.identifierToken = function() {
|
||||
var colon, forcedIdentifier, id, input, match, prev, tag, _ref, _ref2;
|
||||
var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
|
||||
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
@@ -46,11 +46,11 @@
|
||||
this.token('OWN', id);
|
||||
return id.length;
|
||||
}
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && !prev.spaced && ((_ref = prev[0]) === '.' || _ref === '?.' || _ref === '@' || _ref === '::');
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
|
||||
tag = 'IDENTIFIER';
|
||||
if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) {
|
||||
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
|
||||
tag = id.toUpperCase();
|
||||
if (tag === 'WHEN' && (_ref2 = this.tag(), __indexOf.call(LINE_BREAK, _ref2) >= 0)) {
|
||||
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
|
||||
tag = 'LEADING_WHEN';
|
||||
} else if (tag === 'FOR') {
|
||||
this.seenFor = true;
|
||||
@@ -81,8 +81,8 @@
|
||||
}
|
||||
}
|
||||
if (!forcedIdentifier) {
|
||||
if (COFFEE_ALIASES.hasOwnProperty(id)) {
|
||||
id = COFFEE_ALIASES[id];
|
||||
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
|
||||
id = COFFEE_ALIAS_MAP[id];
|
||||
}
|
||||
tag = (function() {
|
||||
switch (id) {
|
||||
@@ -175,7 +175,6 @@
|
||||
return 0;
|
||||
}
|
||||
comment = match[0], here = match[1];
|
||||
this.line += count(comment, '\n');
|
||||
if (here) {
|
||||
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
|
||||
herecomment: true,
|
||||
@@ -183,6 +182,7 @@
|
||||
}));
|
||||
this.token('TERMINATOR', '\n');
|
||||
}
|
||||
this.line += count(comment, '\n');
|
||||
return comment.length;
|
||||
};
|
||||
Lexer.prototype.jsToken = function() {
|
||||
@@ -194,15 +194,17 @@
|
||||
return script.length;
|
||||
};
|
||||
Lexer.prototype.regexToken = function() {
|
||||
var match, prev, regex, _ref;
|
||||
var length, match, prev, regex, _ref2;
|
||||
if (this.chunk.charAt(0) !== '/') {
|
||||
return 0;
|
||||
}
|
||||
if (match = HEREGEX.exec(this.chunk)) {
|
||||
return this.heregexToken(match);
|
||||
length = this.heregexToken(match);
|
||||
this.line += count(match[0], '\n');
|
||||
return length;
|
||||
}
|
||||
prev = last(this.tokens);
|
||||
if (prev && (_ref = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref) >= 0)) {
|
||||
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = REGEX.exec(this.chunk))) {
|
||||
@@ -213,7 +215,7 @@
|
||||
return regex.length;
|
||||
};
|
||||
Lexer.prototype.heregexToken = function(match) {
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _ref4;
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
|
||||
heregex = match[0], body = match[1], flags = match[2];
|
||||
if (0 > body.indexOf('#{')) {
|
||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
|
||||
@@ -223,11 +225,11 @@
|
||||
this.token('IDENTIFIER', 'RegExp');
|
||||
this.tokens.push(['CALL_START', '(']);
|
||||
tokens = [];
|
||||
_ref = this.interpolateString(body, {
|
||||
_ref2 = this.interpolateString(body, {
|
||||
regex: true
|
||||
});
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
_ref2 = _ref[_i], tag = _ref2[0], value = _ref2[1];
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
_ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
|
||||
if (tag === 'TOKENS') {
|
||||
tokens.push.apply(tokens, value);
|
||||
} else {
|
||||
@@ -240,10 +242,10 @@
|
||||
tokens.push(['+', '+']);
|
||||
}
|
||||
tokens.pop();
|
||||
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') {
|
||||
if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
|
||||
this.tokens.push(['STRING', '""'], ['+', '+']);
|
||||
}
|
||||
(_ref4 = this.tokens).push.apply(_ref4, tokens);
|
||||
(_ref5 = this.tokens).push.apply(_ref5, tokens);
|
||||
if (flags) {
|
||||
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
|
||||
}
|
||||
@@ -340,7 +342,7 @@
|
||||
return this;
|
||||
};
|
||||
Lexer.prototype.literalToken = function() {
|
||||
var match, prev, tag, value, _ref, _ref2, _ref3, _ref4;
|
||||
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
|
||||
if (match = OPERATOR.exec(this.chunk)) {
|
||||
value = match[0];
|
||||
if (CODE.test(value)) {
|
||||
@@ -352,10 +354,10 @@
|
||||
tag = value;
|
||||
prev = last(this.tokens);
|
||||
if (value === '=' && prev) {
|
||||
if (!prev[1].reserved && (_ref = prev[1], __indexOf.call(JS_FORBIDDEN, _ref) >= 0)) {
|
||||
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
|
||||
this.assignmentError();
|
||||
}
|
||||
if ((_ref2 = prev[1]) === '||' || _ref2 === '&&') {
|
||||
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
|
||||
prev[0] = 'COMPOUND_ASSIGN';
|
||||
prev[1] += '=';
|
||||
return value.length;
|
||||
@@ -376,12 +378,12 @@
|
||||
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
|
||||
tag = 'LOGIC';
|
||||
} else if (prev && !prev.spaced) {
|
||||
if (value === '(' && (_ref3 = prev[0], __indexOf.call(CALLABLE, _ref3) >= 0)) {
|
||||
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
}
|
||||
tag = 'CALL_START';
|
||||
} else if (value === '[' && (_ref4 = prev[0], __indexOf.call(INDEXABLE, _ref4) >= 0)) {
|
||||
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
|
||||
tag = 'INDEX_START';
|
||||
switch (prev[0]) {
|
||||
case '?':
|
||||
@@ -396,15 +398,19 @@
|
||||
return value.length;
|
||||
};
|
||||
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
||||
var attempt, herecomment, indent, match, _ref;
|
||||
var attempt, herecomment, indent, match, _ref2;
|
||||
indent = options.indent, herecomment = options.herecomment;
|
||||
if (herecomment && 0 > doc.indexOf('\n')) {
|
||||
return doc;
|
||||
}
|
||||
if (!herecomment) {
|
||||
if (herecomment) {
|
||||
if (HEREDOC_ILLEGAL.test(doc)) {
|
||||
throw new Error("block comment cannot contain \"*/\", starting on line " + (this.line + 1));
|
||||
}
|
||||
if (doc.indexOf('\n') <= 0) {
|
||||
return doc;
|
||||
}
|
||||
} else {
|
||||
while (match = HEREDOC_INDENT.exec(doc)) {
|
||||
attempt = match[1];
|
||||
if (indent === null || (0 < (_ref = attempt.length) && _ref < indent.length)) {
|
||||
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
|
||||
indent = attempt;
|
||||
}
|
||||
}
|
||||
@@ -435,9 +441,11 @@
|
||||
case 'CALL_START':
|
||||
if (stack.length) {
|
||||
stack.pop();
|
||||
} else {
|
||||
} else if (tok[0] === '(') {
|
||||
tok[0] = 'PARAM_START';
|
||||
return this;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,9 +461,9 @@
|
||||
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
|
||||
};
|
||||
Lexer.prototype.balancedString = function(str, end) {
|
||||
var i, letter, prev, stack, _ref;
|
||||
var i, letter, match, prev, stack, _ref2;
|
||||
stack = [end];
|
||||
for (i = 1, _ref = str.length; (1 <= _ref ? i < _ref : i > _ref); (1 <= _ref ? i += 1 : i -= 1)) {
|
||||
for (i = 1, _ref2 = str.length; 1 <= _ref2 ? i < _ref2 : i > _ref2; 1 <= _ref2 ? i++ : i--) {
|
||||
switch (letter = str.charAt(i)) {
|
||||
case '\\':
|
||||
i++;
|
||||
@@ -470,6 +478,8 @@
|
||||
}
|
||||
if (end === '}' && (letter === '"' || letter === "'")) {
|
||||
stack.push(end = letter);
|
||||
} else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) {
|
||||
i += match[0].length - 1;
|
||||
} else if (end === '}' && letter === '{') {
|
||||
stack.push(end = '}');
|
||||
} else if (end === '"' && prev === '#' && letter === '{') {
|
||||
@@ -480,7 +490,7 @@
|
||||
throw new Error("missing " + (stack.pop()) + ", starting on line " + (this.line + 1));
|
||||
};
|
||||
Lexer.prototype.interpolateString = function(str, options) {
|
||||
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref, _ref2, _ref3;
|
||||
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref2, _ref3, _ref4;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -506,7 +516,7 @@
|
||||
rewrite: false
|
||||
});
|
||||
nested.pop();
|
||||
if (((_ref = nested[0]) != null ? _ref[0] : void 0) === 'TERMINATOR') {
|
||||
if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
|
||||
nested.shift();
|
||||
}
|
||||
if (len = nested.length) {
|
||||
@@ -536,12 +546,12 @@
|
||||
this.token('(', '(');
|
||||
}
|
||||
for (i = 0, _len = tokens.length; i < _len; i++) {
|
||||
_ref2 = tokens[i], tag = _ref2[0], value = _ref2[1];
|
||||
_ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
|
||||
if (i) {
|
||||
this.token('+', '+');
|
||||
}
|
||||
if (tag === 'TOKENS') {
|
||||
(_ref3 = this.tokens).push.apply(_ref3, value);
|
||||
(_ref4 = this.tokens).push.apply(_ref4, value);
|
||||
} else {
|
||||
this.token('STRING', this.makeString(value, '"', heredoc));
|
||||
}
|
||||
@@ -587,7 +597,7 @@
|
||||
})();
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
||||
for (op in COFFEE_ALIASES = {
|
||||
COFFEE_ALIAS_MAP = {
|
||||
and: '&&',
|
||||
or: '||',
|
||||
is: '==',
|
||||
@@ -597,14 +607,21 @@
|
||||
no: 'false',
|
||||
on: 'true',
|
||||
off: 'false'
|
||||
}) {
|
||||
COFFEE_KEYWORDS.push(op);
|
||||
}
|
||||
};
|
||||
COFFEE_ALIASES = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (key in COFFEE_ALIAS_MAP) {
|
||||
_results.push(key);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
|
||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf'];
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS);
|
||||
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
|
||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
|
||||
NUMBER = /^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;
|
||||
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
WHITESPACE = /^[^\n\S]+/;
|
||||
@@ -613,13 +630,14 @@
|
||||
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
|
||||
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
|
||||
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
|
||||
REGEX = /^\/(?!\s)[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
|
||||
REGEX = /^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
|
||||
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
|
||||
HEREGEX_OMIT = /\s+(?:#.*)?/g;
|
||||
MULTILINER = /\n/g;
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
|
||||
HEREDOC_ILLEGAL = /\*\//;
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
|
||||
LINE_CONTINUER = /^\s*(?:,|\??\.(?!\.)|::)/;
|
||||
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
|
||||
TRAILING_SPACES = /\s+$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
|
||||
|
||||
730
lib/nodes.js
730
lib/nodes.js
File diff suppressed because it is too large
Load Diff
268
lib/parser.js
268
lib/parser.js
File diff suppressed because one or more lines are too long
110
lib/repl.js
110
lib/repl.js
@@ -1,47 +1,123 @@
|
||||
(function() {
|
||||
var CoffeeScript, error, helpers, readline, repl, run, stdin, stdout;
|
||||
var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, g, getCompletions, inspect, nonContextGlobals, readline, repl, run, sandbox, stdin, stdout, _i, _len;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers');
|
||||
readline = require('readline');
|
||||
inspect = require('util').inspect;
|
||||
Script = require('vm').Script;
|
||||
Module = require('module');
|
||||
REPL_PROMPT = 'coffee> ';
|
||||
REPL_PROMPT_CONTINUATION = '......> ';
|
||||
enableColours = false;
|
||||
if (process.platform !== 'win32') {
|
||||
enableColours = !process.env.NODE_DISABLE_COLORS;
|
||||
}
|
||||
stdin = process.openStdin();
|
||||
stdout = process.stdout;
|
||||
error = function(err) {
|
||||
return stdout.write((err.stack || err.toString()) + '\n\n');
|
||||
};
|
||||
helpers.extend(global, {
|
||||
quit: function() {
|
||||
return process.exit(0);
|
||||
}
|
||||
});
|
||||
backlog = '';
|
||||
sandbox = Script.createContext();
|
||||
nonContextGlobals = ['Buffer', 'console', 'process', 'setInterval', 'clearInterval', 'setTimeout', 'clearTimeout'];
|
||||
for (_i = 0, _len = nonContextGlobals.length; _i < _len; _i++) {
|
||||
g = nonContextGlobals[_i];
|
||||
sandbox[g] = global[g];
|
||||
}
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox;
|
||||
run = function(buffer) {
|
||||
var val;
|
||||
var code, returnValue, _;
|
||||
if (!buffer.toString().trim() && !backlog) {
|
||||
repl.prompt();
|
||||
return;
|
||||
}
|
||||
code = backlog += buffer;
|
||||
if (code[code.length - 1] === '\\') {
|
||||
backlog = "" + backlog.slice(0, -1) + "\n";
|
||||
repl.setPrompt(REPL_PROMPT_CONTINUATION);
|
||||
repl.prompt();
|
||||
return;
|
||||
}
|
||||
repl.setPrompt(REPL_PROMPT);
|
||||
backlog = '';
|
||||
try {
|
||||
val = CoffeeScript.eval(buffer.toString(), {
|
||||
bare: true,
|
||||
globals: true,
|
||||
filename: 'repl'
|
||||
_ = sandbox._;
|
||||
returnValue = CoffeeScript.eval("_=(" + code + "\n)", {
|
||||
sandbox: sandbox,
|
||||
filename: 'repl',
|
||||
modulename: 'repl'
|
||||
});
|
||||
if (val !== void 0) {
|
||||
process.stdout.write(val + '\n');
|
||||
if (returnValue === void 0) {
|
||||
sandbox._ = _;
|
||||
} else {
|
||||
process.stdout.write(inspect(returnValue, false, 2, enableColours) + '\n');
|
||||
}
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
return repl.prompt();
|
||||
};
|
||||
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
|
||||
SIMPLEVAR = /\s*(\w*)$/i;
|
||||
autocomplete = function(text) {
|
||||
return completeAttribute(text) || completeVariable(text) || [[], text];
|
||||
};
|
||||
completeAttribute = function(text) {
|
||||
var all, completions, match, obj, prefix, val;
|
||||
if (match = text.match(ACCESSOR)) {
|
||||
all = match[0], obj = match[1], prefix = match[2];
|
||||
try {
|
||||
val = Script.runInContext(obj, sandbox);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
completions = getCompletions(prefix, Object.getOwnPropertyNames(val));
|
||||
return [completions, prefix];
|
||||
}
|
||||
};
|
||||
completeVariable = function(text) {
|
||||
var completions, free, possibilities, vars, _ref;
|
||||
if (free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0) {
|
||||
vars = Script.runInContext('Object.getOwnPropertyNames(this)', sandbox);
|
||||
possibilities = vars.concat(CoffeeScript.RESERVED);
|
||||
completions = getCompletions(free, possibilities);
|
||||
return [completions, free];
|
||||
}
|
||||
};
|
||||
getCompletions = function(prefix, candidates) {
|
||||
var el, _j, _len2, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len2 = candidates.length; _j < _len2; _j++) {
|
||||
el = candidates[_j];
|
||||
if (el.indexOf(prefix) === 0) {
|
||||
_results.push(el);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
process.on('uncaughtException', error);
|
||||
if (readline.createInterface.length < 3) {
|
||||
repl = readline.createInterface(stdin);
|
||||
repl = readline.createInterface(stdin, autocomplete);
|
||||
stdin.on('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
} else {
|
||||
repl = readline.createInterface(stdin, stdout);
|
||||
repl = readline.createInterface(stdin, stdout, autocomplete);
|
||||
}
|
||||
repl.setPrompt('coffee> ');
|
||||
repl.on('attemptClose', function() {
|
||||
if (backlog) {
|
||||
backlog = '';
|
||||
process.stdout.write('\n');
|
||||
repl.setPrompt(REPL_PROMPT);
|
||||
return repl.prompt();
|
||||
} else {
|
||||
return repl.close();
|
||||
}
|
||||
});
|
||||
repl.on('close', function() {
|
||||
process.stdout.write('\n');
|
||||
return stdin.destroy();
|
||||
});
|
||||
repl.on('line', run);
|
||||
repl.setPrompt(REPL_PROMPT);
|
||||
repl.prompt();
|
||||
}).call(this);
|
||||
|
||||
@@ -121,7 +121,10 @@
|
||||
return ((tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':')) || (tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT'));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
|
||||
var tok;
|
||||
tok = ['}', '}', token[2]];
|
||||
tok.generated = true;
|
||||
return this.tokens.splice(i, 0, tok);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var ago, idx, tag, tok, value, _ref, _ref2;
|
||||
@@ -159,7 +162,7 @@
|
||||
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var callObject, current, next, prev, seenSingle, tag, _ref, _ref2, _ref3;
|
||||
var callObject, current, next, prev, seenControl, seenSingle, tag, _ref, _ref2, _ref3;
|
||||
tag = token[0];
|
||||
if (tag === 'CLASS' || tag === 'IF') {
|
||||
noCall = true;
|
||||
@@ -167,29 +170,36 @@
|
||||
_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;
|
||||
seenControl = false;
|
||||
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
|
||||
noCall = false;
|
||||
}
|
||||
if (prev && !prev.spaced && tag === '?') {
|
||||
token.call = true;
|
||||
}
|
||||
if (token.fromThen) {
|
||||
return 1;
|
||||
}
|
||||
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref3 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref3) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
|
||||
return 1;
|
||||
}
|
||||
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
this.detectEnd(i + 1, function(token, i) {
|
||||
var post, _ref;
|
||||
var post, _ref4;
|
||||
tag = token[0];
|
||||
if (!seenSingle && token.fromThen) {
|
||||
return true;
|
||||
}
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === '->' || tag === '=>') {
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>') {
|
||||
seenSingle = true;
|
||||
}
|
||||
if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY') {
|
||||
seenControl = true;
|
||||
}
|
||||
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
|
||||
return true;
|
||||
}
|
||||
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
|
||||
return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0 || (tag === 'INDENT' && !seenControl)) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref4 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref4) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
|
||||
}, action);
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
@@ -222,8 +232,8 @@
|
||||
indent.generated = outdent.generated = true;
|
||||
tokens.splice(i + 1, 0, indent);
|
||||
condition = function(token, i) {
|
||||
var _ref;
|
||||
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
|
||||
var _ref3;
|
||||
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
||||
@@ -346,7 +356,7 @@
|
||||
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', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT'];
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
|
||||
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
|
||||
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
|
||||
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
|
||||
|
||||
30
lib/scope.js
30
lib/scope.js
@@ -46,12 +46,12 @@
|
||||
return this.add(name, 'param');
|
||||
};
|
||||
Scope.prototype.check = function(name, immediate) {
|
||||
var found, _ref;
|
||||
var found, _ref2;
|
||||
found = !!this.type(name);
|
||||
if (found || immediate) {
|
||||
return found;
|
||||
}
|
||||
return !!((_ref = this.parent) != null ? _ref.check(name) : void 0);
|
||||
return !!((_ref2 = this.parent) != null ? _ref2.check(name) : void 0);
|
||||
};
|
||||
Scope.prototype.temporary = function(name, index) {
|
||||
if (name.length > 1) {
|
||||
@@ -61,10 +61,10 @@
|
||||
}
|
||||
};
|
||||
Scope.prototype.type = function(name) {
|
||||
var v, _i, _len, _ref;
|
||||
_ref = this.variables;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
v = _ref[_i];
|
||||
var v, _i, _len, _ref2;
|
||||
_ref2 = this.variables;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
v = _ref2[_i];
|
||||
if (v.name === name) {
|
||||
return v.type;
|
||||
}
|
||||
@@ -74,7 +74,7 @@
|
||||
Scope.prototype.freeVariable = function(type) {
|
||||
var index, temp;
|
||||
index = 0;
|
||||
while (this.check((temp = this.temporary(type, index)), true)) {
|
||||
while (this.check((temp = this.temporary(type, index)))) {
|
||||
index++;
|
||||
}
|
||||
this.add(temp, 'var', true);
|
||||
@@ -91,12 +91,12 @@
|
||||
return !!this.declaredVariables().length;
|
||||
};
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
var realVars, tempVars, v, _i, _len, _ref;
|
||||
var realVars, tempVars, v, _i, _len, _ref2;
|
||||
realVars = [];
|
||||
tempVars = [];
|
||||
_ref = this.variables;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
v = _ref[_i];
|
||||
_ref2 = this.variables;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
v = _ref2[_i];
|
||||
if (v.type === 'var') {
|
||||
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
|
||||
}
|
||||
@@ -104,11 +104,11 @@
|
||||
return realVars.sort().concat(tempVars.sort());
|
||||
};
|
||||
Scope.prototype.assignedVariables = function() {
|
||||
var v, _i, _len, _ref, _results;
|
||||
_ref = this.variables;
|
||||
var v, _i, _len, _ref2, _results;
|
||||
_ref2 = this.variables;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
v = _ref[_i];
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
v = _ref2[_i];
|
||||
if (v.type.assigned) {
|
||||
_results.push("" + v.name + " = " + v.type.value);
|
||||
}
|
||||
|
||||
45
package.json
45
package.json
@@ -1,22 +1,27 @@
|
||||
{
|
||||
"name": "coffee-script",
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.0.1",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.2.5"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib"
|
||||
},
|
||||
"main" : "./lib/coffee-script",
|
||||
"bin": {
|
||||
"coffee": "./bin/coffee",
|
||||
"cake": "./bin/cake"
|
||||
}
|
||||
"name": "coffee-script",
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.1.2",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.2.5"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib"
|
||||
},
|
||||
"main" : "./lib/coffee-script",
|
||||
"bin": {
|
||||
"coffee": "./bin/coffee",
|
||||
"cake": "./bin/cake"
|
||||
},
|
||||
"homepage": "http://coffeescript.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jashkenas/coffee-script.git"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,24 +16,35 @@ CoffeeScript.run = (code, options = {}) ->
|
||||
return unless window?
|
||||
|
||||
# Load a remote script from the current domain via XHR.
|
||||
CoffeeScript.load = (url, options) ->
|
||||
CoffeeScript.load = (url, callback) ->
|
||||
xhr = new (window.ActiveXObject or XMLHttpRequest)('Microsoft.XMLHTTP')
|
||||
xhr.open 'GET', url, true
|
||||
xhr.overrideMimeType 'text/plain' if 'overrideMimeType' of xhr
|
||||
xhr.onreadystatechange = ->
|
||||
CoffeeScript.run xhr.responseText, options if xhr.readyState is 4
|
||||
if xhr.readyState is 4
|
||||
if xhr.status in [0, 200]
|
||||
CoffeeScript.run xhr.responseText
|
||||
else
|
||||
throw new Error "Could not load #{url}"
|
||||
callback() if callback
|
||||
xhr.send null
|
||||
|
||||
# Activate CoffeeScript in the browser by having it compile and evaluate
|
||||
# all script tags with a content-type of `text/coffeescript`.
|
||||
# This happens on page load.
|
||||
runScripts = ->
|
||||
for script in document.getElementsByTagName 'script'
|
||||
if script.type is 'text/coffeescript'
|
||||
scripts = document.getElementsByTagName 'script'
|
||||
coffees = (s for s in scripts when s.type is 'text/coffeescript')
|
||||
index = 0
|
||||
length = coffees.length
|
||||
do execute = ->
|
||||
script = coffees[index++]
|
||||
if script?.type is 'text/coffeescript'
|
||||
if script.src
|
||||
CoffeeScript.load script.src
|
||||
CoffeeScript.load script.src, execute
|
||||
else
|
||||
CoffeeScript.run script.innerHTML
|
||||
execute()
|
||||
null
|
||||
|
||||
# Listen for window load, both in browsers and in IE.
|
||||
|
||||
@@ -63,7 +63,7 @@ printTasks = ->
|
||||
console.log "cake #{name}#{spaces} #{desc}"
|
||||
console.log oparse.help() if switches.length
|
||||
|
||||
# Print an error and exit when attempting to all an undefined task.
|
||||
# Print an error and exit when attempting to call an undefined task.
|
||||
missingTask = (task) ->
|
||||
console.log "No such task: \"#{task}\""
|
||||
process.exit 1
|
||||
|
||||
@@ -14,13 +14,13 @@ path = require 'path'
|
||||
# TODO: Remove registerExtension when fully deprecated.
|
||||
if require.extensions
|
||||
require.extensions['.coffee'] = (module, filename) ->
|
||||
content = compile fs.readFileSync filename, 'utf8'
|
||||
content = compile fs.readFileSync(filename, 'utf8'), {filename}
|
||||
module._compile content, filename
|
||||
else if require.registerExtension
|
||||
require.registerExtension '.coffee', (content) -> compile content
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '1.0.1'
|
||||
exports.VERSION = '1.1.2'
|
||||
|
||||
# Words that cannot be used as identifiers in CoffeeScript code
|
||||
exports.RESERVED = RESERVED
|
||||
@@ -53,26 +53,58 @@ exports.nodes = (source, options) ->
|
||||
# Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
# setting `__filename`, `__dirname`, and relative `require()`.
|
||||
exports.run = (code, options) ->
|
||||
# We want the root module.
|
||||
root = module
|
||||
while root.parent
|
||||
root = root.parent
|
||||
mainModule = require.main
|
||||
|
||||
# Set the filename.
|
||||
root.filename = if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
mainModule.filename = process.argv[1] =
|
||||
if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
|
||||
# Clear the module cache.
|
||||
root.moduleCache = {} if root.moduleCache
|
||||
mainModule.moduleCache and= {}
|
||||
|
||||
# Assign paths for node_modules loading
|
||||
if process.binding('natives').module
|
||||
{Module} = require 'module'
|
||||
mainModule.paths = Module._nodeModulePaths path.dirname options.filename
|
||||
|
||||
# Compile.
|
||||
if path.extname(root.filename) isnt '.coffee' or require.extensions
|
||||
root._compile compile(code, options), root.filename
|
||||
if path.extname(mainModule.filename) isnt '.coffee' or require.extensions
|
||||
mainModule._compile compile(code, options), mainModule.filename
|
||||
else
|
||||
root._compile code, root.filename
|
||||
mainModule._compile code, mainModule.filename
|
||||
|
||||
# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
# The CoffeeScript REPL uses this to run the input.
|
||||
exports.eval = (code, options) ->
|
||||
__filename = module.filename = options.filename
|
||||
__dirname = path.dirname __filename
|
||||
eval compile code, options
|
||||
exports.eval = (code, options = {}) ->
|
||||
return unless code = code.trim()
|
||||
if {Script} = require 'vm'
|
||||
sandbox = Script.createContext()
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
|
||||
if options.sandbox?
|
||||
if options.sandbox instanceof sandbox.constructor
|
||||
sandbox = options.sandbox
|
||||
else
|
||||
sandbox[k] = v for own k, v of options.sandbox
|
||||
sandbox.__filename = options.filename || 'eval'
|
||||
sandbox.__dirname = path.dirname sandbox.__filename
|
||||
# define module/require only if they chose not to specify their own
|
||||
unless sandbox.module or sandbox.require
|
||||
Module = require 'module'
|
||||
sandbox.module = _module = new Module(options.modulename || 'eval')
|
||||
sandbox.require = _require = (path) -> Module._load path, _module
|
||||
_module.filename = sandbox.__filename
|
||||
_require[r] = require[r] for r in Object.getOwnPropertyNames require
|
||||
# use the same hack node currently uses for their own REPL
|
||||
_require.paths = _module.paths = Module._nodeModulePaths process.cwd()
|
||||
_require.resolve = (request) -> Module._resolveFilename request, _module
|
||||
o = {}
|
||||
o[k] = v for own k, v of options
|
||||
o.bare = on # ensure return value
|
||||
js = compile code, o
|
||||
if Script
|
||||
Script.runInContext js, sandbox
|
||||
else
|
||||
eval js
|
||||
|
||||
# Instantiate a Lexer for our use here.
|
||||
lexer = new Lexer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The `coffee` utility. Handles command-line compilation of CoffeeScript
|
||||
# into various forms: saved into `.js` files or printed to stdout, piped to
|
||||
# [JSLint](http://javascriptlint.com/) or recompiled every time the source is
|
||||
# [JavaScript Lint](http://javascriptlint.com/) or recompiled every time the source is
|
||||
# saved, printed as a token stream or as the syntax tree, or launch an
|
||||
# interactive REPL.
|
||||
|
||||
@@ -29,10 +29,10 @@ SWITCHES = [
|
||||
['-c', '--compile', 'compile to JavaScript and save as .js files']
|
||||
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
|
||||
['-o', '--output [DIR]', 'set the directory for compiled JavaScript']
|
||||
['-j', '--join', 'concatenate the scripts before compiling']
|
||||
['-j', '--join [FILE]', 'concatenate the scripts before compiling']
|
||||
['-w', '--watch', 'watch scripts for changes, and recompile']
|
||||
['-p', '--print', 'print the compiled JavaScript to stdout']
|
||||
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
|
||||
['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint']
|
||||
['-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']
|
||||
@@ -66,31 +66,52 @@ exports.run = ->
|
||||
if opts.run
|
||||
opts.literals = sources.splice(1).concat opts.literals
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
|
||||
process.argv[0] = 'coffee'
|
||||
process.execPath = require.main.filename
|
||||
compileScripts()
|
||||
|
||||
# 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.
|
||||
compileScripts = ->
|
||||
unprocessed = []
|
||||
for source in sources
|
||||
unprocessed[sources.indexOf(source)]=1
|
||||
for source in sources
|
||||
base = path.join(source)
|
||||
compile = (source, topLevel) ->
|
||||
compile = (source, sourceIndex, topLevel) ->
|
||||
remaining_files = ->
|
||||
total = 0
|
||||
total += x for x in unprocessed
|
||||
total
|
||||
path.exists source, (exists) ->
|
||||
if topLevel and not exists and source[-7..] isnt '.coffee'
|
||||
return compile "#{source}.coffee", sourceIndex, topLevel
|
||||
|
||||
throw new Error "File not found: #{source}" if topLevel and not exists
|
||||
fs.stat source, (err, stats) ->
|
||||
throw err if err
|
||||
if stats.isDirectory()
|
||||
fs.readdir source, (err, files) ->
|
||||
throw err if err
|
||||
unprocessed[sourceIndex] += files.length
|
||||
for file in files
|
||||
compile path.join(source, file)
|
||||
compile path.join(source, file), sourceIndex
|
||||
unprocessed[sourceIndex] -= 1
|
||||
else if topLevel or path.extname(source) is '.coffee'
|
||||
fs.readFile source, (err, code) ->
|
||||
throw err if err
|
||||
unprocessed[sourceIndex] -= 1
|
||||
if opts.join
|
||||
contents[sources.indexOf source] = code.toString()
|
||||
compileJoin() if helpers.compact(contents).length is sources.length
|
||||
contents[sourceIndex] = helpers.compact([contents[sourceIndex], code.toString()]).join('\n')
|
||||
if helpers.compact(contents).length > 0 and remaining_files() == 0
|
||||
compileJoin()
|
||||
else
|
||||
compileScript(source, code.toString(), base)
|
||||
watch source, base if opts.watch and not opts.join
|
||||
compile source, true
|
||||
else
|
||||
unprocessed[sourceIndex] -= 1
|
||||
compile source, sources.indexOf(source), true
|
||||
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
# requested options. If evaluating the script directly sets `__filename`,
|
||||
@@ -131,7 +152,7 @@ compileStdio = ->
|
||||
# them together.
|
||||
compileJoin = ->
|
||||
code = contents.join '\n'
|
||||
compileScript "concatenation", code, "concatenation"
|
||||
compileScript opts.join, code, opts.join
|
||||
|
||||
# Load files that are to-be-required before compilation occurs.
|
||||
loadRequires = ->
|
||||
@@ -165,7 +186,7 @@ writeJs = (source, js, base) ->
|
||||
if err
|
||||
printLine err.message
|
||||
else if opts.compile and opts.watch
|
||||
console.log "#{(new Date).toTimeString()} - compiled #{source}"
|
||||
console.log "#{(new Date).toLocaleTimeString()} - compiled #{source}"
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p #{dir}", compile
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ grammar =
|
||||
|
||||
# All the different types of expressions in our language. The basic unit of
|
||||
# CoffeeScript is the **Expression** -- everything that can be an expression
|
||||
# is one. Block serve as the building blocks of many other rules, making
|
||||
# is one. Blocks serve as the building blocks of many other rules, making
|
||||
# them somewhat circular.
|
||||
Expression: [
|
||||
o 'Value'
|
||||
@@ -120,7 +120,7 @@ grammar =
|
||||
o 'STRING', -> new Literal $1
|
||||
]
|
||||
|
||||
# All of our immediate values. These can (in general), be passed straight
|
||||
# All of our immediate values. Generally these can be passed straight
|
||||
# through and printed to JavaScript.
|
||||
Literal: [
|
||||
o 'AlphaNumeric'
|
||||
@@ -201,6 +201,7 @@ grammar =
|
||||
o 'ParamVar = Expression', -> new Param $1, $3
|
||||
]
|
||||
|
||||
# Function Parameters
|
||||
ParamVar: [
|
||||
o 'Identifier'
|
||||
o 'ThisProperty'
|
||||
@@ -246,16 +247,20 @@ grammar =
|
||||
o ':: Identifier', -> new Access $2, 'proto'
|
||||
o '::', -> new Access new Literal 'prototype'
|
||||
o 'Index'
|
||||
o 'Slice', -> new Slice $1
|
||||
]
|
||||
|
||||
# Indexing into an object or array using bracket notation.
|
||||
Index: [
|
||||
o 'INDEX_START Expression INDEX_END', -> new Index $2
|
||||
o 'INDEX_START IndexValue INDEX_END', -> $2
|
||||
o 'INDEX_SOAK Index', -> extend $2, soak : yes
|
||||
o 'INDEX_PROTO Index', -> extend $2, proto: yes
|
||||
]
|
||||
|
||||
IndexValue: [
|
||||
o 'Expression', -> new Index $1
|
||||
o 'Slice', -> new Slice $1
|
||||
]
|
||||
|
||||
# In CoffeeScript, an object literal is simply a list of assignments.
|
||||
Object: [
|
||||
o '{ AssignList OptComma }', -> new Obj $2, $1.generated
|
||||
@@ -334,9 +339,9 @@ grammar =
|
||||
|
||||
# Array slice literals.
|
||||
Slice: [
|
||||
o 'INDEX_START Expression RangeDots Expression INDEX_END', -> new Range $2, $4, $3
|
||||
o 'INDEX_START Expression RangeDots INDEX_END', -> new Range $2, null, $3
|
||||
o 'INDEX_START RangeDots Expression INDEX_END', -> new Range null, $3, $2
|
||||
o 'Expression RangeDots Expression', -> new Range $1, $3, $2
|
||||
o 'Expression RangeDots', -> new Range $1, null, $2
|
||||
o 'RangeDots Expression', -> new Range null, $2, $1
|
||||
]
|
||||
|
||||
# The **ArgList** is both the list of objects passed into a function call,
|
||||
@@ -350,7 +355,7 @@ grammar =
|
||||
o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
|
||||
]
|
||||
|
||||
# Valid arguments are Block or Splats.
|
||||
# Valid arguments are Blocks or Splats.
|
||||
Arg: [
|
||||
o 'Expression'
|
||||
o 'Splat'
|
||||
@@ -569,7 +574,7 @@ operators = [
|
||||
# Wrapping Up
|
||||
# -----------
|
||||
|
||||
# Finally, now what we have our **grammar** and our **operators**, we can create
|
||||
# Finally, now that we have our **grammar** and our **operators**, we can create
|
||||
# our **Jison.Parser**. We do this by processing all of our rules, recording all
|
||||
# terminals (every symbol which does not appear as the name of a rule above)
|
||||
# as "tokens".
|
||||
|
||||
@@ -80,11 +80,11 @@ exports.Lexer = class Lexer
|
||||
@token 'OWN', id
|
||||
return id.length
|
||||
forcedIdentifier = colon or
|
||||
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
|
||||
(prev = last @tokens) and (prev[0] in ['.', '?.', '::'] or
|
||||
not prev.spaced and prev[0] is '@')
|
||||
tag = 'IDENTIFIER'
|
||||
|
||||
if id in JS_KEYWORDS or
|
||||
not forcedIdentifier and id in COFFEE_KEYWORDS
|
||||
if not forcedIdentifier and (id in JS_KEYWORDS or id in COFFEE_KEYWORDS)
|
||||
tag = id.toUpperCase()
|
||||
if tag is 'WHEN' and @tag() in LINE_BREAK
|
||||
tag = 'LEADING_WHEN'
|
||||
@@ -113,7 +113,7 @@ exports.Lexer = class Lexer
|
||||
@identifierError id
|
||||
|
||||
unless forcedIdentifier
|
||||
id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id
|
||||
id = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
|
||||
tag = switch id
|
||||
when '!' then 'UNARY'
|
||||
when '==', '!=' then 'COMPARE'
|
||||
@@ -170,11 +170,11 @@ exports.Lexer = class Lexer
|
||||
commentToken: ->
|
||||
return 0 unless match = @chunk.match COMMENT
|
||||
[comment, here] = match
|
||||
@line += count comment, '\n'
|
||||
if here
|
||||
@token 'HERECOMMENT', @sanitizeHeredoc here,
|
||||
herecomment: true, indent: Array(@indent + 1).join(' ')
|
||||
@token 'TERMINATOR', '\n'
|
||||
@line += count comment, '\n'
|
||||
comment.length
|
||||
|
||||
# Matches JavaScript interpolated directly into the source via backticks.
|
||||
@@ -188,7 +188,11 @@ exports.Lexer = class Lexer
|
||||
# JavaScript and Ruby.
|
||||
regexToken: ->
|
||||
return 0 if @chunk.charAt(0) isnt '/'
|
||||
return @heregexToken match if match = HEREGEX.exec @chunk
|
||||
if match = HEREGEX.exec @chunk
|
||||
length = @heregexToken match
|
||||
@line += count match[0], '\n'
|
||||
return length
|
||||
|
||||
prev = last @tokens
|
||||
return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX))
|
||||
return 0 unless match = REGEX.exec @chunk
|
||||
@@ -343,8 +347,11 @@ exports.Lexer = class Lexer
|
||||
# erasing all external indentation on the left-hand side.
|
||||
sanitizeHeredoc: (doc, options) ->
|
||||
{indent, herecomment} = options
|
||||
return doc if herecomment and 0 > doc.indexOf '\n'
|
||||
unless herecomment
|
||||
if herecomment
|
||||
if HEREDOC_ILLEGAL.test doc
|
||||
throw new Error "block comment cannot contain \"*/\", starting on line #{@line + 1}"
|
||||
return doc if doc.indexOf('\n') <= 0
|
||||
else
|
||||
while match = HEREDOC_INDENT.exec doc
|
||||
attempt = match[1]
|
||||
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
||||
@@ -367,9 +374,10 @@ exports.Lexer = class Lexer
|
||||
stack.push tok
|
||||
when '(', 'CALL_START'
|
||||
if stack.length then stack.pop()
|
||||
else
|
||||
else if tok[0] is '('
|
||||
tok[0] = 'PARAM_START'
|
||||
return this
|
||||
else return this
|
||||
this
|
||||
|
||||
# Close up all remaining open blocks at the end of the file.
|
||||
@@ -405,6 +413,8 @@ exports.Lexer = class Lexer
|
||||
continue
|
||||
if end is '}' and letter in ['"', "'"]
|
||||
stack.push end = letter
|
||||
else if end is '}' and letter is '/' and match = (HEREGEX.exec(str.slice i) or REGEX.exec(str.slice i))
|
||||
i += match[0].length - 1
|
||||
else if end is '}' and letter is '{'
|
||||
stack.push end = '}'
|
||||
else if end is '"' and prev is '#' and letter is '{'
|
||||
@@ -508,7 +518,8 @@ JS_KEYWORDS = [
|
||||
|
||||
# CoffeeScript-only keywords.
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']
|
||||
COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
||||
|
||||
COFFEE_ALIAS_MAP =
|
||||
and : '&&'
|
||||
or : '||'
|
||||
is : '=='
|
||||
@@ -519,6 +530,9 @@ COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
||||
on : 'true'
|
||||
off : 'false'
|
||||
|
||||
COFFEE_ALIASES = (key for key of COFFEE_ALIAS_MAP)
|
||||
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES
|
||||
|
||||
# The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
# used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
# to avoid having a JavaScript error at runtime.
|
||||
@@ -542,7 +556,7 @@ IDENTIFIER = /// ^
|
||||
|
||||
NUMBER = ///
|
||||
^ 0x[\da-f]+ | # hex
|
||||
^ (?: \d+(\.\d+)? | \.\d+ ) (?:e[+-]?\d+)? # decimal
|
||||
^ \d*\.?\d+ (?:e[+-]?\d+)? # decimal
|
||||
///i
|
||||
|
||||
HEREDOC = /// ^ ("""|''') ([\s\S]*?) (?:\n[^\n\S]*)? \1 ///
|
||||
@@ -571,7 +585,7 @@ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/
|
||||
|
||||
# Regex-matching-regexes.
|
||||
REGEX = /// ^
|
||||
/ (?! \s ) # disallow leading whitespace
|
||||
/ (?! [\s=] ) # disallow leading whitespace or equals signs
|
||||
[^ [ / \n \\ ]* # every other thing
|
||||
(?:
|
||||
(?: \\[\s\S] # anything escaped
|
||||
@@ -593,9 +607,11 @@ MULTILINER = /\n/g
|
||||
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g
|
||||
|
||||
HEREDOC_ILLEGAL = /\*\//
|
||||
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
||||
|
||||
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?!\.) | :: ) ///
|
||||
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
|
||||
|
||||
TRAILING_SPACES = /\s+$/
|
||||
|
||||
@@ -643,7 +659,7 @@ NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', '++', '--', ']']
|
||||
# force a division parse:
|
||||
NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING'
|
||||
|
||||
# Tokens which could legitimately be invoked or indexed. A opening
|
||||
# Tokens which could legitimately be invoked or indexed. An opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
# of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']
|
||||
|
||||
395
src/nodes.coffee
395
src/nodes.coffee
@@ -48,7 +48,7 @@ exports.Base = class Base
|
||||
# Statements converted into expressions via closure-wrapping share a scope
|
||||
# object with their parent closure, to preserve the expected lexical scope.
|
||||
compileClosure: (o) ->
|
||||
if @jumps()
|
||||
if @jumps() or this instanceof Throw
|
||||
throw SyntaxError 'cannot use a pure statement in an expression.'
|
||||
o.sharedScope = yes
|
||||
Closure.wrap(this).compileNode o
|
||||
@@ -188,7 +188,7 @@ exports.Block = class Block extends Base
|
||||
for exp in @expressions
|
||||
return exp if exp.jumps o
|
||||
|
||||
# An Block node does not return its entire body, rather it
|
||||
# A Block node does not return its entire body, rather it
|
||||
# ensures that the final expression is returned.
|
||||
makeReturn: ->
|
||||
len = @expressions.length
|
||||
@@ -200,7 +200,7 @@ exports.Block = class Block extends Base
|
||||
break
|
||||
this
|
||||
|
||||
# An **Block** is the only node that can serve as the root.
|
||||
# A **Block** is the only node that can serve as the root.
|
||||
compile: (o = {}, level) ->
|
||||
if o.scope then super o, level else @compileRoot o
|
||||
|
||||
@@ -214,7 +214,12 @@ exports.Block = class Block extends Base
|
||||
for node in @expressions
|
||||
node = node.unwrapAll()
|
||||
node = (node.unfoldSoak(o) or node)
|
||||
if top
|
||||
if node instanceof Block
|
||||
# This is a nested block. We don't do anything special here like enclose
|
||||
# it in a new scope; we just compile the statements in this block along with
|
||||
# our own
|
||||
codes.push node.compileNode o
|
||||
else if top
|
||||
node.front = true
|
||||
code = node.compile o
|
||||
codes.push if node.isStatement o then code else @tab + code + ';'
|
||||
@@ -233,7 +238,6 @@ exports.Block = class Block extends Base
|
||||
o.scope = new Scope null, this, null
|
||||
o.level = LEVEL_TOP
|
||||
code = @compileWithDeclarations o
|
||||
code = code.replace TRAILING_WHITESPACE, ''
|
||||
if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
|
||||
|
||||
# Compile the expressions body for the contents of a function, with
|
||||
@@ -246,18 +250,22 @@ exports.Block = class Block extends Base
|
||||
o = merge(o, level: LEVEL_TOP)
|
||||
if i
|
||||
rest = @expressions.splice i, @expressions.length
|
||||
code = @compileNode o
|
||||
code = @compileNode(o)
|
||||
@expressions = rest
|
||||
post = @compileNode o
|
||||
{scope} = o
|
||||
if scope.expressions is this
|
||||
if not o.globals and o.scope.hasDeclarations()
|
||||
declars = o.scope.hasDeclarations()
|
||||
assigns = scope.hasAssignments
|
||||
if (declars or assigns) and i
|
||||
code += '\n'
|
||||
if declars
|
||||
code += "#{@tab}var #{ scope.declaredVariables().join(', ') };\n"
|
||||
if scope.hasAssignments
|
||||
if assigns
|
||||
code += "#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"
|
||||
code + post
|
||||
|
||||
# Wrap up the given nodes as an **Block**, unless it already happens
|
||||
# Wrap up the given nodes as a **Block**, unless it already happens
|
||||
# to be one.
|
||||
@wrap: (nodes) ->
|
||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block
|
||||
@@ -380,7 +388,7 @@ exports.Value = class Value extends Base
|
||||
name = last @properties
|
||||
if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
|
||||
return [this, this] # `a` `a.b`
|
||||
base = new Value @base, @properties.slice 0, -1
|
||||
base = new Value @base, @properties[...-1]
|
||||
if base.isComplex() # `a().b`
|
||||
bref = new Literal o.scope.freeVariable 'base'
|
||||
base = new Value new Parens new Assign bref, base
|
||||
@@ -399,25 +407,28 @@ exports.Value = class Value extends Base
|
||||
@base.front = @front
|
||||
props = @properties
|
||||
code = @base.compile o, if props.length then LEVEL_ACCESS else null
|
||||
code = "(#{code})" if props[0] instanceof Access and @isSimpleNumber()
|
||||
code = "#{code}." if (@base instanceof Parens or props.length) and SIMPLENUM.test code
|
||||
code += prop.compile o for prop in props
|
||||
code
|
||||
|
||||
# Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
|
||||
unfoldSoak: (o) ->
|
||||
if ifn = @base.unfoldSoak o
|
||||
Array::push.apply ifn.body.properties, @properties
|
||||
return ifn
|
||||
for prop, i in @properties when prop.soak
|
||||
prop.soak = off
|
||||
fst = new Value @base, @properties.slice 0, i
|
||||
snd = new Value @base, @properties.slice i
|
||||
if fst.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, fst
|
||||
snd.base = ref
|
||||
return new If new Existence(fst), snd, soak: on
|
||||
null
|
||||
return @unfoldedSoak if @unfoldedSoak?
|
||||
result = do =>
|
||||
if ifn = @base.unfoldSoak o
|
||||
Array::push.apply ifn.body.properties, @properties
|
||||
return ifn
|
||||
for prop, i in @properties when prop.soak
|
||||
prop.soak = off
|
||||
fst = new Value @base, @properties[...i]
|
||||
snd = new Value @base, @properties[i..]
|
||||
if fst.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, fst
|
||||
snd.base = ref
|
||||
return new If new Existence(fst), snd, soak: on
|
||||
null
|
||||
@unfoldedSoak = result or no
|
||||
|
||||
#### Comment
|
||||
|
||||
@@ -449,7 +460,7 @@ exports.Call = class Call extends Base
|
||||
# Tag this invocation as creating a new instance.
|
||||
newInstance: ->
|
||||
base = @variable.base or @variable
|
||||
if base instanceof Call
|
||||
if base instanceof Call and not base.isNew
|
||||
base.newInstance()
|
||||
else
|
||||
@isNew = true
|
||||
@@ -461,9 +472,9 @@ exports.Call = class Call extends Base
|
||||
{method} = o.scope
|
||||
throw SyntaxError 'cannot call super outside of a function.' unless method
|
||||
{name} = method
|
||||
throw SyntaxError 'cannot call super on an anonymous function.' unless name
|
||||
throw SyntaxError 'cannot call super on an anonymous function.' unless name?
|
||||
if method.klass
|
||||
"#{method.klass}.__super__.#{name}"
|
||||
(new Value (new Literal method.klass), [new Access(new Literal "__super__"), new Access new Literal name]).compile o
|
||||
else
|
||||
"#{name}.__super__.constructor"
|
||||
|
||||
@@ -478,7 +489,7 @@ exports.Call = class Call extends Base
|
||||
rite = new Value left
|
||||
rite = new Call rite, @args
|
||||
rite.isNew = @isNew
|
||||
left = new Literal "typeof #{ left.compile o } == \"function\""
|
||||
left = new Literal "typeof #{ left.compile o } === \"function\""
|
||||
return new If left, new Value(rite), soak: yes
|
||||
call = this
|
||||
list = []
|
||||
@@ -499,12 +510,31 @@ exports.Call = class Call extends Base
|
||||
ifn = unfoldSoak o, call, 'variable'
|
||||
ifn
|
||||
|
||||
# Walk through the objects in the arguments, moving over simple values.
|
||||
# This allows syntax like `call a: b, c` into `call({a: b}, c);`
|
||||
filterImplicitObjects: (list) ->
|
||||
nodes = []
|
||||
for node in list
|
||||
unless node.isObject?() and node.base.generated
|
||||
nodes.push node
|
||||
continue
|
||||
obj = null
|
||||
for prop in node.base.properties
|
||||
if prop instanceof Assign or prop instanceof Comment
|
||||
nodes.push obj = new Obj properties = [], true if not obj
|
||||
properties.push prop
|
||||
else
|
||||
nodes.push prop
|
||||
obj = null
|
||||
nodes
|
||||
|
||||
# Compile a vanilla function call.
|
||||
compileNode: (o) ->
|
||||
@variable?.front = @front
|
||||
if code = Splat.compileSplattedArray o, @args, true
|
||||
return @compileSplat o, code
|
||||
args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
|
||||
args = @filterImplicitObjects @args
|
||||
args = (arg.compile o, LEVEL_LIST for arg in args).join ', '
|
||||
if @isSuper
|
||||
@superReference(o) + ".call(this#{ args and ', ' + args })"
|
||||
else
|
||||
@@ -524,11 +554,11 @@ exports.Call = class Call extends Base
|
||||
if @isNew
|
||||
idt = @tab + TAB
|
||||
return """
|
||||
(function(func, args, ctor) {
|
||||
#{idt}ctor.prototype = func.prototype;
|
||||
#{idt}var child = new ctor, result = func.apply(child, args);
|
||||
#{idt}return typeof result == "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
(function(func, args, ctor) {
|
||||
#{idt}ctor.prototype = func.prototype;
|
||||
#{idt}var child = new ctor, result = func.apply(child, args);
|
||||
#{idt}return typeof result === "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
"""
|
||||
base = new Value @variable
|
||||
if (name = base.properties.pop()) and base.isComplex()
|
||||
@@ -573,7 +603,7 @@ exports.Access = class Access extends Base
|
||||
|
||||
compile: (o) ->
|
||||
name = @name.compile o
|
||||
@proto + if IS_STRING.test name then "[#{name}]" else ".#{name}"
|
||||
@proto + if IDENTIFIER.test name then ".#{name}" else "[#{name}]"
|
||||
|
||||
isComplex: NO
|
||||
|
||||
@@ -607,39 +637,48 @@ exports.Range = class Range extends Base
|
||||
# Compiles the range's source variables -- where it starts and where it ends.
|
||||
# But only if they need to be cached to avoid double evaluation.
|
||||
compileVariables: (o) ->
|
||||
o = merge(o, top: true)
|
||||
[@from, @fromVar] = @from.cache o, LEVEL_LIST
|
||||
[@to, @toVar] = @to.cache o, LEVEL_LIST
|
||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||
parts = []
|
||||
parts.push @from if @from isnt @fromVar
|
||||
parts.push @to if @to isnt @toVar
|
||||
o = merge o, top: true
|
||||
[@fromC, @fromVar] = @from.cache o, LEVEL_LIST
|
||||
[@toC, @toVar] = @to.cache o, LEVEL_LIST
|
||||
[@step, @stepVar] = step.cache o, LEVEL_LIST if step = del o, 'step'
|
||||
[@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)]
|
||||
@stepNum = @stepVar.match(SIMPLENUM) if @stepVar
|
||||
|
||||
# When compiled normally, the range returns the contents of the *for loop*
|
||||
# needed to iterate over the values in the range. Used by comprehensions.
|
||||
compileNode: (o) ->
|
||||
@compileVariables o
|
||||
return @compileArray(o) unless o.index
|
||||
return @compileSimple(o) if @fromNum and @toNum
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
intro = "(#{@fromVar} <= #{@toVar} ? #{idx}"
|
||||
compare = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})"
|
||||
stepPart = if step then step.compile(o) else '1'
|
||||
incr = if step then "#{idx} += #{stepPart}" else "#{intro} += #{stepPart} : #{idx} -= #{stepPart})"
|
||||
"#{vars}; #{compare}; #{incr}"
|
||||
@compileVariables o unless @fromVar
|
||||
return @compileArray(o) unless o.index
|
||||
|
||||
# Compile a simple range comprehension, with integers.
|
||||
compileSimple: (o) ->
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
step and= "#{idx} += #{step.compile(o)}"
|
||||
if from <= to
|
||||
"#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "#{idx}++"}"
|
||||
# Set up endpoints.
|
||||
known = @fromNum and @toNum
|
||||
idx = del o, 'index'
|
||||
varPart = "#{idx} = #{@fromC}"
|
||||
varPart += ", #{@toC}" if @toC isnt @toVar
|
||||
varPart += ", #{@step}" if @step isnt @stepVar
|
||||
[lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"]
|
||||
|
||||
# Generate the condition.
|
||||
condPart = if @stepNum
|
||||
condPart = if +@stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}"
|
||||
else if known
|
||||
[from, to] = [+@fromNum, +@toNum]
|
||||
condPart = if from <= to then "#{lt} #{to}" else "#{gt} #{to}"
|
||||
else
|
||||
"#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "#{idx}--"}"
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
condPart = "#{cond} ? #{lt} #{@toVar} : #{gt} #{@toVar}"
|
||||
|
||||
# Generate the step.
|
||||
stepPart = if @stepVar
|
||||
"#{idx} += #{@stepVar}"
|
||||
else if known
|
||||
if from <= to then "#{idx}++" else "#{idx}--"
|
||||
else
|
||||
"#{cond} ? #{idx}++ : #{idx}--"
|
||||
|
||||
# The final loop body.
|
||||
"#{varPart}; #{condPart}; #{stepPart}"
|
||||
|
||||
|
||||
# When used as a value, expand the range into the equivalent array.
|
||||
compileArray: (o) ->
|
||||
@@ -653,13 +692,15 @@ exports.Range = class Range extends Base
|
||||
pre = "\n#{idt}#{result} = [];"
|
||||
if @fromNum and @toNum
|
||||
o.index = i
|
||||
body = @compileSimple o
|
||||
body = @compileNode o
|
||||
else
|
||||
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
clause = "#{@fromVar} <= #{@toVar} ?"
|
||||
body = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
|
||||
vars = "#{i} = #{@fromC}" + if @toC isnt @toVar then ", #{@toC}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
body = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--"
|
||||
post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
|
||||
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this, arguments)"
|
||||
hasArgs = (node) -> node?.contains (n) -> n instanceof Literal and n.value is 'arguments' and not n.asKey
|
||||
args = ', arguments' if hasArgs(@from) or hasArgs(@to)
|
||||
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this#{args ? ''})"
|
||||
|
||||
#### Slice
|
||||
|
||||
@@ -701,6 +742,9 @@ exports.Obj = class Obj extends Base
|
||||
compileNode: (o) ->
|
||||
props = @properties
|
||||
return (if @front then '({})' else '{}') unless props.length
|
||||
if @generated
|
||||
for node in props when node instanceof Value
|
||||
throw new Error 'cannot have an implicit value in an implicit object'
|
||||
idt = o.indent += TAB
|
||||
lastNoncom = @lastNonComment @properties
|
||||
props = for prop, i in props
|
||||
@@ -735,11 +779,14 @@ exports.Arr = class Arr extends Base
|
||||
|
||||
children: ['objects']
|
||||
|
||||
filterImplicitObjects: Call::filterImplicitObjects
|
||||
|
||||
compileNode: (o) ->
|
||||
return '[]' unless @objects.length
|
||||
o.indent += TAB
|
||||
return code if code = Splat.compileSplattedArray o, @objects
|
||||
code = (obj.compile o, LEVEL_LIST for obj in @objects).join ', '
|
||||
objs = @filterImplicitObjects @objects
|
||||
return code if code = Splat.compileSplattedArray o, objs
|
||||
code = (obj.compile o, LEVEL_LIST for obj in objs).join ', '
|
||||
if code.indexOf('\n') >= 0
|
||||
"[\n#{o.indent}#{code}\n#{@tab}]"
|
||||
else
|
||||
@@ -786,14 +833,14 @@ exports.Class = class Class extends Base
|
||||
addBoundFunctions: (o) ->
|
||||
if @boundFuncs.length
|
||||
for bvar in @boundFuncs
|
||||
bname = bvar.compile o
|
||||
@ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this);"
|
||||
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
|
||||
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
|
||||
|
||||
# Merge the properties from a top-level object as prototypal properties
|
||||
# on the class.
|
||||
addProperties: (node, name) ->
|
||||
props = node.base.properties.slice 0
|
||||
while assign = props.shift()
|
||||
addProperties: (node, name, o) ->
|
||||
props = node.base.properties[0..]
|
||||
exprs = while assign = props.shift()
|
||||
if assign instanceof Assign
|
||||
base = assign.variable.base
|
||||
delete assign.context
|
||||
@@ -806,7 +853,8 @@ exports.Class = class Class extends Base
|
||||
if func instanceof Code
|
||||
assign = @ctor = func
|
||||
else
|
||||
assign = @ctor = new Assign(new Value(new Literal name), func)
|
||||
@externalCtor = o.scope.freeVariable 'class'
|
||||
assign = new Assign new Literal(@externalCtor), func
|
||||
else
|
||||
unless assign.variable.this
|
||||
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
|
||||
@@ -814,15 +862,16 @@ exports.Class = class Class extends Base
|
||||
@boundFuncs.push base
|
||||
func.bound = no
|
||||
assign
|
||||
compact exprs
|
||||
|
||||
# Walk the body of the class, looking for prototype properties to be converted.
|
||||
walkBody: (name) ->
|
||||
walkBody: (name, o) ->
|
||||
@traverseChildren false, (child) =>
|
||||
return false if child instanceof Class
|
||||
if child instanceof Block
|
||||
for node, i in exps = child.expressions
|
||||
if node instanceof Value and node.isObject(true)
|
||||
exps[i] = @addProperties node, name
|
||||
exps[i] = @addProperties node, name, o
|
||||
child.expressions = exps = flatten exps
|
||||
|
||||
# Make sure that a constructor is defined for the class, and properly
|
||||
@@ -830,7 +879,8 @@ exports.Class = class Class extends Base
|
||||
ensureConstructor: (name) ->
|
||||
if not @ctor
|
||||
@ctor = new Code
|
||||
@ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent
|
||||
@ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent
|
||||
@ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor
|
||||
@body.expressions.unshift @ctor
|
||||
@ctor.ctor = @ctor.name = name
|
||||
@ctor.klass = null
|
||||
@@ -845,9 +895,10 @@ exports.Class = class Class extends Base
|
||||
lname = new Literal name
|
||||
|
||||
@setContext name
|
||||
@walkBody name
|
||||
@body.expressions.unshift new Extends lname, @parent if @parent
|
||||
@walkBody name, o
|
||||
@ensureConstructor name
|
||||
@body.expressions.unshift new Extends lname, @parent if @parent
|
||||
@body.expressions.unshift @ctor unless @ctor instanceof Code
|
||||
@body.expressions.push lname
|
||||
@addBoundFunctions o
|
||||
|
||||
@@ -863,11 +914,11 @@ exports.Assign = class Assign extends Base
|
||||
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\x7f-\uffff]*)$/
|
||||
|
||||
children: ['variable', 'value']
|
||||
|
||||
isStatement: (o) ->
|
||||
o?.level is LEVEL_TOP and @context? and "?" in @context
|
||||
|
||||
assigns: (name) ->
|
||||
@[if @context is 'object' then 'value' else 'variable'].assigns name
|
||||
|
||||
@@ -884,18 +935,18 @@ exports.Assign = class Assign extends Base
|
||||
return @compileSplice o if @variable.isSplice()
|
||||
return @compileConditional o if @context in ['||=', '&&=', '?=']
|
||||
name = @variable.compile o, LEVEL_LIST
|
||||
if @value instanceof Code and match = @METHOD_DEF.exec name
|
||||
@value.name = match[2]
|
||||
@value.klass = match[1] if match[1]
|
||||
val = @value.compile o, LEVEL_LIST
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
unless @variable.isAssignable()
|
||||
unless @context or @variable.isAssignable()
|
||||
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
|
||||
unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
|
||||
if @param
|
||||
o.scope.add name, 'var'
|
||||
else
|
||||
o.scope.find name
|
||||
if @value instanceof Code and match = METHOD_DEF.exec name
|
||||
@value.klass = match[1] if match[1]
|
||||
@value.name = match[2] ? match[3] ? match[4] ? match[5]
|
||||
val = @value.compile o, LEVEL_LIST
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
val = name + " #{ @context or '=' } " + val
|
||||
if o.level <= LEVEL_LIST then val else "(#{val})"
|
||||
|
||||
@@ -908,7 +959,6 @@ exports.Assign = class Assign extends Base
|
||||
{value} = this
|
||||
{objects} = @variable.base
|
||||
unless olen = objects.length
|
||||
return false if top
|
||||
code = value.compile o
|
||||
return if o.level >= LEVEL_OP then "(#{code})" else code
|
||||
isObject = @variable.isObject()
|
||||
@@ -927,7 +977,7 @@ exports.Assign = class Assign extends Base
|
||||
acc = IDENTIFIER.test idx.unwrap().value or 0
|
||||
value = new Value value
|
||||
value.properties.push new (if acc then Access else Index) idx
|
||||
return new Assign(obj, value).compile o
|
||||
return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP
|
||||
vvar = value.compile o, LEVEL_LIST
|
||||
assigns = []
|
||||
splat = false
|
||||
@@ -969,7 +1019,7 @@ exports.Assign = class Assign extends Base
|
||||
val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
|
||||
assigns.push new Assign(obj, val, null, param: @param).compile o, LEVEL_TOP
|
||||
assigns.push vvar unless top
|
||||
code = (compact assigns).join ', '
|
||||
code = assigns.join ', '
|
||||
if o.level < LEVEL_LIST then code else "(#{code})"
|
||||
|
||||
# When compiling a conditional assignment, take care to ensure that the
|
||||
@@ -977,7 +1027,8 @@ exports.Assign = class Assign extends Base
|
||||
# more than once.
|
||||
compileConditional: (o) ->
|
||||
[left, rite] = @variable.cacheReference o
|
||||
new Op(@context.slice(0, -1), left, new Assign(rite, @value, '=')).compile o
|
||||
if "?" in @context then o.isExistentialEquals = true
|
||||
new Op(@context[0...-1], left, new Assign(rite, @value, '=') ).compile o
|
||||
|
||||
# Compile the assignment from an array splice literal, using JavaScript's
|
||||
# `Array#splice` method.
|
||||
@@ -1018,7 +1069,7 @@ exports.Code = class Code extends Base
|
||||
|
||||
# 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 `=>`
|
||||
# the JavaScript `arguments` object. If the function is bound with the `=>`
|
||||
# arrow, generates a wrapper that saves the current value of `this` through
|
||||
# a closure.
|
||||
compileNode: (o) ->
|
||||
@@ -1026,10 +1077,10 @@ exports.Code = class Code extends Base
|
||||
o.scope.shared = del o, 'sharedScope'
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
delete o.globals
|
||||
vars = []
|
||||
exprs = []
|
||||
for param in @params when param.splat
|
||||
o.scope.add p.name.value, 'var', yes for p in @params when p.name.value
|
||||
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
|
||||
new Value new Literal 'arguments'
|
||||
break
|
||||
@@ -1112,7 +1163,7 @@ exports.Splat = class Splat extends Base
|
||||
compile: (o) ->
|
||||
if @index? then @compileParam o else @name.compile o
|
||||
|
||||
# Utility function that converts arbitrary number of elements, mixed with
|
||||
# Utility function that converts an arbitrary number of elements, mixed with
|
||||
# splats, to a proper array.
|
||||
@compileSplattedArray: (o, list, apply) ->
|
||||
index = -1
|
||||
@@ -1122,14 +1173,14 @@ exports.Splat = class Splat extends Base
|
||||
code = list[0].compile o, LEVEL_LIST
|
||||
return code if apply
|
||||
return "#{ utility 'slice' }.call(#{code})"
|
||||
args = list.slice index
|
||||
args = list[index..]
|
||||
for node, i in args
|
||||
code = node.compile o, LEVEL_LIST
|
||||
args[i] = if node instanceof Splat
|
||||
then "#{ utility 'slice' }.call(#{code})"
|
||||
else "[#{code}]"
|
||||
return args[0] + ".concat(#{ args.slice(1).join ', ' })" if index is 0
|
||||
base = (node.compile o, LEVEL_LIST for node in list.slice 0, index)
|
||||
return args[0] + ".concat(#{ args[1..].join ', ' })" if index is 0
|
||||
base = (node.compile o, LEVEL_LIST for node in list[0...index])
|
||||
"[#{ base.join ', ' }].concat(#{ args.join ', ' })"
|
||||
|
||||
#### While
|
||||
@@ -1186,12 +1237,15 @@ exports.While = class While extends Base
|
||||
# Simple Arithmetic and logical operations. Performs some conversion from
|
||||
# CoffeeScript operations into their JavaScript equivalents.
|
||||
exports.Op = class Op extends Base
|
||||
constructor: (op, first, second, flip) ->
|
||||
constructor: (op, first, second, flip ) ->
|
||||
return new In first, second if op is 'in'
|
||||
return new Call first, first.params or [] if op is 'do'
|
||||
if op is 'do'
|
||||
call = new Call first, first.params or []
|
||||
call.do = yes
|
||||
return call
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call
|
||||
first = new Parens first if first instanceof Code and first.bound
|
||||
return first.newInstance() if first instanceof Call and not first.do and not first.isNew
|
||||
first = new Parens first if first instanceof Code and first.bound or first.do
|
||||
@operator = CONVERSIONS[op] or op
|
||||
@first = first
|
||||
@second = second
|
||||
@@ -1216,6 +1270,9 @@ exports.Op = class Op extends Base
|
||||
isUnary: ->
|
||||
not @second
|
||||
|
||||
isComplex: ->
|
||||
not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex()
|
||||
|
||||
# Am I capable of
|
||||
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
|
||||
isChainable: ->
|
||||
@@ -1273,18 +1330,19 @@ exports.Op = class Op extends Base
|
||||
|
||||
compileExistence: (o) ->
|
||||
if @first.isComplex()
|
||||
ref = o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign new Literal(ref), @first
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, @first
|
||||
else
|
||||
fst = @first
|
||||
ref = fst.compile o
|
||||
new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL_LIST }"
|
||||
ref = fst
|
||||
new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o
|
||||
|
||||
# Compile a unary **Op**.
|
||||
compileUnary: (o) ->
|
||||
parts = [op = @operator]
|
||||
parts.push ' ' if op in ['new', 'typeof', 'delete'] or
|
||||
op in ['+', '-'] and @first instanceof Op and @first.operator is op
|
||||
@first = new Parens @first if op is 'new' and @first.isStatement o
|
||||
parts.push @first.compile o, LEVEL_OP
|
||||
parts.reverse() if @flip
|
||||
parts.join ''
|
||||
@@ -1302,15 +1360,19 @@ exports.In = class In extends Base
|
||||
|
||||
compileNode: (o) ->
|
||||
if @array instanceof Value and @array.isArray()
|
||||
@compileOrTest o
|
||||
else
|
||||
@compileLoopTest o
|
||||
for obj in @array.base.objects when obj instanceof Splat
|
||||
hasSplat = yes
|
||||
break
|
||||
# `compileOrTest` only if we have an array literal with no splats
|
||||
return @compileOrTest o unless hasSplat
|
||||
@compileLoopTest o
|
||||
|
||||
compileOrTest: (o) ->
|
||||
[sub, ref] = @object.cache o, LEVEL_OP
|
||||
[cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
|
||||
tests = for item, i in @array.base.objects
|
||||
(if i then ref else sub) + cmp + item.compile o, LEVEL_OP
|
||||
return 'false' if tests.length is 0
|
||||
tests = tests.join cnj
|
||||
if o.level < LEVEL_OP then tests else "(#{tests})"
|
||||
|
||||
@@ -1348,6 +1410,7 @@ exports.Try = class Try extends Base
|
||||
o.indent += TAB
|
||||
errorPart = if @error then " (#{ @error.compile o }) " else ' '
|
||||
catchPart = if @recovery
|
||||
o.scope.add @error.value, 'param'
|
||||
" catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
|
||||
else unless @ensure or @recovery
|
||||
' catch (_e) {}'
|
||||
@@ -1389,13 +1452,11 @@ exports.Existence = class Existence extends Base
|
||||
compileNode: (o) ->
|
||||
code = @expression.compile o, LEVEL_OP
|
||||
code = if IDENTIFIER.test(code) and not o.scope.check code
|
||||
if @negated
|
||||
"typeof #{code} == \"undefined\" || #{code} === null"
|
||||
else
|
||||
"typeof #{code} != \"undefined\" && #{code} !== null"
|
||||
[cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&']
|
||||
"typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null"
|
||||
else
|
||||
sym = if @negated then '==' else '!='
|
||||
"#{code} #{sym} null"
|
||||
# do not use strict equality here; it will break existing code
|
||||
"#{code} #{if @negated then '==' else '!='} null"
|
||||
if o.level <= LEVEL_COND then code else "(#{code})"
|
||||
|
||||
#### Parens
|
||||
@@ -1462,50 +1523,53 @@ exports.For = class For extends Base
|
||||
# comprehensions. Some of the generated code can be shared in common, and
|
||||
# some cannot.
|
||||
compileNode: (o) ->
|
||||
body = Block.wrap [@body]
|
||||
lastJumps = last(body.expressions)?.jumps()
|
||||
@returns = no if lastJumps and lastJumps instanceof Return
|
||||
source = if @range then @source.base else @source
|
||||
scope = o.scope
|
||||
name = @name and @name.compile o, LEVEL_LIST
|
||||
index = @index and @index.compile o, LEVEL_LIST
|
||||
body = Block.wrap [@body]
|
||||
lastJumps = last(body.expressions)?.jumps()
|
||||
@returns = no if lastJumps and lastJumps instanceof Return
|
||||
source = if @range then @source.base else @source
|
||||
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
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
name = ivar if @pattern
|
||||
varPart = ''
|
||||
guardPart = ''
|
||||
defPart = ''
|
||||
idt1 = @tab + TAB
|
||||
rvar = scope.freeVariable 'results' if @returns
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
# the `_by` variable is created twice in `Range`s if we don't prevent it from being declared here
|
||||
stepvar = scope.freeVariable "step" if @step and not @range
|
||||
name = ivar if @pattern
|
||||
varPart = ''
|
||||
guardPart = ''
|
||||
defPart = ''
|
||||
idt1 = @tab + TAB
|
||||
if @range
|
||||
forPart = source.compile merge(o, {index: ivar, @step})
|
||||
else
|
||||
svar = @source.compile o, LEVEL_LIST
|
||||
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
|
||||
defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
|
||||
svar = ref
|
||||
if name and not @pattern
|
||||
namePart = "#{name} = #{svar}[#{ivar}]"
|
||||
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}"
|
||||
lvar = scope.freeVariable 'len'
|
||||
forVarPart = "#{ivar} = 0, #{lvar} = #{svar}.length" + if @step then ", #{stepvar} = #{@step.compile(o, LEVEL_OP)}" else ''
|
||||
stepPart = if @step then "#{ivar} += #{stepvar}" else "#{ivar}++"
|
||||
forPart = "#{forVarPart}; #{ivar} < #{lvar}; #{stepPart}"
|
||||
if @returns
|
||||
resultPart = "#{@tab}#{rvar} = [];\n"
|
||||
returnResult = "\n#{@tab}return #{rvar};"
|
||||
body = Push.wrap rvar, body
|
||||
resultPart = "#{@tab}#{rvar} = [];\n"
|
||||
returnResult = "\n#{@tab}return #{rvar};"
|
||||
body = Push.wrap rvar, body
|
||||
if @guard
|
||||
body = Block.wrap [new If @guard, body]
|
||||
body = Block.wrap [new If @guard, body]
|
||||
if @pattern
|
||||
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
|
||||
defPart += @pluckDirectCall o, body
|
||||
varPart = "\n#{idt1}#{namePart};" if namePart
|
||||
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
|
||||
body = body.compile merge(o, indent: idt1), LEVEL_TOP
|
||||
body = '\n' + body + '\n' if body
|
||||
forPart = "#{ivar} in #{svar}"
|
||||
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
|
||||
body = body.compile merge(o, indent: idt1), LEVEL_TOP
|
||||
body = '\n' + body + '\n' if body
|
||||
"""
|
||||
#{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
|
||||
"""
|
||||
@@ -1526,7 +1590,6 @@ exports.For = class For extends Base
|
||||
base = new Value ref
|
||||
if val.base
|
||||
[val.base, base] = [base, val]
|
||||
args.unshift new Literal 'this'
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
|
||||
defs
|
||||
@@ -1614,10 +1677,15 @@ exports.If = class If extends Base
|
||||
ensureBlock: (node) ->
|
||||
if node instanceof Block then node else new Block [node]
|
||||
|
||||
# Compile the **If** as a regular *if-else* statement. Flattened chains
|
||||
# Compile the `If` as a regular *if-else* statement. Flattened chains
|
||||
# force inner *else* bodies into statement form.
|
||||
compileStatement: (o) ->
|
||||
child = del o, 'chainChild'
|
||||
exeq = del o, 'isExistentialEquals'
|
||||
|
||||
if exeq
|
||||
return new If(@condition.invert(), @elseBodyNode(), type: 'if').compile o
|
||||
|
||||
cond = @condition.compile o, LEVEL_PAREN
|
||||
o.indent += TAB
|
||||
body = @ensureBlock(@body).compile o
|
||||
@@ -1632,7 +1700,7 @@ exports.If = class If extends Base
|
||||
else
|
||||
"{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"
|
||||
|
||||
# Compile the If as a conditional operator.
|
||||
# Compile the `If` as a conditional operator.
|
||||
compileExpression: (o) ->
|
||||
cond = @condition.compile o, LEVEL_COND
|
||||
body = @bodyNode().compile o, LEVEL_LIST
|
||||
@@ -1669,8 +1737,7 @@ Closure =
|
||||
return expressions if expressions.jumps()
|
||||
func = new Code [], Block.wrap [expressions]
|
||||
args = []
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or
|
||||
( expressions.contains @literalThis)
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
|
||||
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
||||
args = [new Literal 'this']
|
||||
args.push new Literal 'arguments' if mentionsArgs
|
||||
@@ -1729,7 +1796,7 @@ UTILITIES =
|
||||
hasProp: 'Object.prototype.hasOwnProperty'
|
||||
slice : 'Array.prototype.slice'
|
||||
|
||||
# Levels indicates a node's position in the AST. Useful for knowing if
|
||||
# Levels indicate a node's position in the AST. Useful for knowing if
|
||||
# parens are necessary or superfluous.
|
||||
LEVEL_TOP = 1 # ...;
|
||||
LEVEL_PAREN = 2 # (...)
|
||||
@@ -1741,12 +1808,24 @@ LEVEL_ACCESS = 6 # ...[0]
|
||||
# Tabs are two spaces for pretty printing.
|
||||
TAB = ' '
|
||||
|
||||
# Trim out all trailing whitespace, so that the generated code plays nice
|
||||
# with Git.
|
||||
TRAILING_WHITESPACE = /[ \t]+$/gm
|
||||
|
||||
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/
|
||||
IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"
|
||||
IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ ///
|
||||
SIMPLENUM = /^[+-]?\d+$/
|
||||
METHOD_DEF = ///
|
||||
^
|
||||
(?:
|
||||
(#{IDENTIFIER_STR})
|
||||
\.prototype
|
||||
(?:
|
||||
\.(#{IDENTIFIER_STR})
|
||||
| \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\]
|
||||
| \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\]
|
||||
)
|
||||
)
|
||||
|
|
||||
(#{IDENTIFIER_STR})
|
||||
$
|
||||
///
|
||||
|
||||
# Is a literal value a string?
|
||||
IS_STRING = /^['"]/
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.OptionParser = class OptionParser
|
||||
@rules = buildRules rules
|
||||
|
||||
# Parse the list of arguments, populating an `options` object with all of the
|
||||
# specified options, and returning it. `options.arguments` will be an array
|
||||
# specified options, and return it. `options.arguments` will be an array
|
||||
# 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
|
||||
|
||||
108
src/repl.coffee
108
src/repl.coffee
@@ -6,42 +6,128 @@
|
||||
|
||||
# Require the **coffee-script** module to get access to the compiler.
|
||||
CoffeeScript = require './coffee-script'
|
||||
helpers = require './helpers'
|
||||
readline = require 'readline'
|
||||
{inspect} = require 'util'
|
||||
{Script} = require 'vm'
|
||||
Module = require 'module'
|
||||
|
||||
# REPL Setup
|
||||
|
||||
# Config
|
||||
REPL_PROMPT = 'coffee> '
|
||||
REPL_PROMPT_CONTINUATION = '......> '
|
||||
enableColours = no
|
||||
unless process.platform is 'win32'
|
||||
enableColours = not process.env.NODE_DISABLE_COLORS
|
||||
|
||||
# Start by opening up `stdin` and `stdout`.
|
||||
stdin = process.openStdin()
|
||||
stdin = process.openStdin()
|
||||
stdout = process.stdout
|
||||
|
||||
# Log an error.
|
||||
error = (err) ->
|
||||
stdout.write (err.stack or err.toString()) + '\n\n'
|
||||
|
||||
# Quick alias for quitting the REPL.
|
||||
helpers.extend global, quit: -> process.exit(0)
|
||||
# The current backlog of multi-line code.
|
||||
backlog = ''
|
||||
|
||||
# The REPL context; must be visible outside `run` to allow for tab completion
|
||||
sandbox = Script.createContext()
|
||||
nonContextGlobals = [
|
||||
'Buffer', 'console', 'process'
|
||||
'setInterval', 'clearInterval'
|
||||
'setTimeout', 'clearTimeout'
|
||||
]
|
||||
sandbox[g] = global[g] for g in nonContextGlobals
|
||||
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
|
||||
|
||||
# The main REPL function. **run** is called every time a line of code is entered.
|
||||
# Attempt to evaluate the command. If there's an exception, print it out instead
|
||||
# of exiting.
|
||||
run = (buffer) ->
|
||||
if !buffer.toString().trim() and !backlog
|
||||
repl.prompt()
|
||||
return
|
||||
code = backlog += buffer
|
||||
if code[code.length - 1] is '\\'
|
||||
backlog = "#{backlog[...-1]}\n"
|
||||
repl.setPrompt REPL_PROMPT_CONTINUATION
|
||||
repl.prompt()
|
||||
return
|
||||
repl.setPrompt REPL_PROMPT
|
||||
backlog = ''
|
||||
try
|
||||
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, filename: 'repl'
|
||||
process.stdout.write val + '\n' if val isnt undefined
|
||||
_ = sandbox._
|
||||
returnValue = CoffeeScript.eval "_=(#{code}\n)", {
|
||||
sandbox,
|
||||
filename: 'repl'
|
||||
modulename: 'repl'
|
||||
}
|
||||
if returnValue is undefined
|
||||
sandbox._ = _
|
||||
else
|
||||
process.stdout.write inspect(returnValue, no, 2, enableColours) + '\n'
|
||||
catch err
|
||||
error err
|
||||
repl.prompt()
|
||||
|
||||
## Autocompletion
|
||||
|
||||
# Regexes to match complete-able bits of text.
|
||||
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/
|
||||
SIMPLEVAR = /\s*(\w*)$/i
|
||||
|
||||
# Returns a list of completions, and the completed text.
|
||||
autocomplete = (text) ->
|
||||
completeAttribute(text) or completeVariable(text) or [[], text]
|
||||
|
||||
# Attempt to autocomplete a chained dotted attribute: `one.two.three`.
|
||||
completeAttribute = (text) ->
|
||||
if match = text.match ACCESSOR
|
||||
[all, obj, prefix] = match
|
||||
try
|
||||
val = Script.runInContext obj, sandbox
|
||||
catch error
|
||||
return
|
||||
completions = getCompletions prefix, Object.getOwnPropertyNames val
|
||||
[completions, prefix]
|
||||
|
||||
# Attempt to autocomplete an in-scope free variable: `one`.
|
||||
completeVariable = (text) ->
|
||||
if free = (text.match SIMPLEVAR)?[1]
|
||||
vars = Script.runInContext 'Object.getOwnPropertyNames(this)', sandbox
|
||||
possibilities = vars.concat CoffeeScript.RESERVED
|
||||
completions = getCompletions free, possibilities
|
||||
[completions, free]
|
||||
|
||||
# Return elements of candidates for which `prefix` is a prefix.
|
||||
getCompletions = (prefix, candidates) ->
|
||||
(el for el in candidates when el.indexOf(prefix) is 0)
|
||||
|
||||
# Make sure that uncaught exceptions don't kill the REPL.
|
||||
process.on 'uncaughtException', error
|
||||
|
||||
# Create the REPL by listening to **stdin**.
|
||||
if readline.createInterface.length < 3
|
||||
repl = readline.createInterface stdin
|
||||
repl = readline.createInterface stdin, autocomplete
|
||||
stdin.on 'data', (buffer) -> repl.write buffer
|
||||
else
|
||||
repl = readline.createInterface stdin, stdout
|
||||
repl = readline.createInterface stdin, stdout, autocomplete
|
||||
|
||||
repl.setPrompt 'coffee> '
|
||||
repl.on 'close', -> stdin.destroy()
|
||||
repl.on 'line', run
|
||||
repl.on 'attemptClose', ->
|
||||
if backlog
|
||||
backlog = ''
|
||||
process.stdout.write '\n'
|
||||
repl.setPrompt REPL_PROMPT
|
||||
repl.prompt()
|
||||
else
|
||||
repl.close()
|
||||
|
||||
repl.on 'close', ->
|
||||
process.stdout.write '\n'
|
||||
stdin.destroy()
|
||||
|
||||
repl.on 'line', run
|
||||
|
||||
repl.setPrompt REPL_PROMPT
|
||||
repl.prompt()
|
||||
|
||||
@@ -104,7 +104,10 @@ class exports.Rewriter
|
||||
not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':')) or
|
||||
(tag is ',' and one and
|
||||
one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
|
||||
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
|
||||
action = (token, i) ->
|
||||
tok = ['}', '}', token[2]]
|
||||
tok.generated = yes
|
||||
@tokens.splice i, 0, tok
|
||||
@scanTokens (token, i, tokens) ->
|
||||
if (tag = token[0]) in EXPRESSION_START
|
||||
stack.push [(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag), i]
|
||||
@@ -137,12 +140,14 @@ class exports.Rewriter
|
||||
tag = token[0]
|
||||
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
|
||||
token.call = yes if prev and not prev.spaced and tag is '?'
|
||||
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
|
||||
seenControl = no
|
||||
noCall = no if tag in LINEBREAKS
|
||||
token.call = yes if prev and not prev.spaced and tag is '?'
|
||||
return 1 if token.fromThen
|
||||
return 1 unless callObject or
|
||||
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
|
||||
(tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)
|
||||
@@ -150,9 +155,11 @@ class exports.Rewriter
|
||||
@detectEnd i + 1, (token, i) ->
|
||||
[tag] = token
|
||||
return yes if not seenSingle and token.fromThen
|
||||
seenSingle = yes if tag in ['IF', 'ELSE', '->', '=>']
|
||||
seenSingle = yes if tag in ['IF', 'ELSE', 'CATCH', '->', '=>']
|
||||
seenControl = yes if tag in ['IF', 'ELSE', 'SWITCH', 'TRY']
|
||||
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
|
||||
not token.generated and @tag(i - 1) isnt ',' and (tag in IMPLICIT_END or
|
||||
(tag is 'INDENT' and not seenControl)) and
|
||||
(tag isnt 'INDENT' or
|
||||
(@tag(i - 2) isnt 'CLASS' and @tag(i - 1) not in IMPLICIT_BLOCK and
|
||||
not ((post = @tokens[i + 1]) and post.generated and post[0] is '{')))
|
||||
@@ -315,7 +322,7 @@ IMPLICIT_UNSPACED_CALL = ['+', '-']
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']
|
||||
|
||||
# Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR', 'INDENT']
|
||||
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR']
|
||||
|
||||
# Single-line flavors of block expressions that have unclosed endings.
|
||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
|
||||
@@ -14,10 +14,10 @@ exports.Scope = class Scope
|
||||
@root: null
|
||||
|
||||
# Initialize a scope with its parent, for lookups up the chain,
|
||||
# as well as a reference to the **Block** node is belongs to, which is
|
||||
# as well as a reference to the **Block** node it belongs to, which is
|
||||
# where it should declare its variables, and a reference to the function that
|
||||
# it wraps.
|
||||
constructor:(@parent, @expressions, @method) ->
|
||||
constructor: (@parent, @expressions, @method) ->
|
||||
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||
@positions = {}
|
||||
Scope.root = this unless @parent
|
||||
@@ -66,7 +66,7 @@ exports.Scope = class Scope
|
||||
# compiler-generated variable. `_var`, `_var2`, and so on...
|
||||
freeVariable: (type) ->
|
||||
index = 0
|
||||
index++ while @check((temp = @temporary type, index), true)
|
||||
index++ while @check((temp = @temporary type, index))
|
||||
@add temp, 'var', yes
|
||||
temp
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
# Array Literals
|
||||
# --------------
|
||||
|
||||
# * Array Literals
|
||||
# * Splats in Array Literals
|
||||
|
||||
# TODO: refactor array literal tests
|
||||
# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()
|
||||
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
ok a.length is 2
|
||||
|
||||
# Funky indentation within non-comma-seperated arrays.
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
|
||||
|
||||
#### Splats in Array Literals
|
||||
|
||||
test "array splat expansions with assignments", ->
|
||||
nums = [1, 2, 3]
|
||||
list = [a = 0, nums..., b = 4]
|
||||
eq 0, a
|
||||
eq 4, b
|
||||
arrayEq [0,1,2,3,4], list
|
||||
77
test/arrays.coffee
Normal file
77
test/arrays.coffee
Normal file
@@ -0,0 +1,77 @@
|
||||
# Array Literals
|
||||
# --------------
|
||||
|
||||
# * Array Literals
|
||||
# * Splats in Array Literals
|
||||
|
||||
# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()
|
||||
|
||||
test "trailing commas", ->
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
ok a.length is 2
|
||||
|
||||
test "incorrect indentation without commas", ->
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
|
||||
|
||||
# Splats in Array Literals
|
||||
|
||||
test "array splat expansions with assignments", ->
|
||||
nums = [1, 2, 3]
|
||||
list = [a = 0, nums..., b = 4]
|
||||
eq 0, a
|
||||
eq 4, b
|
||||
arrayEq [0,1,2,3,4], list
|
||||
|
||||
|
||||
test "mixed shorthand objects in array lists", ->
|
||||
|
||||
arr = [
|
||||
a:1
|
||||
'b'
|
||||
c:1
|
||||
]
|
||||
ok arr.length is 3
|
||||
ok arr[2].c is 1
|
||||
|
||||
arr = [b: 1, a: 2, 100]
|
||||
eq arr[1], 100
|
||||
|
||||
arr = [a:0, b:1, (1 + 1)]
|
||||
eq arr[1], 2
|
||||
|
||||
arr = [a:1, 'a', b:1, 'b']
|
||||
eq arr.length, 4
|
||||
eq arr[2].b, 1
|
||||
eq arr[3], 'b'
|
||||
|
||||
|
||||
test "array splats with nested arrays", ->
|
||||
nonce = {}
|
||||
a = [nonce]
|
||||
list = [1, 2, a...]
|
||||
eq list[0], 1
|
||||
eq list[2], nonce
|
||||
|
||||
a = [[nonce]]
|
||||
list = [1, 2, a...]
|
||||
arrayEq list, [1, 2, [nonce]]
|
||||
|
||||
test "#1274: `[] = a()` compiles to `false` instead of `a()`", ->
|
||||
a = false
|
||||
fn = -> a = true
|
||||
[] = fn()
|
||||
ok a
|
||||
@@ -1,8 +1,6 @@
|
||||
# Assignment
|
||||
# ----------
|
||||
|
||||
# TODO: organize assignment file
|
||||
|
||||
# * Assignment
|
||||
# * Compound Assignment
|
||||
# * Destructuring Assignment
|
||||
@@ -27,7 +25,7 @@ test "compound assignments should not declare", ->
|
||||
eq Math, (-> Math or= 0)()
|
||||
|
||||
|
||||
#### Compound Assignment
|
||||
# Compound Assignment
|
||||
|
||||
test "boolean operators", ->
|
||||
nonce = {}
|
||||
@@ -136,7 +134,7 @@ test "more compound assignment", ->
|
||||
eq c, val
|
||||
|
||||
|
||||
#### Destructuring Assignment
|
||||
# Destructuring Assignment
|
||||
|
||||
test "empty destructuring assignment", ->
|
||||
{} = [] = undefined
|
||||
@@ -231,6 +229,10 @@ test "destructuring assignment against an expression", ->
|
||||
eq a, y
|
||||
eq b, z
|
||||
|
||||
test "bracket insertion when necessary", ->
|
||||
[a] = [0] ? [1]
|
||||
eq a, 0
|
||||
|
||||
# for implicit destructuring assignment in comprehensions, see the comprehension tests
|
||||
|
||||
test "destructuring assignment with context (@) properties", ->
|
||||
@@ -251,7 +253,7 @@ test "#1024", ->
|
||||
eq 2 * [] = 3 + 5, 16
|
||||
|
||||
|
||||
#### Existential Assignment
|
||||
# Existential Assignment
|
||||
|
||||
test "existential assignment", ->
|
||||
nonce = {}
|
||||
@@ -266,3 +268,21 @@ test "existential assignment", ->
|
||||
eq nonce, c
|
||||
d ?= nonce
|
||||
eq nonce, d
|
||||
|
||||
test "#1348, #1216: existential assignment compilation", ->
|
||||
nonce = {}
|
||||
a = nonce
|
||||
b = (a ?= 0)
|
||||
eq nonce, b
|
||||
#the first ?= compiles into a statement; the second ?= compiles to a ternary expression
|
||||
eq a ?= b ?= 1, nonce
|
||||
|
||||
e ?= f ?= g ?= 1
|
||||
eq e + g, 2
|
||||
|
||||
#need to ensure the two vars are not defined, hence the strange names;
|
||||
# broke earlier when using c ?= d ?= 1 because `d` is declared elsewhere
|
||||
eq und1_1348 ?= und2_1348 ?= 1, 1
|
||||
|
||||
if a then a ?= 2 else a = 3
|
||||
eq a, nonce
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Boolean Literals
|
||||
# ----------------
|
||||
|
||||
# TODO: add method invocation tests: true.toString() is "true"
|
||||
|
||||
#764: Boolean should be indexable
|
||||
toString = Boolean::toString
|
||||
|
||||
eq toString, true['toString']
|
||||
eq toString, false['toString']
|
||||
eq toString, yes['toString']
|
||||
eq toString, no['toString']
|
||||
eq toString, on['toString']
|
||||
eq toString, off['toString']
|
||||
|
||||
eq toString, true.toString
|
||||
eq toString, false.toString
|
||||
eq toString, yes.toString
|
||||
eq toString, no.toString
|
||||
eq toString, on.toString
|
||||
eq toString, off.toString
|
||||
21
test/booleans.coffee
Normal file
21
test/booleans.coffee
Normal file
@@ -0,0 +1,21 @@
|
||||
# Boolean Literals
|
||||
# ----------------
|
||||
|
||||
# TODO: add method invocation tests: true.toString() is "true"
|
||||
|
||||
test "#764 Booleans should be indexable", ->
|
||||
toString = Boolean::toString
|
||||
|
||||
eq toString, true['toString']
|
||||
eq toString, false['toString']
|
||||
eq toString, yes['toString']
|
||||
eq toString, no['toString']
|
||||
eq toString, on['toString']
|
||||
eq toString, off['toString']
|
||||
|
||||
eq toString, true.toString
|
||||
eq toString, false.toString
|
||||
eq toString, yes.toString
|
||||
eq toString, no.toString
|
||||
eq toString, on.toString
|
||||
eq toString, off.toString
|
||||
@@ -1,4 +0,0 @@
|
||||
# Cake
|
||||
# ----
|
||||
|
||||
# TODO: add tests
|
||||
@@ -5,113 +5,119 @@
|
||||
# * Class Instantiation
|
||||
# * Inheritance and Super
|
||||
|
||||
# TODO: refactor class tests
|
||||
test "classes with a four-level inheritance chain", ->
|
||||
|
||||
# Test classes with a four-level inheritance chain.
|
||||
class Base
|
||||
func: (string) ->
|
||||
"zero/#{string}"
|
||||
class Base
|
||||
func: (string) ->
|
||||
"zero/#{string}"
|
||||
|
||||
@static: (string) ->
|
||||
"static/#{string}"
|
||||
@static: (string) ->
|
||||
"static/#{string}"
|
||||
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild = class extends FirstChild
|
||||
func: (string) ->
|
||||
super('two/') + string
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/').length + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is '9two/three/four'
|
||||
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
|
||||
|
||||
test "constructors with inheritance and super", ->
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
test "Overriding the static property new doesn't clobber Function::new", ->
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
test "basic classes, again, but in the manual prototype style", ->
|
||||
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-#{string}"
|
||||
|
||||
FirstChild = ->
|
||||
SecondChild = ->
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
|
||||
ThirdChild extends SecondChild extends FirstChild extends Base
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild = class extends FirstChild
|
||||
func: (string) ->
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/').length + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is '9two/three/four'
|
||||
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
# And now the same tests, but written in the manual style:
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-#{string}"
|
||||
|
||||
FirstChild = ->
|
||||
SecondChild = ->
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
|
||||
ThirdChild extends SecondChild extends FirstChild extends Base
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
test "super with plain ol' functions as the original constructors", ->
|
||||
|
||||
TopClass = (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
@@ -131,283 +137,356 @@ SubClass extends SuperClass
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
# '@' referring to the current instance, and not being coerced into a call.
|
||||
class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
test "'@' referring to the current instance, and not being coerced into a call", ->
|
||||
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
|
||||
|
||||
# super() calls in constructors of classes that are defined as object properties.
|
||||
class Hive
|
||||
constructor: (name) -> @name = name
|
||||
test "super() calls in constructors of classes that are defined as object properties", ->
|
||||
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
class Hive
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
|
||||
|
||||
# Class with JS-keyword properties.
|
||||
class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
test "classes with JS-keyword properties", ->
|
||||
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
|
||||
|
||||
# Classes with methods that are pre-bound to the instance.
|
||||
# ... or statically, to the class.
|
||||
class Dog
|
||||
test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
|
||||
|
||||
constructor: (name) ->
|
||||
@name = name
|
||||
class Dog
|
||||
constructor: (name) ->
|
||||
@name = name
|
||||
|
||||
bark: =>
|
||||
"#{@name} woofs!"
|
||||
bark: =>
|
||||
"#{@name} woofs!"
|
||||
|
||||
@static = =>
|
||||
new this('Dog')
|
||||
@static = =>
|
||||
new this('Dog')
|
||||
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
|
||||
obj = func: Dog.static
|
||||
obj = func: Dog.static
|
||||
|
||||
ok obj.func().name is 'Dog'
|
||||
ok obj.func().name is 'Dog'
|
||||
|
||||
|
||||
# Testing a bound function in a bound function.
|
||||
class Mini
|
||||
num: 10
|
||||
generate: =>
|
||||
for i in [1..3]
|
||||
=>
|
||||
@num
|
||||
test "a bound function in a bound function", ->
|
||||
|
||||
m = new Mini
|
||||
eq (func() for func in m.generate()).join(' '), '10 10 10'
|
||||
class Mini
|
||||
num: 10
|
||||
generate: =>
|
||||
for i in [1..3]
|
||||
=>
|
||||
@num
|
||||
|
||||
m = new Mini
|
||||
eq (func() for func in m.generate()).join(' '), '10 10 10'
|
||||
|
||||
|
||||
# Testing a contructor called with varargs.
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
test "contructor called with varargs", ->
|
||||
|
||||
out: ->
|
||||
"#{@one}-#{@two}-#{@three}"
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
out: ->
|
||||
"#{@one}-#{@two}-#{@three}"
|
||||
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
|
||||
|
||||
# Test calling super and passing along all arguments.
|
||||
class Parent
|
||||
method: (args...) -> @args = args
|
||||
test "calling super and passing along all arguments", ->
|
||||
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
class Parent
|
||||
method: (args...) -> @args = args
|
||||
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
|
||||
|
||||
# Test classes wrapped in decorators.
|
||||
func = (klass) ->
|
||||
klass::prop = 'value'
|
||||
klass
|
||||
test "classes wrapped in decorators", ->
|
||||
|
||||
func class Test
|
||||
prop2: 'value2'
|
||||
func = (klass) ->
|
||||
klass::prop = 'value'
|
||||
klass
|
||||
|
||||
ok (new Test).prop is 'value'
|
||||
ok (new Test).prop2 is 'value2'
|
||||
func class Test
|
||||
prop2: 'value2'
|
||||
|
||||
ok (new Test).prop is 'value'
|
||||
ok (new Test).prop2 is 'value2'
|
||||
|
||||
|
||||
# Test anonymous classes.
|
||||
obj =
|
||||
klass: class
|
||||
method: -> 'value'
|
||||
test "anonymous classes", ->
|
||||
|
||||
instance = new obj.klass
|
||||
ok instance.method() is 'value'
|
||||
obj =
|
||||
klass: class
|
||||
method: -> 'value'
|
||||
|
||||
instance = new obj.klass
|
||||
ok instance.method() is 'value'
|
||||
|
||||
|
||||
# Implicit objects as static properties.
|
||||
class Static
|
||||
@static =
|
||||
one: 1
|
||||
two: 2
|
||||
test "Implicit objects as static properties", ->
|
||||
|
||||
ok Static.static.one is 1
|
||||
ok Static.static.two is 2
|
||||
class Static
|
||||
@static =
|
||||
one: 1
|
||||
two: 2
|
||||
|
||||
ok Static.static.one is 1
|
||||
ok Static.static.two is 2
|
||||
|
||||
|
||||
# Nothing classes.
|
||||
c = class
|
||||
ok c instanceof Function
|
||||
test "nothing classes", ->
|
||||
|
||||
c = class
|
||||
ok c instanceof Function
|
||||
|
||||
|
||||
# Classes with value'd constructors.
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
counter++
|
||||
inner = counter
|
||||
->
|
||||
@value = inner
|
||||
test "classes with value'd constructors", ->
|
||||
|
||||
class One
|
||||
constructor: classMaker()
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
inner = ++counter
|
||||
->
|
||||
@value = inner
|
||||
|
||||
class Two
|
||||
constructor: classMaker()
|
||||
class One
|
||||
constructor: classMaker()
|
||||
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
class Two
|
||||
constructor: classMaker()
|
||||
|
||||
eq (new One).value, 1
|
||||
eq (new Two).value, 2
|
||||
eq (new One).value, 1
|
||||
eq (new Two).value, 2
|
||||
|
||||
|
||||
# Exectuable class bodies.
|
||||
class A
|
||||
if true
|
||||
b: 'b'
|
||||
else
|
||||
c: 'c'
|
||||
test "exectuable class bodies", ->
|
||||
|
||||
a = new A
|
||||
class A
|
||||
if true
|
||||
b: 'b'
|
||||
else
|
||||
c: 'c'
|
||||
|
||||
eq a.b, 'b'
|
||||
eq a.c, undefined
|
||||
a = new A
|
||||
|
||||
eq a.b, 'b'
|
||||
eq a.c, undefined
|
||||
|
||||
|
||||
# Light metaprogramming.
|
||||
class Base
|
||||
@attr: (name) ->
|
||||
@::[name] = (val) ->
|
||||
if arguments.length > 0
|
||||
@["_#{name}"] = val
|
||||
else
|
||||
@["_#{name}"]
|
||||
test "mild metaprogramming", ->
|
||||
|
||||
class Robot extends Base
|
||||
@attr 'power'
|
||||
@attr 'speed'
|
||||
class Base
|
||||
@attr: (name) ->
|
||||
@::[name] = (val) ->
|
||||
if arguments.length > 0
|
||||
@["_#{name}"] = val
|
||||
else
|
||||
@["_#{name}"]
|
||||
|
||||
robby = new Robot
|
||||
class Robot extends Base
|
||||
@attr 'power'
|
||||
@attr 'speed'
|
||||
|
||||
ok robby.power() is undefined
|
||||
robby = new Robot
|
||||
|
||||
robby.power 11
|
||||
robby.speed Infinity
|
||||
ok robby.power() is undefined
|
||||
|
||||
eq robby.power(), 11
|
||||
eq robby.speed(), Infinity
|
||||
robby.power 11
|
||||
robby.speed Infinity
|
||||
|
||||
eq robby.power(), 11
|
||||
eq robby.speed(), Infinity
|
||||
|
||||
|
||||
# Namespaced classes do not reserve their function name in outside scope.
|
||||
one = {}
|
||||
two = {}
|
||||
test "namespaced classes do not reserve their function name in outside scope", ->
|
||||
|
||||
class one.Klass
|
||||
@label = "one"
|
||||
one = {}
|
||||
two = {}
|
||||
|
||||
class two.Klass
|
||||
@label = "two"
|
||||
class one.Klass
|
||||
@label = "one"
|
||||
|
||||
eq typeof Klass, 'undefined'
|
||||
eq one.Klass.label, 'one'
|
||||
eq two.Klass.label, 'two'
|
||||
class two.Klass
|
||||
@label = "two"
|
||||
|
||||
eq typeof Klass, 'undefined'
|
||||
eq one.Klass.label, 'one'
|
||||
eq two.Klass.label, 'two'
|
||||
|
||||
|
||||
# Nested classes.
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'outer'
|
||||
test "nested classes", ->
|
||||
|
||||
class @Inner
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
@label = 'outer'
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
class @Inner
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
|
||||
|
||||
# Variables in constructor bodies are correctly scoped.
|
||||
class A
|
||||
x = 1
|
||||
constructor: ->
|
||||
x = 10
|
||||
y = 20
|
||||
y = 2
|
||||
captured: ->
|
||||
{x, y}
|
||||
test "variables in constructor bodies are correctly scoped", ->
|
||||
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
class A
|
||||
x = 1
|
||||
constructor: ->
|
||||
x = 10
|
||||
y = 20
|
||||
y = 2
|
||||
captured: ->
|
||||
{x, y}
|
||||
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
|
||||
|
||||
# Issue #924: Static methods in nested classes.
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
test "Issue #924: Static methods in nested classes", ->
|
||||
|
||||
eq A.B.c(), 5
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
|
||||
eq A.B.c(), 5
|
||||
|
||||
|
||||
# `class extends this` ...
|
||||
class A
|
||||
func: -> 'A'
|
||||
test "`class extends this`", ->
|
||||
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
class A
|
||||
func: -> 'A'
|
||||
|
||||
makeClass.call A
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
makeClass.call A
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
|
||||
|
||||
test "ensure that constructors invoked with splats return a new object", ->
|
||||
|
||||
args = [1, 2, 3]
|
||||
Type = (@args) ->
|
||||
type = new Type args
|
||||
|
||||
ok type and type instanceof Type
|
||||
ok type.args and type.args instanceof Array
|
||||
ok v is args[i] for v, i in type.args
|
||||
|
||||
Type1 = (@a, @b, @c) ->
|
||||
type1 = new Type1 args...
|
||||
|
||||
ok type1 instanceof Type1
|
||||
eq type1.constructor, Type1
|
||||
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
|
||||
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
|
||||
test "`new` shouldn't add extra parens", ->
|
||||
|
||||
ok new Date().constructor is Date
|
||||
|
||||
|
||||
# Ensure that constructors invoked with splats return a new object.
|
||||
args = [1, 2, 3]
|
||||
Type = (@args) ->
|
||||
type = new Type args
|
||||
test "`new` works against bare function", ->
|
||||
|
||||
ok type and type instanceof Type
|
||||
ok type.args and type.args instanceof Array
|
||||
ok v is args[i] for v, i in type.args
|
||||
eq Date, new ->
|
||||
eq this, new => this
|
||||
Date
|
||||
|
||||
Type1 = (@a, @b, @c) ->
|
||||
type1 = new Type1 args...
|
||||
|
||||
ok type1 instanceof Type1
|
||||
eq type1.constructor, Type1
|
||||
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
|
||||
test "#1182: a subclass should be able to set its constructor to an external function", ->
|
||||
ctor = ->
|
||||
@val = 1
|
||||
class A
|
||||
class B extends A
|
||||
constructor: ctor
|
||||
eq (new B).val, 1
|
||||
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
test "#1182: external constructors continued", ->
|
||||
ctor = ->
|
||||
class A
|
||||
class B extends A
|
||||
method: ->
|
||||
constructor: ctor
|
||||
ok B::method
|
||||
|
||||
# `new` shouldn't add extra parens
|
||||
ok new Date().constructor is Date
|
||||
test "#1313: misplaced __extends", ->
|
||||
nonce = {}
|
||||
class A
|
||||
class B extends A
|
||||
prop: nonce
|
||||
constructor: ->
|
||||
eq nonce, B::prop
|
||||
|
||||
# `new` works against bare function
|
||||
eq Date, new ->
|
||||
eq this, new => this
|
||||
Date
|
||||
test "#1182: execution order needs to be considered as well", ->
|
||||
counter = 0
|
||||
makeFn = (n) -> eq n, ++counter; ->
|
||||
class B extends (makeFn 1)
|
||||
@B: makeFn 2
|
||||
constructor: makeFn 3
|
||||
|
||||
test "#1182: external constructors with bound functions", ->
|
||||
fn = ->
|
||||
{one: 1}
|
||||
class B
|
||||
class A
|
||||
constructor: fn
|
||||
method: => this instanceof A
|
||||
ok (new A).method.call(new B)
|
||||
|
||||
test "#1372: bound class methods with reserved names", ->
|
||||
class C
|
||||
delete: =>
|
||||
ok C::delete
|
||||
|
||||
test "#1380: `super` with reserved names", ->
|
||||
class C
|
||||
do: -> super
|
||||
ok C::do
|
||||
|
||||
class B
|
||||
0: -> super
|
||||
ok B::[0]
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Command
|
||||
# -------
|
||||
|
||||
# TODO: add tests
|
||||
@@ -110,7 +110,7 @@ test "spaced comments with conditional statements", ->
|
||||
eq nonce, result
|
||||
|
||||
|
||||
#### Block Comments
|
||||
# Block Comments
|
||||
|
||||
###
|
||||
This is a here-comment.
|
||||
|
||||
@@ -1,47 +1,43 @@
|
||||
# Compilation
|
||||
# -----------
|
||||
|
||||
# TODO: refactor compilation tests
|
||||
|
||||
# helper to assert that a string should fail compilation
|
||||
cantCompile = (code) ->
|
||||
throws -> CoffeeScript.compile code
|
||||
|
||||
|
||||
# Ensure that carriage returns don't break compilation on Windows.
|
||||
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
|
||||
test "ensure that carriage returns don't break compilation on Windows", ->
|
||||
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
|
||||
|
||||
# `globals: on` removes `var`s
|
||||
eq -1, CoffeeScript.compile('x = y', bare: on, globals: on).indexOf 'var'
|
||||
test "--bare", ->
|
||||
eq -1, CoffeeScript.compile('x = y', bare: on).indexOf 'function'
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
|
||||
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
|
||||
|
||||
# multiple generated references
|
||||
(->
|
||||
test "multiple generated references", ->
|
||||
a = {b: []}
|
||||
a.b[true] = -> this == a.b
|
||||
c = 0
|
||||
d = []
|
||||
ok a.b[0<++c<2] d...
|
||||
)()
|
||||
|
||||
# Splat on a line by itself is invalid.
|
||||
cantCompile "x 'a'\n...\n"
|
||||
test "splat on a line by itself is invalid", ->
|
||||
cantCompile "x 'a'\n...\n"
|
||||
|
||||
#750
|
||||
cantCompile 'f(->'
|
||||
test "Issue 750", ->
|
||||
|
||||
cantCompile 'a = (break)'
|
||||
cantCompile 'f(->'
|
||||
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
cantCompile 'a = (break)'
|
||||
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
|
||||
# Issue #986: Unicode identifiers.
|
||||
λ = 5
|
||||
eq λ, 5
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
|
||||
test "Issue #986: Unicode identifiers", ->
|
||||
λ = 5
|
||||
eq λ, 5
|
||||
|
||||
test "don't accidentally stringify keywords", ->
|
||||
ok (-> this == 'this')() is false
|
||||
@@ -55,3 +51,11 @@ test "#1026", ->
|
||||
else
|
||||
d
|
||||
'''
|
||||
|
||||
test "#1050", ->
|
||||
cantCompile "### */ ###"
|
||||
|
||||
test "#1106: __proto__ compilation", ->
|
||||
object = eq
|
||||
@["__proto__"] = true
|
||||
ok __proto__
|
||||
|
||||
@@ -9,323 +9,357 @@
|
||||
|
||||
# TODO: refactor comprehension tests
|
||||
|
||||
# Basic array comprehensions.
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
test "Basic array comprehensions.", ->
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
|
||||
|
||||
# Basic object comprehensions.
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = (prop + '!' for prop of obj)
|
||||
odds = (prop + '!' for prop, value of obj when value & 1)
|
||||
test "Basic object comprehensions.", ->
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = (prop + '!' for prop of obj)
|
||||
odds = (prop + '!' for prop, value of obj when value & 1)
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
|
||||
|
||||
# Basic range comprehensions.
|
||||
nums = (i * 3 for i in [1..3])
|
||||
test "Basic range comprehensions.", ->
|
||||
|
||||
negs = (x for x in [-20..-5*2])
|
||||
negs = negs[0..2]
|
||||
nums = (i * 3 for i in [1..3])
|
||||
|
||||
result = nums.concat(negs).join(', ')
|
||||
negs = (x for x in [-20..-5*2])
|
||||
negs = negs[0..2]
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
result = nums.concat(negs).join(', ')
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
|
||||
|
||||
# With range comprehensions, you can loop in steps.
|
||||
results = (x for x in [0...15] by 5)
|
||||
ok results.join(' ') is '0 5 10'
|
||||
test "With range comprehensions, you can loop in steps.", ->
|
||||
|
||||
results = (x for x in [0..100] by 10)
|
||||
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
|
||||
results = (x for x in [0...15] by 5)
|
||||
ok results.join(' ') is '0 5 10'
|
||||
|
||||
results = (x for x in [0..100] by 10)
|
||||
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
|
||||
|
||||
|
||||
# And can loop downwards, with a negative step.
|
||||
results = (x for x in [5..1])
|
||||
test "And can loop downwards, with a negative step.", ->
|
||||
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
results = (x for x in [5..1])
|
||||
|
||||
results = (x for x in [10..1])
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
|
||||
results = (x for x in [10...0] by -2)
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
results = (x for x in [10..1])
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
|
||||
results = (x for x in [10...0] by -2)
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
|
||||
|
||||
# Range comprehension gymnastics.
|
||||
eq "#{i for i in [5..1]}", '5,4,3,2,1'
|
||||
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
|
||||
test "Range comprehension gymnastics.", ->
|
||||
|
||||
a = 6
|
||||
b = 0
|
||||
c = -2
|
||||
eq "#{i for i in [5..1]}", '5,4,3,2,1'
|
||||
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
|
||||
|
||||
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
|
||||
eq "#{i for i in [a..b] by c}", '6,4,2,0'
|
||||
a = 6
|
||||
b = 0
|
||||
c = -2
|
||||
|
||||
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
|
||||
eq "#{i for i in [a..b] by c}", '6,4,2,0'
|
||||
|
||||
|
||||
# Multiline array comprehension with filter.
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
eq evens + '', '4,6,8'
|
||||
test "Multiline array comprehension with filter.", ->
|
||||
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
eq evens + '', '4,6,8'
|
||||
|
||||
|
||||
# The in operator still works, standalone.
|
||||
ok 2 of evens
|
||||
test "The in operator still works, standalone.", ->
|
||||
|
||||
# all isn't reserved.
|
||||
all = 1
|
||||
ok 2 of evens
|
||||
|
||||
|
||||
# Ensure that the closure wrapper preserves local variables.
|
||||
obj = {}
|
||||
test "all isn't reserved.", ->
|
||||
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
all = 1
|
||||
|
||||
|
||||
# Index values at the end of a loop.
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 4
|
||||
test "Ensure that the closure wrapper preserves local variables.", ->
|
||||
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
|
||||
|
||||
# Ensure that local variables are closed over for range comprehensions.
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
-> -i
|
||||
test "Index values at the end of a loop.", ->
|
||||
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 4
|
||||
|
||||
|
||||
# Even when referenced in the filter.
|
||||
list = ['one', 'two', 'three']
|
||||
test "Ensure that local variables are closed over for range comprehensions.", ->
|
||||
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
# Even a convoluted one.
|
||||
funcs = []
|
||||
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
||||
# Naked ranges are expanded into arrays.
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Nested shared scopes.
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
-> -i
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
|
||||
|
||||
# Scoped loop pattern matching.
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
test "Even when referenced in the filter.", ->
|
||||
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
# Nested comprehensions.
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
test "Even a convoluted one.", ->
|
||||
|
||||
singleLiner =
|
||||
(([x, y] for y in [3..5]) for x in [3..5])
|
||||
funcs = []
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
ok 5 is multiLiner[2][2][1]
|
||||
ok 5 is singleLiner[2][2][1]
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
||||
# Comprehensions within parentheses.
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
test "Naked ranges are expanded into arrays.", ->
|
||||
|
||||
ok result.join(' ') is '6 4 2'
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Closure-wrapped comprehensions that refer to the "arguments" object.
|
||||
expr = ->
|
||||
result = (item * item for item in arguments)
|
||||
test "Nested shared scopes.", ->
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Fast object comprehensions over all properties, including prototypal ones.
|
||||
class Cat
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
test "Scoped loop pattern matching.", ->
|
||||
|
||||
whiskers = new Cat
|
||||
own = (value for own key, value of whiskers)
|
||||
all = (value for key, value of whiskers)
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
|
||||
|
||||
# Optimized range comprehensions.
|
||||
exxes = ('x' for [0...10])
|
||||
ok exxes.join(' ') is 'x x x x x x x x x x'
|
||||
test "Nested comprehensions.", ->
|
||||
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
|
||||
singleLiner =
|
||||
(([x, y] for y in [3..5]) for x in [3..5])
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
ok 5 is multiLiner[2][2][1]
|
||||
ok 5 is singleLiner[2][2][1]
|
||||
|
||||
|
||||
# Comprehensions safely redeclare parameters if they're not present in closest
|
||||
# scope.
|
||||
rule = (x) -> x
|
||||
test "Comprehensions within parentheses.", ->
|
||||
|
||||
learn = ->
|
||||
rule for rule in [1, 2, 3]
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
|
||||
ok learn().join(' ') is '1 2 3'
|
||||
|
||||
ok rule(101) is 101
|
||||
|
||||
f = -> [-> ok no, 'should cache source']
|
||||
ok yes for k of [f] = f()
|
||||
ok result.join(' ') is '6 4 2'
|
||||
|
||||
|
||||
# Lenient on pure statements not trying to reach out of the closure
|
||||
val = for i in [1]
|
||||
for j in [] then break
|
||||
i
|
||||
ok val[0] is i
|
||||
test "Closure-wrapped comprehensions that refer to the 'arguments' object.", ->
|
||||
|
||||
expr = ->
|
||||
result = (item * item for item in arguments)
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
|
||||
|
||||
# Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
# to have pure expressions in them.
|
||||
func = -> for i in [1]
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
test "Fast object comprehensions over all properties, including prototypal ones.", ->
|
||||
|
||||
ok func()[0][0] is 1
|
||||
class Cat
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
whiskers = new Cat
|
||||
own = (value for own key, value of whiskers)
|
||||
all = (value for key, value of whiskers)
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
|
||||
|
||||
# Issue #897: Ensure that plucked function variables aren't leaked.
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
test "Optimized range comprehensions.", ->
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
exxes = ('x' for [0...10])
|
||||
ok exxes.join(' ') is 'x x x x x x x x x x'
|
||||
|
||||
|
||||
# Issue #905. Soaks as the for loop subject.
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
test "Comprehensions safely redeclare parameters if they're not present in closest scope.", ->
|
||||
|
||||
eq e, 3
|
||||
rule = (x) -> x
|
||||
|
||||
learn = ->
|
||||
rule for rule in [1, 2, 3]
|
||||
|
||||
ok learn().join(' ') is '1 2 3'
|
||||
|
||||
ok rule(101) is 101
|
||||
|
||||
f = -> [-> ok no, 'should cache source']
|
||||
ok yes for k of [f] = f()
|
||||
|
||||
|
||||
# Issue #948. Capturing loop variables.
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
test "Lenient on pure statements not trying to reach out of the closure", ->
|
||||
|
||||
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"
|
||||
val = for i in [1]
|
||||
for j in [] then break
|
||||
i
|
||||
ok val[0] is i
|
||||
|
||||
|
||||
# Cancel the comprehension if there's a jump inside the loop.
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
test "Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
to have pure expressions in them.", ->
|
||||
|
||||
eq result, 10
|
||||
func = -> for i in [1]
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
|
||||
ok func()[0][0] is 1
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
|
||||
|
||||
# Comprehensions over break.
|
||||
arrayEq (break for [1..10]), []
|
||||
test "Issue #897: Ensure that plucked function variables aren't leaked.", ->
|
||||
|
||||
# Comprehensions over continue.
|
||||
arrayEq (break for [1..10]), []
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
||||
|
||||
# Comprehensions over function literals.
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
test "Issue #905. Soaks as the for loop subject.", ->
|
||||
|
||||
eq a, 1
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
|
||||
eq e, 3
|
||||
|
||||
|
||||
# Comprehensions that mention arguments.
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
eq args[0], 10
|
||||
test "Issue #948. Capturing loop variables.", ->
|
||||
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
|
||||
|
||||
test "Cancel the comprehension if there's a jump inside the loop.", ->
|
||||
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
|
||||
eq result, 10
|
||||
|
||||
|
||||
test "Comprehensions over break.", ->
|
||||
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
|
||||
test "Comprehensions over continue.", ->
|
||||
|
||||
arrayEq (continue for [1..10]), []
|
||||
|
||||
|
||||
test "Comprehensions over function literals.", ->
|
||||
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
|
||||
eq a, 1
|
||||
|
||||
|
||||
test "Comprehensions that mention arguments.", ->
|
||||
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
eq args[0], 10
|
||||
|
||||
|
||||
test "expression conversion under explicit returns", ->
|
||||
@@ -341,8 +375,6 @@ test "expression conversion under explicit returns", ->
|
||||
arrayEq [nonce,nonce,nonce], fn()
|
||||
|
||||
|
||||
#### Implicit Destructuring Assignment
|
||||
|
||||
test "implicit destructuring assignment in object of objects", ->
|
||||
a={}; b={}; c={}
|
||||
obj = {
|
||||
@@ -353,6 +385,7 @@ test "implicit destructuring assignment in object of objects", ->
|
||||
result = ([y,z] for y, { d: z } of obj)
|
||||
arrayEq [['a',a],['b',b],['c',c]], result
|
||||
|
||||
|
||||
test "implicit destructuring assignment in array of objects", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}
|
||||
arr = [
|
||||
@@ -363,8 +396,35 @@ test "implicit destructuring assignment in array of objects", ->
|
||||
result = ([y,z] for { a: y, b: { c: z } } in arr)
|
||||
arrayEq [[a,b],[c,d],[e,f]], result
|
||||
|
||||
|
||||
test "implicit destructuring assignment in array of arrays", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}
|
||||
arr = [[a, [b]], [c, [d]], [e, [f]]]
|
||||
result = ([y,z] for [y, [z]] in arr)
|
||||
arrayEq [[a,b],[c,d],[e,f]], result
|
||||
|
||||
test "issue #1124: don't assign a variable in two scopes", ->
|
||||
lista = [1, 2, 3, 4, 5]
|
||||
listb = (_i + 1 for _i in lista)
|
||||
arrayEq [2, 3, 4, 5, 6], listb
|
||||
|
||||
test "#1326: `by` value is uncached", ->
|
||||
a = [0,1,2]
|
||||
fi = gi = hi = 0
|
||||
f = -> ++fi
|
||||
g = -> ++gi
|
||||
h = -> ++hi
|
||||
|
||||
forCompile = []
|
||||
rangeCompileSimple = []
|
||||
|
||||
#exercises For.compile
|
||||
for v,i in a by f() then forCompile.push i
|
||||
|
||||
#exercises Range.compileSimple
|
||||
rangeCompileSimple = (i for i in [0..2] by g())
|
||||
|
||||
arrayEq a, forCompile
|
||||
arrayEq a, rangeCompileSimple
|
||||
#exercises Range.compile
|
||||
eq "#{i for i in [0..2] by h()}", '0,1,2'
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
#### Conditionals
|
||||
# Conditionals
|
||||
|
||||
test "basic conditionals", ->
|
||||
if false
|
||||
@@ -198,38 +198,38 @@ test "#748: trailing reserved identifiers", ->
|
||||
eq nonce, result
|
||||
|
||||
|
||||
#### For / While / Until / Loop
|
||||
test "basic `while` loops", ->
|
||||
|
||||
# TODO: refactor while tests
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
|
||||
# While
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
test "Issue 759: `if` within `while` condition", ->
|
||||
|
||||
2 while if 1 then 0
|
||||
|
||||
#759: `if` within `while` condition
|
||||
2 while if 1 then 0
|
||||
|
||||
test "assignment inside the condition of a `while` loop", ->
|
||||
|
||||
nonce = {}
|
||||
count = 1
|
||||
a = nonce while count--
|
||||
@@ -239,47 +239,45 @@ test "assignment inside the condition of a `while` loop", ->
|
||||
b = nonce
|
||||
eq nonce, b
|
||||
|
||||
# While over break.
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
break
|
||||
arrayEq result, []
|
||||
|
||||
# While over continue.
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
continue
|
||||
arrayEq result, []
|
||||
test "While over break.", ->
|
||||
|
||||
# Until
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
break
|
||||
arrayEq result, []
|
||||
|
||||
# TODO: refactor until tests
|
||||
# TODO: add until tests
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i++
|
||||
ok i is 6
|
||||
test "While over continue.", ->
|
||||
|
||||
# Loop
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
continue
|
||||
arrayEq result, []
|
||||
|
||||
# TODO: refactor loop tests
|
||||
# TODO: add loop tests
|
||||
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
test "Basic `until`", ->
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i++
|
||||
ok i is 6
|
||||
|
||||
|
||||
test "Basic `loop`", ->
|
||||
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
|
||||
# TODO: refactor for tests
|
||||
# TODO: add for tests
|
||||
|
||||
test "break at the top level", ->
|
||||
for i in [1,2,3]
|
||||
@@ -289,7 +287,7 @@ test "break at the top level", ->
|
||||
eq 2, result
|
||||
|
||||
test "break *not* at the top level", ->
|
||||
someFunc = () ->
|
||||
someFunc = ->
|
||||
i = 0
|
||||
while ++i < 3
|
||||
result = i
|
||||
@@ -298,121 +296,125 @@ test "break *not* at the top level", ->
|
||||
eq 2, someFunc()
|
||||
|
||||
|
||||
#### Switch
|
||||
test "basic `switch`", ->
|
||||
|
||||
# TODO: refactor switch tests
|
||||
|
||||
num = 10
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
false
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
num = 10
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
when 1, 3, 5
|
||||
false
|
||||
|
||||
ok func(2)
|
||||
ok func(6)
|
||||
ok !func(3)
|
||||
eq func(8), undefined
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Ensure that trailing switch elses don't get rewritten.
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to handle switches sans-condition.
|
||||
result = switch
|
||||
when null then 0
|
||||
when !1 then 1
|
||||
when '' not of {''} then 2
|
||||
when [] not instanceof Array then 3
|
||||
when true is false then 4
|
||||
when 'x' < 'y' > 'z' then 5
|
||||
when 'a' in ['b', 'c'] then 6
|
||||
when 'd' in (['e', 'f']) then 7
|
||||
else ok
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
true
|
||||
when 1, 3, 5
|
||||
false
|
||||
|
||||
eq result, ok
|
||||
ok func(2)
|
||||
ok func(6)
|
||||
ok !func(3)
|
||||
eq func(8), undefined
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch clause.
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
when 101 then '101!'
|
||||
else 'other'
|
||||
}
|
||||
test "Ensure that trailing switch elses don't get rewritten.", ->
|
||||
|
||||
ok obj.func() is '101!'
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch cases.
|
||||
obj = {
|
||||
num: 101
|
||||
func: (yesOrNo) ->
|
||||
result = switch yesOrNo
|
||||
when yes then @num
|
||||
else 'other'
|
||||
result
|
||||
}
|
||||
test "Should be able to handle switches sans-condition.", ->
|
||||
|
||||
ok obj.func(yes) is 101
|
||||
result = switch
|
||||
when null then 0
|
||||
when !1 then 1
|
||||
when '' not of {''} then 2
|
||||
when [] not instanceof Array then 3
|
||||
when true is false then 4
|
||||
when 'x' < 'y' > 'z' then 5
|
||||
when 'a' in ['b', 'c'] then 6
|
||||
when 'd' in (['e', 'f']) then 7
|
||||
else ok
|
||||
|
||||
eq result, ok
|
||||
|
||||
|
||||
# Switch with break as the return value of a loop.
|
||||
i = 10
|
||||
results = while i > 0
|
||||
i--
|
||||
switch i % 2
|
||||
when 1 then i
|
||||
when 0 then break
|
||||
test "Should be able to use `@properties` within the switch clause.", ->
|
||||
|
||||
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
when 101 then '101!'
|
||||
else 'other'
|
||||
}
|
||||
|
||||
ok obj.func() is '101!'
|
||||
|
||||
|
||||
# Issue #997. Switch doesn't fallthrough.
|
||||
val = 1
|
||||
switch true
|
||||
when true
|
||||
if false
|
||||
return 5
|
||||
else
|
||||
val = 2
|
||||
test "Should be able to use `@properties` within the switch cases.", ->
|
||||
|
||||
eq val, 1
|
||||
obj = {
|
||||
num: 101
|
||||
func: (yesOrNo) ->
|
||||
result = switch yesOrNo
|
||||
when yes then @num
|
||||
else 'other'
|
||||
result
|
||||
}
|
||||
|
||||
ok obj.func(yes) is 101
|
||||
|
||||
|
||||
test "Switch with break as the return value of a loop.", ->
|
||||
|
||||
i = 10
|
||||
results = while i > 0
|
||||
i--
|
||||
switch i % 2
|
||||
when 1 then i
|
||||
when 0 then break
|
||||
|
||||
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
|
||||
|
||||
|
||||
test "Issue #997. Switch doesn't fallthrough.", ->
|
||||
|
||||
val = 1
|
||||
switch true
|
||||
when true
|
||||
if false
|
||||
return 5
|
||||
else
|
||||
val = 2
|
||||
|
||||
eq val, 1
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
nonce = {}
|
||||
|
||||
|
||||
#### Throw
|
||||
# Throw
|
||||
|
||||
test "basic exception throwing", ->
|
||||
throws (-> throw 'error'), 'error'
|
||||
|
||||
|
||||
#### Empty Try/Catch/Finally
|
||||
# Empty Try/Catch/Finally
|
||||
|
||||
test "try can exist alone", ->
|
||||
try
|
||||
@@ -43,7 +43,7 @@ test "single-line try/catch/finally with empty try, empty catch, empty finally",
|
||||
try catch err then finally
|
||||
|
||||
|
||||
#### Try/Catch/Finally as an Expression
|
||||
# Try/Catch/Finally as an Expression
|
||||
|
||||
test "return the result of try when no exception is thrown", ->
|
||||
result = try
|
||||
@@ -81,7 +81,7 @@ test "optional catch", ->
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
#### Try/Catch/Finally Interaction With Other Constructs
|
||||
# Try/Catch/Finally Interaction With Other Constructs
|
||||
|
||||
test "try/catch with empty catch as last statement in a function body", ->
|
||||
fn = ->
|
||||
|
||||
@@ -21,7 +21,7 @@ test "multiple semicolon-separated statements in parentheticals", ->
|
||||
eq nonce, (1; 2; nonce)
|
||||
eq nonce, (-> return (1; 2; nonce))()
|
||||
|
||||
#### Line Continuation
|
||||
# Line Continuation
|
||||
|
||||
# Property Access
|
||||
|
||||
@@ -73,6 +73,18 @@ test "`?.` and `::` should continue lines", ->
|
||||
#::
|
||||
#?.foo
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile """
|
||||
oh. yes
|
||||
oh?. true
|
||||
oh:: return
|
||||
"""
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile """
|
||||
a?[b..]
|
||||
a?[...b]
|
||||
a?[b..c]
|
||||
"""
|
||||
|
||||
# Array Literals
|
||||
|
||||
test "indented array literals don't trigger whitespace rewriting", ->
|
||||
@@ -104,3 +116,8 @@ test "indented heredoc", ->
|
||||
abc
|
||||
""")
|
||||
eq "abc", result
|
||||
|
||||
# Nested blocks caused by paren unwrapping
|
||||
test "#1492: Nested blocks don't cause double semicolons", ->
|
||||
js = CoffeeScript.compile '(0;0)'
|
||||
eq -1, js.indexOf ';;'
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
# * Explicit Returns
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
id = (_) -> if arguments.length is 1 then _ else [arguments...]
|
||||
|
||||
|
||||
test "basic argument passing", ->
|
||||
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
@@ -18,7 +20,9 @@ test "basic argument passing", ->
|
||||
eq a, (id a)
|
||||
eq c, (id a, b, c)[2]
|
||||
|
||||
|
||||
test "passing arguments on separate lines", ->
|
||||
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
@@ -37,7 +41,9 @@ test "passing arguments on separate lines", ->
|
||||
eq b,
|
||||
(id b)
|
||||
|
||||
|
||||
test "optional parens can be used in a nested fashion", ->
|
||||
|
||||
call = (func) -> func()
|
||||
add = (a,b) -> a + b
|
||||
result = call ->
|
||||
@@ -45,7 +51,9 @@ test "optional parens can be used in a nested fashion", ->
|
||||
add 5, 5
|
||||
ok result is 10
|
||||
|
||||
|
||||
test "hanging commas and semicolons in argument list", ->
|
||||
|
||||
fn = () -> arguments.length
|
||||
eq 2, fn(0,1,)
|
||||
eq 3, fn 0, 1,
|
||||
@@ -58,24 +66,32 @@ test "hanging commas and semicolons in argument list", ->
|
||||
throws -> CoffeeScript.compile "fn(,0)"
|
||||
throws -> CoffeeScript.compile "fn(;0)"
|
||||
|
||||
func = ->
|
||||
return if true
|
||||
eq undefined, func()
|
||||
|
||||
result = ("hello".slice) 3
|
||||
ok result is 'lo'
|
||||
test "function invocation", ->
|
||||
|
||||
# And even with strange things like this:
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
ok result is 25
|
||||
func = ->
|
||||
return if true
|
||||
eq undefined, func()
|
||||
|
||||
# More fun with optional parens.
|
||||
fn = (arg) -> arg
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
result = ("hello".slice) 3
|
||||
ok result is 'lo'
|
||||
|
||||
|
||||
test "And even with strange things like this:", ->
|
||||
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
ok result is 25
|
||||
|
||||
|
||||
test "More fun with optional parens.", ->
|
||||
|
||||
fn = (arg) -> arg
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
test "chained function calls", ->
|
||||
nonce = {}
|
||||
@@ -84,31 +100,39 @@ test "chained function calls", ->
|
||||
eq nonce, identityWrap(identityWrap(nonce))()()
|
||||
eq nonce, (identityWrap identityWrap nonce)()()
|
||||
|
||||
# Multi-blocks with optional parens.
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
# method calls
|
||||
fnId = (fn) -> -> fn.apply this, arguments
|
||||
math = {
|
||||
add: (a, b) -> a + b
|
||||
anonymousAdd: (a, b) -> a + b
|
||||
fastAdd: fnId (a, b) -> a + b
|
||||
}
|
||||
ok math.add(5, 5) is 10
|
||||
ok math.anonymousAdd(10, 10) is 20
|
||||
ok math.fastAdd(20, 20) is 40
|
||||
test "Multi-blocks with optional parens.", ->
|
||||
|
||||
fn = (arg) -> arg
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
|
||||
test "method calls", ->
|
||||
|
||||
fnId = (fn) -> -> fn.apply this, arguments
|
||||
math = {
|
||||
add: (a, b) -> a + b
|
||||
anonymousAdd: (a, b) -> a + b
|
||||
fastAdd: fnId (a, b) -> a + b
|
||||
}
|
||||
ok math.add(5, 5) is 10
|
||||
ok math.anonymousAdd(10, 10) is 20
|
||||
ok math.fastAdd(20, 20) is 40
|
||||
|
||||
|
||||
test "Ensure that functions can have a trailing comma in their argument list", ->
|
||||
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
ok mult(10, (i for i in [1..6])...) is 7200
|
||||
|
||||
# Ensure that functions can have a trailing comma in their argument list
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
ok mult(10, (i for i in [1..6])...) is 7200
|
||||
|
||||
test "`@` and `this` should both be able to invoke a method", ->
|
||||
nonce = {}
|
||||
@@ -118,136 +142,170 @@ test "`@` and `this` should both be able to invoke a method", ->
|
||||
fn.withAt()
|
||||
fn.withThis()
|
||||
|
||||
# Trying an implicit object call with a trailing function.
|
||||
a = null
|
||||
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
|
||||
meth 'apple', b: 1, a: 13, ->
|
||||
'orange'
|
||||
ok a is '13 apple orange'
|
||||
|
||||
# Ensure that empty functions don't return mistaken values.
|
||||
obj =
|
||||
func: (@param, @rest...) ->
|
||||
ok obj.func(101, 102, 103, 104) is undefined
|
||||
ok obj.param is 101
|
||||
ok obj.rest.join(' ') is '102 103 104'
|
||||
test "Trying an implicit object call with a trailing function.", ->
|
||||
|
||||
# Passing multiple functions without paren-wrapping is legal, and should compile.
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
ok result is 20
|
||||
a = null
|
||||
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
|
||||
meth 'apple', b: 1, a: 13, ->
|
||||
'orange'
|
||||
ok a is '13 apple orange'
|
||||
|
||||
# Implicit call with a trailing if statement as a param.
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
# Test more function passing:
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
ok result is 6
|
||||
test "Ensure that empty functions don't return mistaken values.", ->
|
||||
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
ok result is 3
|
||||
obj =
|
||||
func: (@param, @rest...) ->
|
||||
ok obj.func(101, 102, 103, 104) is undefined
|
||||
ok obj.param is 101
|
||||
ok obj.rest.join(' ') is '102 103 104'
|
||||
|
||||
# Chained blocks, with proper indentation levels:
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
arrayEq [3,2,1], counter.results
|
||||
|
||||
# This is a crazy one.
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
ok result.one is 1
|
||||
test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->
|
||||
|
||||
# More paren compilation tests:
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
ok result is 20
|
||||
|
||||
# Test for inline functions with parentheses and implicit calls.
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
ok result is 9
|
||||
|
||||
# Test for calls/parens/multiline-chains.
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
ok result is 1
|
||||
test "Implicit call with a trailing if statement as a param.", ->
|
||||
|
||||
# Test implicit calls in functions in parens:
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
ok result is 10
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
# Ensure that chained calls with indented implicit object literals below are
|
||||
# alright.
|
||||
result = null
|
||||
obj =
|
||||
method: (val) -> this
|
||||
second: (hash) -> result = hash.three
|
||||
obj
|
||||
.method(
|
||||
101
|
||||
).second(
|
||||
one:
|
||||
two: 2
|
||||
three: 3
|
||||
|
||||
test "Test more function passing:", ->
|
||||
|
||||
sum = (one, two) -> one() + two()
|
||||
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
eq result, 3
|
||||
ok result is 6
|
||||
|
||||
# Test newline-supressed call chains with nested functions.
|
||||
obj =
|
||||
call: -> this
|
||||
func = ->
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
ok result is 3
|
||||
|
||||
|
||||
test "Chained blocks, with proper indentation levels:", ->
|
||||
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
arrayEq [3,2,1], counter.results
|
||||
|
||||
|
||||
test "This is a crazy one.", ->
|
||||
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
ok result.one is 1
|
||||
|
||||
|
||||
test "More paren compilation tests:", ->
|
||||
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
|
||||
|
||||
test "Test for inline functions with parentheses and implicit calls.", ->
|
||||
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
ok result is 9
|
||||
|
||||
|
||||
test "Test for calls/parens/multiline-chains.", ->
|
||||
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
ok result is 1
|
||||
|
||||
|
||||
test "Test implicit calls in functions in parens:", ->
|
||||
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
ok result is 10
|
||||
|
||||
|
||||
test "Ensure that chained calls with indented implicit object literals below are alright.", ->
|
||||
|
||||
result = null
|
||||
obj =
|
||||
method: (val) -> this
|
||||
second: (hash) -> result = hash.three
|
||||
obj
|
||||
.call ->
|
||||
one two
|
||||
.call ->
|
||||
three four
|
||||
101
|
||||
eq func(), 101
|
||||
.method(
|
||||
101
|
||||
).second(
|
||||
one:
|
||||
two: 2
|
||||
three: 3
|
||||
)
|
||||
eq result, 3
|
||||
|
||||
# Implicit objects with number arguments.
|
||||
func = (x, y) -> y
|
||||
obj =
|
||||
prop: func "a", 1
|
||||
ok obj.prop is 1
|
||||
|
||||
# Non-spaced unary and binary operators should cause a function call.
|
||||
func = (val) -> val + 1
|
||||
ok (func +5) is 6
|
||||
ok (func -5) is -4
|
||||
test "Test newline-supressed call chains with nested functions.", ->
|
||||
|
||||
# Prefix unary assignment operators are allowed in parenless calls.
|
||||
val = 5
|
||||
ok (func --val) is 5
|
||||
obj =
|
||||
call: -> this
|
||||
func = ->
|
||||
obj
|
||||
.call ->
|
||||
one two
|
||||
.call ->
|
||||
three four
|
||||
101
|
||||
eq func(), 101
|
||||
|
||||
|
||||
test "Implicit objects with number arguments.", ->
|
||||
|
||||
func = (x, y) -> y
|
||||
obj =
|
||||
prop: func "a", 1
|
||||
ok obj.prop is 1
|
||||
|
||||
|
||||
test "Non-spaced unary and binary operators should cause a function call.", ->
|
||||
|
||||
func = (val) -> val + 1
|
||||
ok (func +5) is 6
|
||||
ok (func -5) is -4
|
||||
|
||||
|
||||
test "Prefix unary assignment operators are allowed in parenless calls.", ->
|
||||
|
||||
func = (val) -> val + 1
|
||||
val = 5
|
||||
ok (func --val) is 5
|
||||
|
||||
test "#855: execution context for `func arr...` should be `null`", ->
|
||||
contextTest = -> eq @, global
|
||||
contextTest = -> eq @, if window? then window else global
|
||||
array = []
|
||||
contextTest array
|
||||
contextTest.apply null, array
|
||||
@@ -262,13 +320,19 @@ test "#904: Destructuring function arguments with same-named variables in scope"
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
obj =
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
ok obj[obj.index++].method([]...), 'should cache base value'
|
||||
test "Simple Destructuring function arguments with same-named variables in scope", ->
|
||||
x = 1
|
||||
f = ([x]) -> x
|
||||
eq f([2]), 2
|
||||
eq x, 1
|
||||
|
||||
test "caching base value", ->
|
||||
|
||||
obj =
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
ok obj[obj.index++].method([]...)
|
||||
|
||||
#### Splats in Function Invocations
|
||||
|
||||
test "passing splats to functions", ->
|
||||
arrayEq [0..4], id id [0..4]...
|
||||
@@ -280,33 +344,46 @@ test "passing splats to functions", ->
|
||||
arrayEq [2..6], others
|
||||
eq 7, last
|
||||
|
||||
#894: Splatting against constructor-chained functions.
|
||||
x = null
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
new Foo().bar([101]...)
|
||||
eq x, 101
|
||||
test "splat variables are local to the function", ->
|
||||
outer = "x"
|
||||
clobber = (avar, outer...) -> outer
|
||||
clobber "foo", "bar"
|
||||
eq "x", outer
|
||||
|
||||
# Functions with splats being called with too few arguments.
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
|
||||
# splats with super() within classes.
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
test "Issue 894: Splatting against constructor-chained functions.", ->
|
||||
|
||||
x = null
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
new Foo().bar([101]...)
|
||||
eq x, 101
|
||||
|
||||
|
||||
test "Functions with splats being called with too few arguments.", ->
|
||||
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
|
||||
|
||||
test "splats with super() within classes.", ->
|
||||
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
|
||||
test "#1011: passing a splat to a method of a number", ->
|
||||
eq '1011', 11.toString [2]...
|
||||
@@ -315,12 +392,13 @@ test "#1011: passing a splat to a method of a number", ->
|
||||
eq '1011', (131.0).toString [5]...
|
||||
|
||||
|
||||
#### Implicit Return
|
||||
test "implicit return", ->
|
||||
|
||||
eq ok, new ->
|
||||
ok
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
eq ok, new ->
|
||||
ok
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
test "implicit returns with multiple branches", ->
|
||||
nonce = {}
|
||||
@@ -332,6 +410,7 @@ test "implicit returns with multiple branches", ->
|
||||
nonce
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
test "implicit returns with switches", ->
|
||||
nonce = {}
|
||||
fn = ->
|
||||
@@ -340,6 +419,7 @@ test "implicit returns with switches", ->
|
||||
else return undefined
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
test "preserve context when generating closure wrappers for expression conversions", ->
|
||||
nonce = {}
|
||||
obj =
|
||||
@@ -355,12 +435,74 @@ test "preserve context when generating closure wrappers for expression conversio
|
||||
eq nonce, obj.property
|
||||
|
||||
|
||||
#### Explicit Returns
|
||||
|
||||
test "don't wrap \"pure\" statements in a closure", ->
|
||||
test "don't wrap 'pure' statements in a closure", ->
|
||||
nonce = {}
|
||||
items = [0, 1, 2, 3, nonce, 4, 5]
|
||||
fn = (items) ->
|
||||
for item in items
|
||||
return item if item is nonce
|
||||
eq nonce, fn items
|
||||
|
||||
|
||||
test "usage of `new` is careful about where the invocation parens end up", ->
|
||||
eq 'object', typeof new try Array
|
||||
eq 'object', typeof new do -> ->
|
||||
|
||||
|
||||
test "implicit call against control structures", ->
|
||||
result = null
|
||||
save = (obj) -> result = obj
|
||||
|
||||
save switch id false
|
||||
when true
|
||||
'true'
|
||||
when false
|
||||
'false'
|
||||
|
||||
eq result, 'false'
|
||||
|
||||
save if id false
|
||||
'false'
|
||||
else
|
||||
'true'
|
||||
|
||||
eq result, 'true'
|
||||
|
||||
save unless id false
|
||||
'true'
|
||||
else
|
||||
'false'
|
||||
|
||||
eq result, 'true'
|
||||
|
||||
save try
|
||||
doesnt exist
|
||||
catch error
|
||||
'caught'
|
||||
|
||||
eq result, 'caught'
|
||||
|
||||
save try doesnt(exist) catch error then 'caught2'
|
||||
|
||||
eq result, 'caught2'
|
||||
|
||||
|
||||
test "#1420: things like `(fn() ->)`; there are no words for this one", ->
|
||||
fn = -> (f) -> f()
|
||||
nonce = {}
|
||||
eq nonce, (fn() -> nonce)
|
||||
|
||||
test "#1416: don't omit one 'new' when compiling 'new new'", ->
|
||||
nonce = {}
|
||||
obj = new new -> -> {prop: nonce}
|
||||
eq obj.prop, nonce
|
||||
|
||||
test "#1416: don't omit one 'new' when compiling 'new new fn()()'", ->
|
||||
nonce = {}
|
||||
argNonceA = {}
|
||||
argNonceB = {}
|
||||
fn = (a) -> (b) -> {a, b, prop: nonce}
|
||||
obj = new new fn(argNonceA)(argNonceB)
|
||||
eq obj.prop, nonce
|
||||
eq obj.a, argNonceA
|
||||
eq obj.b, argNonceB
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# * Parameter Destructuring
|
||||
# * Default Parameters
|
||||
|
||||
#### Function Definition
|
||||
# Function Definition
|
||||
|
||||
x = 1
|
||||
y = {}
|
||||
@@ -46,7 +46,7 @@ del = -> 5
|
||||
ok del() is 5
|
||||
|
||||
|
||||
#### Bound Function Definition
|
||||
# Bound Function Definition
|
||||
|
||||
obj =
|
||||
bound: ->
|
||||
@@ -64,7 +64,15 @@ ok obj isnt obj.unbound()
|
||||
eq obj, obj.nested()
|
||||
|
||||
|
||||
#### Parameter List Features
|
||||
test "self-referencing functions", ->
|
||||
changeMe = ->
|
||||
changeMe = 2
|
||||
|
||||
changeMe()
|
||||
eq changeMe, 2
|
||||
|
||||
|
||||
# Parameter List Features
|
||||
|
||||
test "splats", ->
|
||||
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
|
||||
@@ -147,3 +155,11 @@ test "default values with splatted arguments", ->
|
||||
eq 5, withSplats(1,1)
|
||||
eq 1, withSplats(1,1,1)
|
||||
eq 2, withSplats(1,1,1,1)
|
||||
|
||||
test "default values with function calls", ->
|
||||
doesNotThrow -> CoffeeScript.compile "(x = f()) ->"
|
||||
|
||||
test "arguments vs parameters", ->
|
||||
doesNotThrow -> CoffeeScript.compile "f(x) ->"
|
||||
f = (g) -> g()
|
||||
eq 5, f (x) -> 5
|
||||
@@ -5,7 +5,7 @@
|
||||
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
|
||||
|
||||
|
||||
#### `starts`
|
||||
# `starts`
|
||||
|
||||
test "the `starts` helper tests if a string starts with another string", ->
|
||||
ok starts('01234', '012')
|
||||
@@ -16,7 +16,7 @@ test "the `starts` helper can take an optional offset", ->
|
||||
ok not starts('01234', '01', 1)
|
||||
|
||||
|
||||
#### `ends`
|
||||
# `ends`
|
||||
|
||||
test "the `ends` helper tests if a string ends with another string", ->
|
||||
ok ends('01234', '234')
|
||||
@@ -27,7 +27,7 @@ test "the `ends` helper can take an optional offset", ->
|
||||
ok not ends('01234', '234', 6)
|
||||
|
||||
|
||||
#### `compact`
|
||||
# `compact`
|
||||
|
||||
test "the `compact` helper removes falsey values from an array, preserves truthy ones", ->
|
||||
allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true]
|
||||
@@ -35,7 +35,7 @@ test "the `compact` helper removes falsey values from an array, preserves truthy
|
||||
arrayEq truthyValues, compact(allValues)
|
||||
|
||||
|
||||
#### `count`
|
||||
# `count`
|
||||
|
||||
test "the `count` helper counts the number of occurances of a string in another string", ->
|
||||
eq 1/0, count('abc', '')
|
||||
@@ -46,7 +46,7 @@ test "the `count` helper counts the number of occurances of a string in another
|
||||
eq 2, count('abcdabcd','abc')
|
||||
|
||||
|
||||
#### `merge`
|
||||
# `merge`
|
||||
|
||||
test "the `merge` helper makes a new object with all properties of the objects given as its arguments", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
@@ -58,7 +58,7 @@ test "the `merge` helper makes a new object with all properties of the objects g
|
||||
eq val, merged[key]
|
||||
|
||||
|
||||
#### `extend`
|
||||
# `extend`
|
||||
|
||||
test "the `extend` helper performs a shallow copy", ->
|
||||
ary = [0, 1, 2, 3]
|
||||
@@ -69,7 +69,7 @@ test "the `extend` helper performs a shallow copy", ->
|
||||
eq 2, obj[2]
|
||||
|
||||
|
||||
#### `flatten`
|
||||
# `flatten`
|
||||
|
||||
test "the `flatten` helper flattens an array", ->
|
||||
success = yes
|
||||
@@ -77,7 +77,7 @@ test "the `flatten` helper flattens an array", ->
|
||||
ok success
|
||||
|
||||
|
||||
#### `del`
|
||||
# `del`
|
||||
|
||||
test "the `del` helper deletes a property from an object and returns the deleted value", ->
|
||||
obj = [0, 1, 2]
|
||||
@@ -85,7 +85,7 @@ test "the `del` helper deletes a property from an object and returns the deleted
|
||||
ok 1 not of obj
|
||||
|
||||
|
||||
#### `last`
|
||||
# `last`
|
||||
|
||||
test "the `last` helper returns the last item of an array-like object", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# * String Interpolation
|
||||
# * Regular Expression Interpolation
|
||||
|
||||
#### String Interpolation
|
||||
# String Interpolation
|
||||
|
||||
# TODO: refactor string interpolation tests
|
||||
|
||||
@@ -20,6 +20,20 @@ eq "#{ "{" }", "{"
|
||||
eq "#{ '#{}}' } }", '#{}} }'
|
||||
eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'"
|
||||
|
||||
# Issue #1150: String interpolation regression
|
||||
eq "#{'"/'}", '"/'
|
||||
eq "#{"/'"}", "/'"
|
||||
eq "#{/'"/}", '/\'"/'
|
||||
eq "#{"'/" + '/"' + /"'/}", '\'//"/"\'/'
|
||||
eq "#{"'/"}#{'/"'}#{/"'/}", '\'//"/"\'/'
|
||||
eq "#{6 / 2}", '3'
|
||||
eq "#{6 / 2}#{6 / 2}", '33' # parsed as division
|
||||
eq "#{6 + /2}#{6/ + 2}", '6/2}#{6/2' # parsed as a regex
|
||||
eq "#{6/2}
|
||||
#{6/2}", '3 3' # newline cannot be part of a regex, so it's division
|
||||
eq "#{/// "'/'"/" ///}", '/"\'\\/\'"\\/"/' # heregex, stuffed with spicy characters
|
||||
eq "#{/\\'/}", "/\\\\'/"
|
||||
|
||||
hello = 'Hello'
|
||||
world = 'World'
|
||||
ok '#{hello} #{world}!' is '#{hello} #{world}!'
|
||||
@@ -109,7 +123,7 @@ eq 'multiline nested "interpolations" work', """multiline #{
|
||||
} work"""
|
||||
|
||||
|
||||
#### Regular Expression Interpolation
|
||||
# Regular Expression Interpolation
|
||||
|
||||
# TODO: improve heregex interpolation tests
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# * Non-Integer Literals
|
||||
|
||||
|
||||
#### Decimal Integer Literals
|
||||
# Decimal Integer Literals
|
||||
|
||||
test "call methods directly on numbers", ->
|
||||
eq 4, 4.valueOf()
|
||||
@@ -23,7 +23,7 @@ eq Number::toString, 42['toString']
|
||||
eq Number::toString, 42.toString
|
||||
|
||||
|
||||
#### Non-Integer Literals
|
||||
# Non-Integer Literals
|
||||
|
||||
# Decimal number literals.
|
||||
value = .25 + .75
|
||||
@@ -32,8 +32,17 @@ value = 0.0 + -.25 - -.75 + 0.0
|
||||
ok value is 0.5
|
||||
|
||||
#764: Numbers should be indexable
|
||||
eq Number::toString, 4['toString']
|
||||
eq Number::toString, 4.2['toString']
|
||||
eq Number::toString, .42['toString']
|
||||
eq Number::toString, (4)['toString']
|
||||
|
||||
eq Number::toString, 4.toString
|
||||
eq Number::toString, 4.2.toString
|
||||
eq Number::toString, .42.toString
|
||||
eq Number::toString, (4).toString
|
||||
|
||||
test '#1168: leading floating point suppresses newline', ->
|
||||
eq 1, do ->
|
||||
1
|
||||
.5 + 0.5
|
||||
@@ -183,6 +183,22 @@ test "invoking functions with implicit object literals", ->
|
||||
ok result.length is 3
|
||||
ok result[2].c is 1
|
||||
|
||||
result = getA b: 13, a: 42, 2
|
||||
eq 42, result
|
||||
|
||||
result = getArgs a:1, (1 + 1)
|
||||
ok result[1] is 2
|
||||
|
||||
result = getArgs a:1, b
|
||||
ok result.length is 2
|
||||
ok result[1] is 30
|
||||
|
||||
result = getArgs a:1, b, b:1, a
|
||||
ok result.length is 4
|
||||
ok result[2].b is 1
|
||||
|
||||
throws -> CoffeeScript.compile "a = b:1, c"
|
||||
|
||||
test "some weird indentation in YAML-style object literals", ->
|
||||
two = (a, b) -> b
|
||||
obj = then two 1,
|
||||
@@ -193,3 +209,27 @@ test "some weird indentation in YAML-style object literals", ->
|
||||
d: e
|
||||
f: 1
|
||||
eq 1, obj[1]
|
||||
|
||||
test "#1274: `{} = a()` compiles to `false` instead of `a()`", ->
|
||||
a = false
|
||||
fn = -> a = true
|
||||
{} = fn()
|
||||
ok a
|
||||
|
||||
test "#1436: `for` etc. work as normal property names", ->
|
||||
obj = {}
|
||||
eq no, obj.hasOwnProperty 'for'
|
||||
obj.for = 'foo' of obj
|
||||
eq yes, obj.hasOwnProperty 'for'
|
||||
|
||||
test "#1322: implicit call against implicit object with block comments", ->
|
||||
((obj, arg) ->
|
||||
eq obj.x * obj.y, 6
|
||||
ok not arg
|
||||
)
|
||||
###
|
||||
x
|
||||
###
|
||||
x: 2
|
||||
### y ###
|
||||
y: 3
|
||||
@@ -59,7 +59,7 @@ test "use `::` operator on keywords `this` and `@`", ->
|
||||
eq nonce, obj.withThis()
|
||||
|
||||
|
||||
#### Existential Operator (Binary)
|
||||
# Existential Operator (Binary)
|
||||
|
||||
test "binary existential operator", ->
|
||||
nonce = {}
|
||||
@@ -91,7 +91,7 @@ test "binary existential operator with negative number", ->
|
||||
eq -1, a
|
||||
|
||||
|
||||
#### Existential Operator (Unary)
|
||||
# Existential Operator (Unary)
|
||||
|
||||
test "postfix existential operator", ->
|
||||
ok (if nonexistent? then false else true)
|
||||
@@ -114,7 +114,7 @@ test "postfix existential operator on expressions", ->
|
||||
eq true, (1 or 0)?, true
|
||||
|
||||
|
||||
#### `is`,`isnt`,`==`,`!=`
|
||||
# `is`,`isnt`,`==`,`!=`
|
||||
|
||||
test "`==` and `is` should be interchangeable", ->
|
||||
a = b = 1
|
||||
@@ -130,7 +130,7 @@ test "`!=` and `isnt` should be interchangeable", ->
|
||||
ok a isnt b
|
||||
|
||||
|
||||
#### [not] in/of
|
||||
# [not] in/of
|
||||
|
||||
# - `in` should check if an array contains a value using `indexOf`
|
||||
# - `of` should check if a property is defined on an object using `in`
|
||||
@@ -184,8 +184,16 @@ test "#768: `in` should preserve evaluation order", ->
|
||||
ok a() not in [b(),c()]
|
||||
eq 3, share
|
||||
|
||||
test "#1099: empty array after `in` should compile to `false`", ->
|
||||
eq 1, [5 in []].length
|
||||
eq false, do -> return 0 in []
|
||||
|
||||
test "#1354: optimized `in` checks should not happen when splats are present", ->
|
||||
a = [6, 9]
|
||||
eq 9 in [3, a...], true
|
||||
|
||||
#### Chained Comparison
|
||||
|
||||
# Chained Comparison
|
||||
|
||||
test "chainable operators", ->
|
||||
ok 100 > 10 > 1 > 0 > -1
|
||||
|
||||
@@ -83,3 +83,6 @@ test "#1012 slices with arguments object", ->
|
||||
arrayEq expected, argsAtEnd
|
||||
argsAtBoth = (-> [arguments[0]..arguments[1]]) 0, 9
|
||||
arrayEq expected, argsAtBoth
|
||||
|
||||
test "#1409: creating large ranges outside of a function body", ->
|
||||
CoffeeScript.eval '[0..100]'
|
||||
@@ -20,6 +20,10 @@ test "division is not confused for a regular expression", ->
|
||||
g = 1
|
||||
eq 2, a / b/g
|
||||
|
||||
a = 10
|
||||
b = a /= 4 / 2
|
||||
eq a, 5
|
||||
|
||||
obj = method: -> 2
|
||||
two = 2
|
||||
eq 2, (obj.method()/two + obj.method()/two)
|
||||
@@ -35,7 +39,7 @@ test "#584: slashes are allowed unescaped in character classes", ->
|
||||
ok /^a\/[/]b$/.test 'a//b'
|
||||
|
||||
|
||||
#### Heregexe(n|s)
|
||||
# Heregexe(n|s)
|
||||
|
||||
test "a heregex will ignore whitespace and comments", ->
|
||||
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
|
||||
@@ -20,3 +20,15 @@ test "assignment to an Object.prototype-named variable should not leak to outer
|
||||
constructor = 'word'
|
||||
)()
|
||||
ok constructor isnt 'word'
|
||||
|
||||
test "siblings of splat parameters shouldn't leak to surrounding scope", ->
|
||||
x = 10
|
||||
oops = (x, args...) ->
|
||||
oops(20, 1, 2, 3)
|
||||
eq x, 10
|
||||
|
||||
test "catch statements should introduce their argument to scope", ->
|
||||
try throw ''
|
||||
catch e
|
||||
do -> e = 5
|
||||
eq 5, e
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# shared array
|
||||
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
#### Slicing
|
||||
# Slicing
|
||||
|
||||
test "basic slicing", ->
|
||||
arrayEq [7, 8, 9] , shared[7..9]
|
||||
@@ -53,7 +53,7 @@ test "string slicing", ->
|
||||
ok str[-5..] is "vwxyz"
|
||||
|
||||
|
||||
#### Splicing
|
||||
# Splicing
|
||||
|
||||
test "basic splicing", ->
|
||||
ary = [0..9]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# * Soaked Function Invocation
|
||||
|
||||
|
||||
#### Soaked Property Access
|
||||
# Soaked Property Access
|
||||
|
||||
test "soaked property access", ->
|
||||
nonce = {}
|
||||
@@ -73,7 +73,7 @@ test "operations on soaked properties", ->
|
||||
eq yes, delete a?.b.c
|
||||
|
||||
|
||||
#### Soaked Method Invocation
|
||||
# Soaked Method Invocation
|
||||
|
||||
test "soaked method invocation", ->
|
||||
nonce = {}
|
||||
@@ -96,7 +96,7 @@ test "#733", ->
|
||||
eq a.b?.c?([2, 3]...), 2
|
||||
|
||||
|
||||
#### Soaked Function Invocation
|
||||
# Soaked Function Invocation
|
||||
|
||||
test "soaked function invocation", ->
|
||||
nonce = {}
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
start = new Date
|
||||
success = total = done = failed = 0
|
||||
|
||||
say = (msg, yay) ->
|
||||
say = (msg) ->
|
||||
div = document.createElement 'div'
|
||||
div.appendChild document.createTextNode msg
|
||||
div.style.color = if yay then 'green' else 'red'
|
||||
stdout.appendChild div
|
||||
msg
|
||||
|
||||
@@ -72,16 +71,9 @@
|
||||
return
|
||||
ok no
|
||||
|
||||
|
||||
CoffeeScript.run = (code, cb) ->
|
||||
try Function(CoffeeScript.compile code, wrap: no)()
|
||||
catch e then cb(); throw e
|
||||
cb yes
|
||||
|
||||
run = (name) ->
|
||||
CoffeeScript.load "#{name}.coffee", (yay) ->
|
||||
say "#{ if yay then '\u2714' else '\u3000' } #{name}", yay
|
||||
++failed unless yay
|
||||
CoffeeScript.load "#{name}.coffee", ->
|
||||
say '\u2714 ' + name
|
||||
fin() if ++done is names.length
|
||||
|
||||
fin = ->
|
||||
@@ -92,12 +84,10 @@
|
||||
say msg, yay
|
||||
|
||||
run name for name in names = [
|
||||
'array_literals'
|
||||
'arrays'
|
||||
'assignment'
|
||||
'boolean_literals'
|
||||
'cake'
|
||||
'booleans'
|
||||
'classes'
|
||||
'command'
|
||||
'comments'
|
||||
'compilation'
|
||||
'comprehensions'
|
||||
@@ -105,22 +95,22 @@
|
||||
'exception_handling'
|
||||
'formatting'
|
||||
'function_invocation'
|
||||
'function_literals'
|
||||
'functions'
|
||||
'helpers'
|
||||
'importing'
|
||||
'interpolation'
|
||||
'javascript_literals'
|
||||
'number_literals'
|
||||
'object_literals'
|
||||
'numbers'
|
||||
'objects'
|
||||
'operators'
|
||||
'option_parser'
|
||||
'range_literals'
|
||||
'regular_expression_literals'
|
||||
'ranges'
|
||||
'regexps'
|
||||
'repl'
|
||||
'scope'
|
||||
'slicing_and_splicing'
|
||||
'soaks'
|
||||
'string_literals'
|
||||
'strings'
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user