mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 09:17:55 -05:00
Compare commits
205 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
c44d9ae923 | ||
|
|
a487259e8e | ||
|
|
37308e6760 | ||
|
|
4ce374be25 | ||
|
|
8b8e8a94ff | ||
|
|
3c9fdde24b | ||
|
|
578a46fbda | ||
|
|
6fb2088d5f | ||
|
|
49d9eb687d | ||
|
|
654c933e30 | ||
|
|
83a86aacb5 | ||
|
|
f231809e22 | ||
|
|
2c8e0a6914 | ||
|
|
496816acff | ||
|
|
78b52f5716 | ||
|
|
2ca108820f | ||
|
|
dc6bd715b2 | ||
|
|
18a1e01d64 | ||
|
|
15e1078d01 | ||
|
|
06b0c7e928 | ||
|
|
3924c2f2bd | ||
|
|
7625d900d3 | ||
|
|
53dc1f2055 | ||
|
|
e706fa4a58 | ||
|
|
65e81e4034 | ||
|
|
1f2f55bea3 | ||
|
|
4b78790096 | ||
|
|
236e129e7a | ||
|
|
d200619774 | ||
|
|
f35ea486a7 | ||
|
|
a48cd7cb1d | ||
|
|
d0f13223bc | ||
|
|
7ae284f432 | ||
|
|
df872b8223 | ||
|
|
150a8a12a0 | ||
|
|
d8823ed45e | ||
|
|
9a63b3147f | ||
|
|
3f586ff4ab | ||
|
|
c4d4cfe9dc | ||
|
|
08cd112585 | ||
|
|
566087b518 | ||
|
|
f4a7cca075 | ||
|
|
d9d50fdf54 | ||
|
|
4c18ddf549 | ||
|
|
7c7b9a4be1 | ||
|
|
9faedbf516 | ||
|
|
ba45dedbd5 | ||
|
|
7815138386 | ||
|
|
47e4f4dae1 | ||
|
|
9b3197c6e8 | ||
|
|
44355f8eef | ||
|
|
45058dfa79 | ||
|
|
83f9cb88cf | ||
|
|
c851ed9d60 | ||
|
|
5f19f65ef2 | ||
|
|
8ca8cd046f | ||
|
|
6832dda2fa | ||
|
|
782bc6c03a | ||
|
|
b158f1cbe6 | ||
|
|
944a114400 | ||
|
|
5a7120e163 | ||
|
|
1f58232e87 | ||
|
|
0d3827989d | ||
|
|
07ff3020cf | ||
|
|
af4748d92b | ||
|
|
240a0b9c93 | ||
|
|
6421c865f5 | ||
|
|
06de5c7ffe | ||
|
|
ccae9ea6a8 | ||
|
|
8692a5fd06 | ||
|
|
dcbe62b9b9 | ||
|
|
9bed99482a | ||
|
|
fb201976b8 | ||
|
|
bb745a8036 | ||
|
|
a330eda4b6 | ||
|
|
dcfdd144d8 | ||
|
|
0fd3ed593c | ||
|
|
83d424f2f4 | ||
|
|
c16c90c00a | ||
|
|
8087a5914c | ||
|
|
03eccd4958 | ||
|
|
6d3f272551 | ||
|
|
7ffb7c19fd | ||
|
|
f545f18c2d |
31
Cakefile
31
Cakefile
@@ -16,7 +16,7 @@ header = """
|
||||
* CoffeeScript Compiler v#{CoffeeScript.VERSION}
|
||||
* http://coffeescript.org
|
||||
*
|
||||
* Copyright 2010, Jeremy Ashkenas
|
||||
* Copyright 2011, Jeremy Ashkenas
|
||||
* Released under the MIT License
|
||||
*/
|
||||
"""
|
||||
@@ -50,10 +50,10 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||
exec([
|
||||
"mkdir -p #{lib} #{bin}"
|
||||
"cp -rf bin lib LICENSE README package.json src #{lib}"
|
||||
"ln -sf #{lib}/bin/coffee #{bin}/coffee"
|
||||
"ln -sf #{lib}/bin/cake #{bin}/cake"
|
||||
"ln -sfn #{lib}/bin/coffee #{bin}/coffee"
|
||||
"ln -sfn #{lib}/bin/cake #{bin}/cake"
|
||||
"mkdir -p ~/.node_libraries"
|
||||
"ln -sf #{lib}/lib #{node}"
|
||||
"ln -sfn #{lib}/lib #{node}"
|
||||
].join(' && '), (err, stdout, stderr) ->
|
||||
if err then console.log stderr.trim() else log 'done', green
|
||||
)
|
||||
@@ -94,16 +94,18 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
||||
#{fs.readFileSync "lib/#{name}.js"}
|
||||
};
|
||||
"""
|
||||
{parser, uglify} = require 'uglify-js'
|
||||
ast = parser.parse """
|
||||
code = """
|
||||
this.CoffeeScript = function() {
|
||||
function require(path){ return require[path]; }
|
||||
#{code}
|
||||
return require['./coffee-script']
|
||||
}()
|
||||
"""
|
||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle ast, extra: yes
|
||||
unless process.env.MINIFY is 'false'
|
||||
{parser, uglify} = require 'uglify-js'
|
||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code
|
||||
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
|
||||
console.log "built ... running browser tests:"
|
||||
invoke 'test:browser'
|
||||
|
||||
|
||||
@@ -150,6 +152,9 @@ runTests = (CoffeeScript) ->
|
||||
passedTests = 0
|
||||
failures = []
|
||||
|
||||
# make "global" reference available to tests
|
||||
global.global = global
|
||||
|
||||
# Mix in the assert module globally, to make it available for tests.
|
||||
addGlobal = (name, func) ->
|
||||
global[name] = ->
|
||||
@@ -165,7 +170,8 @@ runTests = (CoffeeScript) ->
|
||||
# Our test helper function for delimiting different test cases.
|
||||
global.test = (description, fn) ->
|
||||
try
|
||||
fn()
|
||||
fn.test = {description, currentFile}
|
||||
fn.call(fn)
|
||||
catch e
|
||||
e.description = description if description?
|
||||
e.source = fn.toString() if fn.toString?
|
||||
@@ -198,6 +204,7 @@ runTests = (CoffeeScript) ->
|
||||
{error, file} = fail
|
||||
jsFile = file.replace(/\.coffee$/,'.js')
|
||||
match = error.stack?.match(new RegExp(fail.file+":(\\d+):(\\d+)"))
|
||||
match = error.stack?.match(/on line (\d+):/) unless match
|
||||
[match, line, col] = match if match
|
||||
log "\n #{error.toString()}", red
|
||||
log " #{error.description}", red if error.description
|
||||
@@ -208,11 +215,11 @@ runTests = (CoffeeScript) ->
|
||||
fs.readdir 'test', (err, files) ->
|
||||
files.forEach (file) ->
|
||||
return unless file.match(/\.coffee$/i)
|
||||
fileName = path.join 'test', file
|
||||
fs.readFile fileName, (err, code) ->
|
||||
currentFile = fileName
|
||||
filename = path.join 'test', file
|
||||
fs.readFile filename, (err, code) ->
|
||||
currentFile = filename
|
||||
try
|
||||
CoffeeScript.run code.toString(), {fileName}
|
||||
CoffeeScript.run code.toString(), {filename}
|
||||
catch e
|
||||
failures.push file: currentFile, error: e
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2010 Jeremy Ashkenas
|
||||
Copyright (c) 2011 Jeremy Ashkenas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
||||
3
README
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
###
|
||||
CoffeeScript Compiler v1.0.0
|
||||
CoffeeScript Compiler v1.1.0
|
||||
Released under the MIT License
|
||||
###
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
for fileName in list
|
||||
do (fileName) ->
|
||||
fs.readFile fileName, (err, contents) ->
|
||||
compile fileName, contents.toString()
|
||||
for filename in list
|
||||
do (filename) ->
|
||||
fs.readFile filename, (err, contents) ->
|
||||
compile filename, contents.toString()
|
||||
@@ -45,6 +45,7 @@ table {
|
||||
}
|
||||
td {
|
||||
padding: 9px 15px 9px 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
table.definitions {
|
||||
width: auto;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -25,7 +25,7 @@ If no tasks are passed, print the help screen.</p> </td>
|
||||
<span class="nx">path</span><span class="p">.</span><span class="nx">exists</span> <span class="s1">'Cakefile'</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">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">"Cakefile not found in #{process.cwd()}"</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">exists</span>
|
||||
<span class="nv">args = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">2</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s1">'Cakefile'</span><span class="p">).</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">fileName</span><span class="o">:</span> <span class="s1">'Cakefile'</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">run</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s1">'Cakefile'</span><span class="p">).</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">filename</span><span class="o">:</span> <span class="s1">'Cakefile'</span>
|
||||
<span class="nv">oparse = </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">switches</span>
|
||||
<span class="k">return</span> <span class="nx">printTasks</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">options = </span><span class="nx">oparse</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span>
|
||||
|
||||
@@ -6,18 +6,19 @@ source CoffeeScript into JavaScript.</p>
|
||||
<p>If included on a webpage, it will automatically sniff out, compile, and
|
||||
execute all scripts present in <code>text/coffeescript</code> tags.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">fs = </span><span class="nx">require</span> <span class="s1">'fs'</span>
|
||||
<span class="nv">path = </span><span class="nx">require</span> <span class="s1">'path'</span>
|
||||
<span class="nv">vm = </span><span class="nx">require</span> <span class="s1">'vm'</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.0'</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.0'</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>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nv">err.message = </span><span class="s2">"In #{options.fileName}, #{err.message}"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span>
|
||||
<span class="nv">err.message = </span><span class="s2">"In #{options.filename}, #{err.message}"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.tokens = </span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">lexer</span><span class="p">.</span><span class="nx">tokenize</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Parse a string of CoffeeScript code or an array of lexed tokens, and
|
||||
return the AST. You can then compile it by calling <code>.compile()</code> on the root,
|
||||
@@ -28,14 +29,26 @@ or traverse it by using <code>.traverse()</code> with a callback.</p>
|
||||
<span class="nx">parser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">source</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</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="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span> <span class="nx">options</span><span class="p">.</span><span class="nx">fileName</span> <span class="o">or</span> <span class="s1">'.'</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="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="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-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>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">root.paths = </span><span class="nx">Module</span><span class="p">.</span><span class="nx">_nodeModulePaths</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</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>
|
||||
<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 = </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">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</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="nv">sandbox = </span><span class="nx">options</span><span class="p">.</span><span class="nx">sandbox</span>
|
||||
<span class="nx">unless</span> <span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox =</span>
|
||||
<span class="nx">require</span><span class="o">:</span> <span class="nx">require</span>
|
||||
<span class="nx">module</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">exports</span><span class="o">:</span> <span class="p">{}</span> <span class="p">}</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">of</span> <span class="nx">global</span>
|
||||
<span class="nv">sandbox.global = </span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.__filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="o">||</span> <span class="s1">'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>
|
||||
<span class="nv">js = </span><span class="nx">compile</span> <span class="s2">"_=(#{code.trim()})"</span><span class="p">,</span> <span class="nx">options</span>
|
||||
<span class="nx">vm</span><span class="p">.</span><span class="nx">runInNewContext</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">sandbox</span><span class="p">,</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">__filename</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Instantiate a Lexer for our use here.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lexer = </span><span class="k">new</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</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>
|
||||
|
||||
@@ -4,7 +4,6 @@ into various forms: saved into <code>.js</code> files or printed to stdout, pipe
|
||||
saved, printed as a token stream or as the syntax tree, or launch an
|
||||
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</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>
|
||||
<span class="nv">util = </span><span class="nx">require</span> <span class="s1">'util'</span>
|
||||
<span class="nv">helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span>
|
||||
<span class="nv">optparse = </span><span class="nx">require</span> <span class="s1">'./optparse'</span>
|
||||
<span class="nv">CoffeeScript = </span><span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
@@ -18,7 +17,7 @@ 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>
|
||||
@@ -41,6 +40,7 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<span class="k">return</span> <span class="nx">forkNode</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span>
|
||||
<span class="k">return</span> <span class="nx">usage</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">help</span>
|
||||
<span class="k">return</span> <span class="nx">version</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">version</span>
|
||||
<span class="nx">loadRequires</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="k">return</span> <span class="nx">require</span> <span class="s1">'./repl'</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">interactive</span>
|
||||
<span class="k">return</span> <span class="nx">compileStdio</span><span class="p">()</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">stdio</span>
|
||||
<span class="k">return</span> <span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nb">eval</span>
|
||||
@@ -48,6 +48,8 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">run</span>
|
||||
<span class="nv">opts.literals = </span><span class="nx">sources</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
|
||||
<span class="nv">process.ARGV = process.argv = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="nx">concat</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">literals</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'coffee'</span>
|
||||
<span class="nv">process.execPath = </span><span class="nx">process</span><span class="p">.</span><span class="nx">mainModule</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nx">compileScripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</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>
|
||||
@@ -55,8 +57,9 @@ compile them. If a directory is passed, recursively compile all
|
||||
<span class="nv">base = </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span>
|
||||
<span class="nv">compile = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">topLevel</span><span class="p">)</span> <span class="o">-></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">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"File not found: #{source}"</span> <span class="nx">unless</span> <span class="nx">exists</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s2">"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">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span>
|
||||
@@ -65,7 +68,7 @@ compile them. If a directory is passed, recursively compile all
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
<span class="nx">contents</span><span class="p">[</span><span class="nx">sources</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">source</span><span class="p">]</span> <span class="o">=</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span> <span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span><span class="p">(</span><span class="nx">contents</span><span class="p">).</span><span class="nx">length</span> <span class="o">is</span> <span class="nx">sources</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">compileJoin</span><span class="p">()</span> <span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span><span class="p">(</span><span class="nx">contents</span><span class="p">).</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span>
|
||||
@@ -74,8 +77,6 @@ requested options. If evaluating the script directly sets <code>__filename</code
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script's path.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileScript = </span><span class="p">(</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o = </span><span class="nx">opts</span>
|
||||
<span class="nv">options = </span><span class="nx">compileOptions</span> <span class="nx">file</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="nx">require</span><span class="p">(</span><span class="k">if</span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">starts</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="s1">'.'</span><span class="p">)</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="k">else</span> <span class="nx">req</span><span class="p">)</span> <span class="k">for</span> <span class="nx">req</span> <span class="k">in</span> <span class="nx">o</span><span class="p">.</span><span class="nx">require</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">t = task = </span><span class="p">{</span><span class="nx">file</span><span class="p">,</span> <span class="nx">input</span><span class="p">,</span> <span class="nx">options</span><span class="p">}</span>
|
||||
<span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">emit</span> <span class="s1">'compile'</span><span class="p">,</span> <span class="nx">task</span>
|
||||
@@ -103,14 +104,18 @@ and write them back to <strong>stdout</strong>.</p> </td>
|
||||
<span class="nx">compileScript</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</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>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
|
||||
<span class="nx">compileScript</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">join</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</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>
|
||||
<span class="nv">module.filename = </span><span class="nx">realFilename</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Watch a source CoffeeScript file using <code>fs.watchFile</code>, recompiling it every
|
||||
time the file is updated. May be used in combination with other options,
|
||||
such as <code>--lint</code> or <code>--print</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">watch = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">watchFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">{</span><span class="nx">persistent</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">interval</span><span class="o">:</span> <span class="mi">500</span><span class="p">},</span> <span class="p">(</span><span class="nx">curr</span><span class="p">,</span> <span class="nx">prev</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">curr</span><span class="p">.</span><span class="nx">size</span> <span class="o">is</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">size</span> <span class="o">and</span> <span class="nx">curr</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span> <span class="o">is</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">mtime</span><span class="p">.</span><span class="nx">getTime</span><span class="p">()</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">throw</span> <span class="nx">err</span> <span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
<span class="nx">compileScript</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
are written out in <code>cwd</code> as <code>.js</code> files with the same name, but the output
|
||||
directory can be customized with <code>--output</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">writeJs = </span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="nx">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">filename = </span><span class="nx">path</span><span class="p">.</span><span class="nx">basename</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">))</span> <span class="o">+</span> <span class="s1">'.js'</span>
|
||||
@@ -121,10 +126,12 @@ directory can be customized with <code>--output</code>.</p> </td>
|
||||
<span class="nv">compile = </span><span class="o">-></span>
|
||||
<span class="nv">js = </span><span class="s1">' '</span> <span class="k">if</span> <span class="nx">js</span><span class="p">.</span><span class="nx">length</span> <span class="o"><=</span> <span class="mi">0</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">jsPath</span><span class="p">,</span> <span class="nx">js</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">err</span> <span class="k">then</span> <span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">util</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"compiled #{source}"</span>
|
||||
<span class="k">if</span> <span class="nx">err</span>
|
||||
<span class="nx">printLine</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">compile</span> <span class="o">and</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span> <span class="s2">"#{(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-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
|
||||
<span class="k">if</span> <span class="nx">exists</span> <span class="k">then</span> <span class="nx">compile</span><span class="p">()</span> <span class="k">else</span> <span class="nx">exec</span> <span class="s2">"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>
|
||||
<span class="nv">printIt = </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">printLine</span> <span class="nx">file</span> <span class="o">+</span> <span class="s1">':\t'</span> <span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">trim</span><span class="p">()</span>
|
||||
<span class="nv">conf = </span><span class="nx">__dirname</span> <span class="o">+</span> <span class="s1">'/../extras/jsl.conf'</span>
|
||||
@@ -132,18 +139,18 @@ any errors or warnings that arise.</p> </td> <td class="
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">printIt</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">printIt</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">write</span> <span class="nx">js</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTokens = </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">end</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Pretty-print a stream of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">printTokens = </span><span class="p">(</span><span class="nx">tokens</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">strings = </span><span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">tokens</span>
|
||||
<span class="p">[</span><span class="nx">tag</span><span class="p">,</span> <span class="nx">value</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">token</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">toString</span><span class="p">().</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\n/</span><span class="p">,</span> <span class="s1">'\\n'</span><span class="p">)]</span>
|
||||
<span class="s2">"[#{tag} #{value}]"</span>
|
||||
<span class="nx">printLine</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</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>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<span class="nx">printLine</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">' '</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
|
||||
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">parseOptions = </span><span class="o">-></span>
|
||||
<span class="nv">optionParser = </span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span>
|
||||
<span class="nv">o = opts = </span><span class="nx">optionParser</span><span class="p">.</span><span class="nx">parse</span> <span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">2</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or=</span> <span class="o">!!</span><span class="nx">o</span><span class="p">.</span><span class="nx">output</span>
|
||||
<span class="nv">o.run = </span><span class="o">not</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span><span class="p">)</span>
|
||||
<span class="nv">o.print = </span><span class="o">!!</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nb">eval</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">stdio</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span><span class="p">))</span>
|
||||
<span class="nv">sources = </span><span class="nx">o</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileOptions = </span><span class="p">(</span><span class="nx">fileName</span><span class="p">)</span> <span class="o">-></span> <span class="p">{</span><span class="nx">fileName</span><span class="p">,</span> <span class="nx">bare</span><span class="o">:</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
|
||||
<span class="nv">sources = </span><span class="nx">o</span><span class="p">.</span><span class="nx">arguments</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <p>The compile-time options to pass to the CoffeeScript compiler.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compileOptions = </span><span class="p">(</span><span class="nx">filename</span><span class="p">)</span> <span class="o">-></span> <span class="p">{</span><span class="nx">filename</span><span class="p">,</span> <span class="nx">bare</span><span class="o">:</span> <span class="nx">opts</span><span class="p">.</span><span class="nx">bare</span><span class="p">}</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
|
||||
the <code>node</code> binary, preserving the other options.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">forkNode = </span><span class="o">-></span>
|
||||
<span class="nv">nodeArgs = </span><span class="nx">opts</span><span class="p">.</span><span class="nx">nodejs</span><span class="p">.</span><span class="nx">split</span> <span class="sr">/\s+/</span>
|
||||
<span class="nv">args = </span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">..]</span>
|
||||
@@ -151,11 +158,9 @@ the <code>node</code> binary, preserving the other options.</p> </td
|
||||
<span class="nx">spawn</span> <span class="nx">process</span><span class="p">.</span><span class="nx">execPath</span><span class="p">,</span> <span class="nx">nodeArgs</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">args</span><span class="p">),</span>
|
||||
<span class="nx">cwd</span><span class="o">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">cwd</span><span class="p">()</span>
|
||||
<span class="nx">env</span><span class="o">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span>
|
||||
<span class="nx">customFds</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
<span class="nx">customFds</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</a> </div> <p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
|
||||
shown.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">usage = </span><span class="o">-></span>
|
||||
<span class="nx">printLine</span> <span class="p">(</span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span><span class="p">).</span><span class="nx">help</span><span class="p">()</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</a> </div> <p>Print the <code>--version</code> message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">version = </span><span class="o">-></span>
|
||||
<span class="nx">printLine</span> <span class="p">(</span><span class="k">new</span> <span class="nx">optparse</span><span class="p">.</span><span class="nx">OptionParser</span> <span class="nx">SWITCHES</span><span class="p">,</span> <span class="nx">BANNER</span><span class="p">).</span><span class="nx">help</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</a> </div> <p>Print the <code>--version</code> message and exit.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">version = </span><span class="o">-></span>
|
||||
<span class="nx">printLine</span> <span class="s2">"CoffeeScript version #{CoffeeScript.VERSION}"</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">0</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -115,7 +115,7 @@ table td {
|
||||
}
|
||||
pre, tt, code {
|
||||
font-size: 12px; line-height: 18px;
|
||||
font-family: Monaco, Consolas, "Lucida Console", monospace;
|
||||
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ previous nonterminal.</p> </td> <td class="code">
|
||||
<span class="k">return</span> <span class="p">[</span><span class="nx">patternString</span><span class="p">,</span> <span class="s1">'$$ = $1;'</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span> <span class="nx">unless</span> <span class="nx">action</span>
|
||||
<span class="nv">action = </span><span class="k">if</span> <span class="nv">match = </span><span class="nx">unwrap</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">action</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">else</span> <span class="s2">"(#{action}())"</span>
|
||||
<span class="nv">action = </span><span class="nx">action</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\bnew /g</span><span class="p">,</span> <span class="s1">'$&yy.'</span>
|
||||
<span class="nv">action = </span><span class="nx">action</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\b(?:Expressions\.wrap|extend)\b/g</span><span class="p">,</span> <span class="s1">'yy.$&'</span>
|
||||
<span class="nv">action = </span><span class="nx">action</span><span class="p">.</span><span class="nx">replace</span> <span class="sr">/\b(?:Block\.wrap|extend)\b/g</span><span class="p">,</span> <span class="s1">'yy.$&'</span>
|
||||
<span class="p">[</span><span class="nx">patternString</span><span class="p">,</span> <span class="s2">"$$ = #{action};"</span><span class="p">,</span> <span class="nx">options</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <h2>Grammatical Rules</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>In all of the rules that follow, you'll see the name of the nonterminal as
|
||||
the key to a list of alternative matches. With each match's action, the
|
||||
dollar-sign variables are provided by Jison as references to the value of
|
||||
@@ -36,14 +36,14 @@ their numeric position, so in this rule:</p>
|
||||
for the <code>UNLESS</code> terminal, and <code>$3</code> would be the value of the second
|
||||
<code>Expression</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">grammar =</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>The <strong>Root</strong> is the top-level node in the syntax tree. Since we parse bottom-up,
|
||||
all parsing must end here.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Root</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">''</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</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">Block</span>
|
||||
<span class="nx">o</span> <span class="s1">'Body'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Block TERMINATOR'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>Any list of statements and expressions, separated by line breaks or semicolons.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Body</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Line'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'Line'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'Body TERMINATOR Line'</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">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'Body TERMINATOR'</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> <p>Expressions and statements, which make up a line in a body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Line</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Block and statements, which make up a line in a body.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Line</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Statement'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Pure statements which cannot be expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Statement</span><span class="o">:</span> <span class="p">[</span>
|
||||
@@ -53,7 +53,7 @@ all parsing must end here.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">'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. Expressions serve as the building blocks of many other rules, making
|
||||
is one. Block serve as the building blocks of many other rules, making
|
||||
them somewhat circular.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Expression</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Value'</span>
|
||||
<span class="nx">o</span> <span class="s1">'Invocation'</span>
|
||||
@@ -69,7 +69,7 @@ them somewhat circular.</p> </td> <td class="code">
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>An indented block of expressions. Note that the <a href="rewriter.html">Rewriter</a>
|
||||
will convert some postfix forms into blocks for us, by adjusting the
|
||||
token stream.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Block</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT OUTDENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Block</span>
|
||||
<span class="nx">o</span> <span class="s1">'INDENT Body OUTDENT'</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-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>A literal identifier, a variable name or property.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Identifier</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
@@ -83,7 +83,9 @@ through and printed to JavaScript.</p> </td> <td class="
|
||||
<span class="nx">o</span> <span class="s1">'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>
|
||||
<span class="nx">o</span> <span class="s1">'REGEX'</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">'BOOL'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="k">new</span> <span class="nx">Literal</span> <span class="k">if</span> <span class="nx">$1</span> <span class="o">is</span> <span class="s1">'undefined'</span> <span class="k">then</span> <span class="s1">'void 0'</span> <span class="k">else</span> <span class="nx">$1</span>
|
||||
<span class="nv">val = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">$1</span>
|
||||
<span class="nv">val.isUndefined = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">$1</span> <span class="o">is</span> <span class="s1">'undefined'</span>
|
||||
<span class="nx">val</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Assignment of a variable, property, or index to a value.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Assign</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'Assignable = Expression'</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">$3</span>
|
||||
<span class="nx">o</span> <span class="s1">'Assignable = 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>
|
||||
@@ -106,7 +108,7 @@ the ordinary <strong>Assign</strong> is that these allow numbers and strings as
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</a> </div> <p>A block comment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Comment</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'HERECOMMENT'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Comment</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</a> </div> <p>The <strong>Code</strong> node is the function literal. It's defined by an indented block
|
||||
of <strong>Expressions</strong> preceded by a function arrow, with an optional parameter
|
||||
of <strong>Block</strong> preceded by a function arrow, with an optional parameter
|
||||
list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Code</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'PARAM_START ParamList PARAM_END FuncGlyph Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Code</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span><span class="p">,</span> <span class="nx">$4</span>
|
||||
<span class="nx">o</span> <span class="s1">'FuncGlyph Block'</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Code</span> <span class="p">[],</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$1</span>
|
||||
@@ -158,11 +160,15 @@ or by array index or slice.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s1">':: 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="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>
|
||||
|
||||
<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-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="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
|
||||
@@ -207,9 +213,9 @@ and optional references to the superclass.</p> </td> <td
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</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="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-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,
|
||||
as well as the contents of an array literal
|
||||
(i.e. comma-separated expressions). Newlines work as well.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ArgList</span><span class="o">:</span> <span class="p">[</span>
|
||||
@@ -218,7 +224,7 @@ as well as the contents of an array literal
|
||||
<span class="nx">o</span> <span class="s1">'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 Expressions or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">¶</a> </div> <p>Valid arguments are Block or Splats.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">Arg</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'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
|
||||
@@ -249,14 +255,14 @@ the trick.</p> </td> <td class="code"> <di
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</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">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'Expression 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">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'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>
|
||||
<span class="nx">o</span> <span class="s1">'Expression 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>
|
||||
<span class="nx">o</span> <span class="s1">'Loop'</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="nx">Loop</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'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">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s1">'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.
|
||||
Comprehensions can either be normal, with a block of expressions to execute,
|
||||
or postfix, with a single expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">For</span><span class="o">:</span> <span class="p">[</span>
|
||||
@@ -313,12 +319,12 @@ if-related rules are broken up along these lines in order to avoid
|
||||
ambiguity.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">IfBlock</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">'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="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="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
|
||||
<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">'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">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'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">Expressions</span><span class="p">.</span><span class="nx">wrap</span><span class="p">([</span><span class="nx">$1</span><span class="p">]),</span> <span class="nx">type</span><span class="o">:</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">statement</span><span class="o">:</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s1">'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.
|
||||
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
|
||||
|
||||
@@ -19,6 +19,7 @@ it has consumed.</p>
|
||||
|
||||
<p>Before returning the token stream, run it through the <a href="rewriter.html">Rewriter</a>
|
||||
unless explicitly asked not to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">tokenize</span><span class="o">:</span> <span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nv">opts = </span><span class="p">{})</span> <span class="o">-></span>
|
||||
<span class="nv">code = </span><span class="s2">"\n#{code}"</span> <span class="k">if</span> <span class="nx">WHITESPACE</span><span class="p">.</span><span class="nx">test</span> <span class="nx">code</span>
|
||||
<span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/\r/g</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nx">replace</span> <span class="nx">TRAILING_SPACES</span><span class="p">,</span> <span class="s1">''</span>
|
||||
|
||||
<span class="vi">@code = </span><span class="nx">code</span> <span class="c1"># The remainder of the source code.</span>
|
||||
@@ -57,7 +58,8 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
|
||||
<span class="nx">@token</span> <span class="s1">'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>
|
||||
@@ -90,7 +92,7 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
|
||||
<span class="nx">@identifierError</span> <span class="nx">id</span>
|
||||
|
||||
<span class="nx">unless</span> <span class="nx">forcedIdentifier</span>
|
||||
<span class="nv">id = </span><span class="nx">COFFEE_ALIASES</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">hasOwnProperty</span> <span class="nx">id</span>
|
||||
<span class="nv">id = </span><span class="nx">COFFEE_ALIAS_MAP</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">id</span> <span class="k">in</span> <span class="nx">COFFEE_ALIASES</span>
|
||||
<span class="nv">tag = </span><span class="k">switch</span> <span class="nx">id</span>
|
||||
<span class="k">when</span> <span class="s1">'!'</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>
|
||||
@@ -135,11 +137,11 @@ preserve whitespace, but ignore indentation to the left.</p> </td>
|
||||
<span class="nx">heredoc</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</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>
|
||||
@@ -276,8 +278,11 @@ parentheses that indicate a method call from regular parentheses, and so on.</p>
|
||||
<span class="nx">value</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">¶</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>
|
||||
@@ -297,7 +302,7 @@ parameters specially in order to make things easier for the parser.</p>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="nx">tok</span>
|
||||
<span class="k">when</span> <span class="s1">'('</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">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>
|
||||
@@ -354,10 +359,11 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="nv">nested = </span><span class="k">new</span> <span class="nx">Lexer</span><span class="p">().</span><span class="nx">tokenize</span> <span class="nx">inner</span><span class="p">,</span> <span class="nx">line</span><span class="o">:</span> <span class="nx">@line</span><span class="p">,</span> <span class="nx">rewrite</span><span class="o">:</span> <span class="kc">off</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span> <span class="k">if</span> <span class="nx">nested</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span>
|
||||
<span class="k">if</span> <span class="nx">nested</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">unshift</span> <span class="p">[</span><span class="s1">'('</span><span class="p">,</span> <span class="s1">'('</span><span class="p">]</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">')'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">]</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'TOKENS'</span><span class="p">,</span> <span class="nx">nested</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nv">len = </span><span class="nx">nested</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="nx">len</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">unshift</span> <span class="p">[</span><span class="s1">'('</span><span class="p">,</span> <span class="s1">'('</span><span class="p">]</span>
|
||||
<span class="nx">nested</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">')'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">]</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'TOKENS'</span><span class="p">,</span> <span class="nx">nested</span><span class="p">]</span>
|
||||
<span class="nx">i</span> <span class="o">+=</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">pi = </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="p">[</span><span class="s1">'NEOSTRING'</span><span class="p">,</span> <span class="nx">str</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">pi</span><span class="p">]</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">></span> <span class="nx">pi</span> <span class="o"><</span> <span class="nx">str</span><span class="p">.</span><span class="nx">length</span>
|
||||
@@ -392,7 +398,8 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="s1">'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>
|
||||
@@ -401,7 +408,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>
|
||||
@@ -411,7 +421,7 @@ to avoid having a JavaScript error at runtime.</p> </td>
|
||||
be used as identifiers or properties.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_FORBIDDEN = </span><span class="nx">JS_KEYWORDS</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">RESERVED</span>
|
||||
|
||||
<span class="nv">exports.RESERVED = </span><span class="nx">RESERVED</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">JS_KEYWORDS</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">COFFEE_KEYWORDS</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</a> </div> <p>Token matching regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER = </span><span class="err">/// ^</span>
|
||||
<span class="p">(</span> <span class="p">[</span><span class="nx">$A</span><span class="o">-</span><span class="nx">Za</span><span class="o">-</span><span class="nx">z_</span><span class="p">][</span><span class="nx">$</span><span class="err">\</span><span class="nx">w</span><span class="p">]</span><span class="o">*</span> <span class="p">)</span>
|
||||
<span class="p">(</span> <span class="p">[</span><span class="nx">$A</span><span class="o">-</span><span class="nx">Za</span><span class="o">-</span><span class="nx">z_</span><span class="err">\</span><span class="nx">x7f</span><span class="o">-</span><span class="err">\</span><span class="nx">uffff</span><span class="p">][</span><span class="nx">$</span><span class="err">\</span><span class="nx">w</span><span class="err">\</span><span class="nx">x7f</span><span class="o">-</span><span class="err">\</span><span class="nx">uffff</span><span class="p">]</span><span class="o">*</span> <span class="p">)</span>
|
||||
<span class="p">(</span> <span class="p">[</span><span class="o">^</span><span class="err">\</span><span class="nx">n</span><span class="err">\</span><span class="nx">S</span><span class="p">]</span><span class="o">*</span> <span class="o">:</span> <span class="p">(</span><span class="o">?!:</span><span class="p">)</span> <span class="p">)</span><span class="o">?</span> <span class="c1"># Is this a property name?</span>
|
||||
<span class="err">///</span>
|
||||
|
||||
@@ -443,7 +453,7 @@ be used as identifiers or properties.</p> </td> <td clas
|
||||
<span class="nv">SIMPLESTR = </span><span class="sr">/^'[^\\']*(?:\\.[^\\']*)*'/</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>
|
||||
@@ -462,9 +472,11 @@ be used as identifiers or properties.</p> </td> <td clas
|
||||
|
||||
<span class="nv">HEREDOC_INDENT = </span><span class="sr">/\n+([^\n\S]*)/g</span>
|
||||
|
||||
<span class="nv">ASSIGNED = </span><span class="sr">/^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/</span>
|
||||
<span class="nv">HEREDOC_ILLEGAL = </span><span class="sr">/\*\//</span>
|
||||
|
||||
<span class="nv">LINE_CONTINUER = </span><span class="err">/// ^ \s* (?: , | \??\.(?!\.) | :: ) ///</span>
|
||||
<span class="nv">ASSIGNED = </span><span class="sr">/^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\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>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ return results).</p> </td> <td class="code">
|
||||
<span class="k">else</span>
|
||||
<span class="nx">node</span><span class="p">.</span><span class="nx">compileClosure</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Statements converted into expressions via closure-wrapping share a scope
|
||||
object with their parent closure, to preserve the expected lexical scope.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileClosure</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@jumps</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">@jumps</span><span class="p">()</span> <span class="o">or</span> <span class="k">this</span> <span class="k">instanceof</span> <span class="nx">Throw</span>
|
||||
<span class="k">throw</span> <span class="nx">SyntaxError</span> <span class="s1">'cannot use a pure statement in an expression.'</span>
|
||||
<span class="nv">o.sharedScope = </span><span class="kc">yes</span>
|
||||
<span class="nx">Closure</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">compileNode</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>If the code generation wishes to use the result of a complex expression
|
||||
@@ -94,9 +94,9 @@ will override these with custom logic, if needed.</p> </td>
|
||||
<span class="nx">isAssignable</span> <span class="o">:</span> <span class="nx">NO</span>
|
||||
|
||||
<span class="nx">unwrap</span> <span class="o">:</span> <span class="nx">THIS</span>
|
||||
<span class="nx">unfoldSoak</span> <span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Is this node used to assign a certain variable?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assigns</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <h3>Expressions</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>The expressions body is the list of expressions that forms the body of an
|
||||
<span class="nx">unfoldSoak</span> <span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>Is this node used to assign a certain variable?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">assigns</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <h3>Block</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>The block is the list of expressions that forms the body of an
|
||||
indented block of code -- the implementation of a function, a clause in an
|
||||
<code>if</code>, <code>switch</code>, or <code>try</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Expressions = </span><span class="nx">class</span> <span class="nx">Expressions</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<code>if</code>, <code>switch</code>, or <code>try</code>, and so on...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Block = </span><span class="nx">class</span> <span class="nx">Block</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">nodes</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@expressions = </span><span class="nx">compact</span> <span class="nx">flatten</span> <span class="nx">nodes</span> <span class="o">or</span> <span class="p">[]</span>
|
||||
|
||||
@@ -105,7 +105,7 @@ indented block of code -- the implementation of a function, a clause in an
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</a> </div> <p>Remove and return the last expression of this expression list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">pop</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">¶</a> </div> <p>Add an expression at the beginning of this expression list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unshift</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="nx">node</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">¶</a> </div> <p>If this Expressions consists of just a single node, unwrap it by pulling
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">¶</a> </div> <p>If this Block consists of just a single node, unwrap it by pulling
|
||||
it back out.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unwrap</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">1</span> <span class="k">then</span> <span class="nx">@expressions</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">else</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">¶</a> </div> <p>Is this an empty block of code?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">isEmpty</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="o">not</span> <span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span>
|
||||
@@ -117,16 +117,17 @@ it back out.</p> </td> <td class="code"> <
|
||||
|
||||
<span class="nx">jumps</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">exp</span> <span class="k">in</span> <span class="nx">@expressions</span>
|
||||
<span class="k">return</span> <span class="nx">exp</span> <span class="k">if</span> <span class="nx">exp</span><span class="p">.</span><span class="nx">jumps</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</a> </div> <p>An Expressions node does not return its entire body, rather it
|
||||
<span class="k">return</span> <span class="nx">exp</span> <span class="k">if</span> <span class="nx">exp</span><span class="p">.</span><span class="nx">jumps</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</a> </div> <p>An Block node does not return its entire body, rather it
|
||||
ensures that the final expression is returned.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nv">len = </span><span class="nx">@expressions</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">while</span> <span class="nx">len</span><span class="o">--</span>
|
||||
<span class="nv">expr = </span><span class="nx">@expressions</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">expr</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Comment</span>
|
||||
<span class="nx">@expressions</span><span class="p">[</span><span class="nx">len</span><span class="p">]</span> <span class="o">=</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()</span>
|
||||
<span class="nx">@expressions</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">len</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Return</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">expression</span>
|
||||
<span class="k">break</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</a> </div> <p>An <strong>Expressions</strong> is the only node that can serve as the root.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nv">o = </span><span class="p">{},</span> <span class="nx">level</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span> <span class="k">then</span> <span class="k">super</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">level</span> <span class="k">else</span> <span class="nx">@compileRoot</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">¶</a> </div> <p>Compile all expressions within the <strong>Expressions</strong> body. If we need to
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</a> </div> <p>An <strong>Block</strong> is the only node that can serve as the root.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nv">o = </span><span class="p">{},</span> <span class="nx">level</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span> <span class="k">then</span> <span class="k">super</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">level</span> <span class="k">else</span> <span class="nx">@compileRoot</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">¶</a> </div> <p>Compile all expressions within the <strong>Block</strong> body. If we need to
|
||||
return the result, and it's an expression, simply return it. If it's a
|
||||
statement, ask the statement to do so.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@tab = </span><span class="nx">o</span><span class="p">.</span><span class="nx">indent</span>
|
||||
@@ -143,7 +144,7 @@ statement, ask the statement to do so.</p> </td> <td cla
|
||||
<span class="nx">codes</span><span class="p">.</span><span class="nx">push</span> <span class="nx">node</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
<span class="k">return</span> <span class="nx">codes</span><span class="p">.</span><span class="nx">join</span> <span class="s1">'\n'</span> <span class="k">if</span> <span class="nx">top</span>
|
||||
<span class="nv">code = </span><span class="nx">codes</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s1">', '</span><span class="p">)</span> <span class="o">or</span> <span class="s1">'void 0'</span>
|
||||
<span class="k">if</span> <span class="nx">codes</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">¶</a> </div> <p>If we happen to be the top-level <strong>Expressions</strong>, wrap everything in
|
||||
<span class="k">if</span> <span class="nx">codes</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">¶</a> </div> <p>If we happen to be the top-level <strong>Block</strong>, wrap everything in
|
||||
a safety closure, unless requested not to.
|
||||
It would be better not to generate them in the first place, but for now,
|
||||
clean up obvious double-parentheses.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileRoot</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -151,7 +152,6 @@ clean up obvious double-parentheses.</p> </td> <td class
|
||||
<span class="nv">o.scope = </span><span class="k">new</span> <span class="nx">Scope</span> <span class="kc">null</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="kc">null</span>
|
||||
<span class="nv">o.level = </span><span class="nx">LEVEL_TOP</span>
|
||||
<span class="nv">code = </span><span class="nx">@compileWithDeclarations</span> <span class="nx">o</span>
|
||||
<span class="nv">code = </span><span class="nx">code</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">TRAILING_WHITESPACE</span><span class="p">,</span> <span class="s1">''</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">bare</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(function() {\n#{code}\n}).call(this);\n"</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">¶</a> </div> <p>Compile the expressions body for the contents of a function, with
|
||||
declarations of all inner variables pushed up to the top.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileWithDeclarations</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">code = post = </span><span class="s1">''</span>
|
||||
@@ -166,14 +166,14 @@ declarations of all inner variables pushed up to the top.</p> </td>
|
||||
<span class="nv">post = </span><span class="nx">@compileNode</span> <span class="nx">o</span>
|
||||
<span class="p">{</span><span class="nx">scope</span><span class="p">}</span> <span class="o">=</span> <span class="nx">o</span>
|
||||
<span class="k">if</span> <span class="nx">scope</span><span class="p">.</span><span class="nx">expressions</span> <span class="o">is</span> <span class="k">this</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">o</span><span class="p">.</span><span class="nx">globals</span> <span class="o">and</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">hasDeclarations</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">hasDeclarations</span><span class="p">()</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="s2">"#{@tab}var #{ scope.declaredVariables().join(', ') };\n"</span>
|
||||
<span class="k">if</span> <span class="nx">scope</span><span class="p">.</span><span class="nx">hasAssignments</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="s2">"#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"</span>
|
||||
<span class="nx">code</span> <span class="o">+</span> <span class="nx">post</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">¶</a> </div> <p>Wrap up the given nodes as an <strong>Expressions</strong>, unless it already happens
|
||||
<span class="nx">code</span> <span class="o">+</span> <span class="nx">post</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">¶</a> </div> <p>Wrap up the given nodes as an <strong>Block</strong>, unless it already happens
|
||||
to be one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">@wrap</span><span class="o">:</span> <span class="p">(</span><span class="nx">nodes</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">nodes</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">instanceof</span> <span class="nx">Expressions</span>
|
||||
<span class="k">new</span> <span class="nx">Expressions</span> <span class="nx">nodes</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">¶</a> </div> <h3>Literal</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Literals are static values that can be passed through directly into
|
||||
<span class="k">return</span> <span class="nx">nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="nx">nodes</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="nx">nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">instanceof</span> <span class="nx">Block</span>
|
||||
<span class="k">new</span> <span class="nx">Block</span> <span class="nx">nodes</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">¶</a> </div> <h3>Literal</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">¶</a> </div> <p>Literals are static values that can be passed through directly into
|
||||
JavaScript without translation, such as: strings, numbers,
|
||||
<code>true</code>, <code>false</code>, <code>null</code>...</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Literal = </span><span class="nx">class</span> <span class="nx">Literal</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@value</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -197,13 +197,19 @@ JavaScript without translation, such as: strings, numbers,
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="p">(</span><span class="nx">o</span> <span class="o">and</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">loop</span> <span class="o">or</span> <span class="nx">o</span><span class="p">.</span><span class="nx">block</span> <span class="o">and</span> <span class="p">(</span><span class="nx">@value</span> <span class="o">isnt</span> <span class="s1">'continue'</span><span class="p">)))</span> <span class="k">then</span> <span class="k">this</span> <span class="k">else</span> <span class="kc">no</span>
|
||||
|
||||
<span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">code = </span><span class="k">if</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">reserved</span> <span class="k">then</span> <span class="s2">"\"#{@value}\""</span> <span class="k">else</span> <span class="nx">@value</span>
|
||||
<span class="nv">code = </span><span class="k">if</span> <span class="nx">@isUndefined</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_ACCESS</span> <span class="k">then</span> <span class="s1">'(void 0)'</span> <span class="k">else</span> <span class="s1">'void 0'</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">reserved</span>
|
||||
<span class="s2">"\"#{@value}\""</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@value</span>
|
||||
<span class="k">if</span> <span class="nx">@isStatement</span><span class="p">()</span> <span class="k">then</span> <span class="s2">"#{@tab}#{code};"</span> <span class="k">else</span> <span class="nx">code</span>
|
||||
|
||||
<span class="nx">toString</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="s1">' "'</span> <span class="o">+</span> <span class="nx">@value</span> <span class="o">+</span> <span class="s1">'"'</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">¶</a> </div> <h3>Return</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">¶</a> </div> <p>A <code>return</code> is a <em>pureStatement</em> -- wrapping it in a closure wouldn't
|
||||
make sense.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Return = </span><span class="nx">class</span> <span class="nx">Return</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@expression</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">expr</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@expression = </span><span class="nx">expr</span> <span class="k">if</span> <span class="nx">expr</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">().</span><span class="nx">isUndefined</span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'expression'</span><span class="p">]</span>
|
||||
|
||||
@@ -278,19 +284,22 @@ evaluate anything twice when building the soak chain.</p> </td>
|
||||
<span class="nv">code = </span><span class="s2">"(#{code})"</span> <span class="k">if</span> <span class="nx">props</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">instanceof</span> <span class="nx">Access</span> <span class="o">and</span> <span class="nx">@isSimpleNumber</span><span class="p">()</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span> <span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">props</span>
|
||||
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">¶</a> </div> <p>Unfold a soak into an <code>If</code>: <code>a?.b</code> -> <code>a.b if a?</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">unfoldSoak</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nv">ifn = </span><span class="nx">@base</span><span class="p">.</span><span class="nx">unfoldSoak</span> <span class="nx">o</span>
|
||||
<span class="nb">Array</span><span class="o">::</span><span class="nx">push</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">ifn</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">properties</span><span class="p">,</span> <span class="nx">@properties</span>
|
||||
<span class="k">return</span> <span class="nx">ifn</span>
|
||||
<span class="k">for</span> <span class="nx">prop</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@properties</span> <span class="k">when</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">soak</span>
|
||||
<span class="nv">prop.soak = </span><span class="kc">off</span>
|
||||
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nv">snd = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span>
|
||||
<span class="k">if</span> <span class="nx">fst</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
|
||||
<span class="nv">ref = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">freeVariable</span> <span class="s1">'ref'</span>
|
||||
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">fst</span>
|
||||
<span class="nv">snd.base = </span><span class="nx">ref</span>
|
||||
<span class="k">return</span> <span class="k">new</span> <span class="nx">If</span> <span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">),</span> <span class="nx">snd</span><span class="p">,</span> <span class="nx">soak</span><span class="o">:</span> <span class="kc">on</span>
|
||||
<span class="kc">null</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <h3>Comment</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">¶</a> </div> <p>CoffeeScript passes through block comments as JavaScript block comments
|
||||
<span class="k">return</span> <span class="nx">@unfoldedSoak</span> <span class="k">if</span> <span class="nx">@unfoldedSoak</span><span class="o">?</span>
|
||||
<span class="nv">result = </span><span class="nx">do</span> <span class="o">=></span>
|
||||
<span class="k">if</span> <span class="nv">ifn = </span><span class="nx">@base</span><span class="p">.</span><span class="nx">unfoldSoak</span> <span class="nx">o</span>
|
||||
<span class="nb">Array</span><span class="o">::</span><span class="nx">push</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">ifn</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">properties</span><span class="p">,</span> <span class="nx">@properties</span>
|
||||
<span class="k">return</span> <span class="nx">ifn</span>
|
||||
<span class="k">for</span> <span class="nx">prop</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@properties</span> <span class="k">when</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">soak</span>
|
||||
<span class="nv">prop.soak = </span><span class="kc">off</span>
|
||||
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">i</span>
|
||||
<span class="nv">snd = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@base</span><span class="p">,</span> <span class="nx">@properties</span><span class="p">.</span><span class="nx">slice</span> <span class="nx">i</span>
|
||||
<span class="k">if</span> <span class="nx">fst</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
|
||||
<span class="nv">ref = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">freeVariable</span> <span class="s1">'ref'</span>
|
||||
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">fst</span>
|
||||
<span class="nv">snd.base = </span><span class="nx">ref</span>
|
||||
<span class="k">return</span> <span class="k">new</span> <span class="nx">If</span> <span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">),</span> <span class="nx">snd</span><span class="p">,</span> <span class="nx">soak</span><span class="o">:</span> <span class="kc">on</span>
|
||||
<span class="kc">null</span>
|
||||
<span class="vi">@unfoldedSoak = </span><span class="nx">result</span> <span class="o">or</span> <span class="kc">no</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">¶</a> </div> <h3>Comment</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">¶</a> </div> <p>CoffeeScript passes through block comments as JavaScript block comments
|
||||
at the same position.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Comment = </span><span class="nx">class</span> <span class="nx">Comment</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@comment</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
@@ -351,17 +360,33 @@ method.</p> </td> <td class="code"> <div c
|
||||
<span class="k">else</span>
|
||||
<span class="nv">call.variable.base = </span><span class="nx">ifn</span>
|
||||
<span class="nv">ifn = </span><span class="nx">unfoldSoak</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">call</span><span class="p">,</span> <span class="s1">'variable'</span>
|
||||
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Compile a vanilla function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">¶</a> </div> <p>Walk through the objects in the arguments, moving over simple values.
|
||||
This allows syntax like <code>call a: b, c</code> into <code>call({a: b}, c);</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">filterImplicitObjects</span><span class="o">:</span> <span class="p">(</span><span class="nx">list</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">nodes = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">list</span>
|
||||
<span class="nx">unless</span> <span class="nx">node</span><span class="p">.</span><span class="nx">isObject</span><span class="o">?</span><span class="p">()</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">generated</span>
|
||||
<span class="nx">nodes</span><span class="p">.</span><span class="nx">push</span> <span class="nx">node</span>
|
||||
<span class="k">continue</span>
|
||||
<span class="nv">obj = </span><span class="kc">null</span>
|
||||
<span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">node</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">properties</span>
|
||||
<span class="k">if</span> <span class="nx">prop</span> <span class="k">instanceof</span> <span class="nx">Assign</span>
|
||||
<span class="nx">nodes</span><span class="p">.</span><span class="nx">push</span> <span class="nv">obj = </span><span class="k">new</span> <span class="nx">Obj</span> <span class="nv">properties = </span><span class="p">[],</span> <span class="kc">true</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">obj</span>
|
||||
<span class="nx">properties</span><span class="p">.</span><span class="nx">push</span> <span class="nx">prop</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">nodes</span><span class="p">.</span><span class="nx">push</span> <span class="nx">prop</span>
|
||||
<span class="nv">obj = </span><span class="kc">null</span>
|
||||
<span class="nx">nodes</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">¶</a> </div> <p>Compile a vanilla function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@variable</span><span class="o">?</span><span class="p">.</span><span class="nv">front = </span><span class="nx">@front</span>
|
||||
<span class="k">if</span> <span class="nv">code = </span><span class="nx">Splat</span><span class="p">.</span><span class="nx">compileSplattedArray</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">@args</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="k">return</span> <span class="nx">@compileSplat</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">code</span>
|
||||
<span class="nv">args = </span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">@args</span><span class="p">).</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
<span class="nv">args = </span><span class="nx">@filterImplicitObjects</span> <span class="nx">@args</span>
|
||||
<span class="nv">args = </span><span class="p">(</span><span class="nx">arg</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">arg</span> <span class="k">in</span> <span class="nx">args</span><span class="p">).</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
<span class="k">if</span> <span class="nx">@isSuper</span>
|
||||
<span class="nx">@superReference</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s2">".call(this#{ args and ', ' + args })"</span>
|
||||
<span class="k">else</span>
|
||||
<span class="p">(</span><span class="k">if</span> <span class="nx">@isNew</span> <span class="k">then</span> <span class="s1">'new '</span> <span class="k">else</span> <span class="s1">''</span><span class="p">)</span> <span class="o">+</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"(#{args})"</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">¶</a> </div> <p><code>super()</code> is converted into a call against the superclass's implementation
|
||||
<span class="p">(</span><span class="k">if</span> <span class="nx">@isNew</span> <span class="k">then</span> <span class="s1">'new '</span> <span class="k">else</span> <span class="s1">''</span><span class="p">)</span> <span class="o">+</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"(#{args})"</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</a> </div> <p><code>super()</code> is converted into a call against the superclass's implementation
|
||||
of the current function.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSuper</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="s2">"#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#{args})"</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">¶</a> </div> <p>If you call a function with a splat, it's converted into a JavaScript
|
||||
<span class="s2">"#{@superReference(o)}.call(this#{ if args.length then ', ' else '' }#{args})"</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">¶</a> </div> <p>If you call a function with a splat, it's converted into a JavaScript
|
||||
<code>.apply()</code> call to allow an array of arguments to be passed.
|
||||
If it's a constructor, then things get real tricky. We have to inject an
|
||||
inner constructor in order to be able to pass the varargs.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSplat</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">splatArgs</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -369,11 +394,11 @@ inner constructor in order to be able to pass the varargs.</p> </td>
|
||||
<span class="k">if</span> <span class="nx">@isNew</span>
|
||||
<span class="nv">idt = </span><span class="nx">@tab</span> <span class="o">+</span> <span class="nx">TAB</span>
|
||||
<span class="k">return</span> <span class="s2">"""</span>
|
||||
<span class="s2"> (function(func, args, ctor) {</span>
|
||||
<span class="s2"> #{idt}ctor.prototype = func.prototype;</span>
|
||||
<span class="s2"> #{idt}var child = new ctor, result = func.apply(child, args);</span>
|
||||
<span class="s2"> #{idt}return typeof result === "</span><span class="nx">object</span><span class="s2">" ? result : child;</span>
|
||||
<span class="s2"> #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})</span>
|
||||
<span class="s2"> (function(func, args, ctor) {</span>
|
||||
<span class="s2"> #{idt}ctor.prototype = func.prototype;</span>
|
||||
<span class="s2"> #{idt}var child = new ctor, result = func.apply(child, args);</span>
|
||||
<span class="s2"> #{idt}return typeof result === "</span><span class="nx">object</span><span class="s2">" ? result : child;</span>
|
||||
<span class="s2"> #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})</span>
|
||||
<span class="s2"> """</span>
|
||||
<span class="nv">base = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">@variable</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nv">name = </span><span class="nx">base</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">pop</span><span class="p">())</span> <span class="o">and</span> <span class="nx">base</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
|
||||
@@ -381,19 +406,20 @@ inner constructor in order to be able to pass the varargs.</p> </td>
|
||||
<span class="nv">fun = </span><span class="s2">"(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">fun = </span><span class="nx">base</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_ACCESS</span>
|
||||
<span class="nv">fun = </span><span class="s2">"(#{fun})"</span> <span class="k">if</span> <span class="nx">SIMPLENUM</span><span class="p">.</span><span class="nx">test</span> <span class="nx">fun</span>
|
||||
<span class="k">if</span> <span class="nx">name</span>
|
||||
<span class="nv">ref = </span><span class="nx">fun</span>
|
||||
<span class="nx">fun</span> <span class="o">+=</span> <span class="nx">name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">ref = </span><span class="s1">'null'</span>
|
||||
<span class="s2">"#{fun}.apply(#{ref}, #{splatArgs})"</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">¶</a> </div> <h3>Extends</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">¶</a> </div> <p>Node to extend an object's prototype with an ancestor object.
|
||||
<span class="s2">"#{fun}.apply(#{ref}, #{splatArgs})"</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">¶</a> </div> <h3>Extends</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">¶</a> </div> <p>Node to extend an object's prototype with an ancestor object.
|
||||
After <code>goog.inherits</code> from the
|
||||
<a href="http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html">Closure Library</a>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Extends = </span><span class="nx">class</span> <span class="nx">Extends</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@child</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'child'</span><span class="p">,</span> <span class="s1">'parent'</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>Hooks one constructor into another's prototype chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'child'</span><span class="p">,</span> <span class="s1">'parent'</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>Hooks one constructor into another's prototype chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">utility</span> <span class="s1">'hasProp'</span>
|
||||
<span class="k">new</span> <span class="nx">Call</span><span class="p">(</span><span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">utility</span> <span class="s1">'extends'</span><span class="p">),</span> <span class="p">[</span><span class="nx">@child</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">]).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">¶</a> </div> <h3>Access</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">¶</a> </div> <p>A <code>.</code> access into a property of a value, or the <code>::</code> shorthand for
|
||||
<span class="k">new</span> <span class="nx">Call</span><span class="p">(</span><span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">utility</span> <span class="s1">'extends'</span><span class="p">),</span> <span class="p">[</span><span class="nx">@child</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">]).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">¶</a> </div> <h3>Access</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">¶</a> </div> <p>A <code>.</code> access into a property of a value, or the <code>::</code> shorthand for
|
||||
an access into the object's prototype.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Access = </span><span class="nx">class</span> <span class="nx">Access</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@name</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@name.asKey = </span><span class="kc">yes</span>
|
||||
@@ -406,7 +432,7 @@ an access into the object's prototype.</p> </td> <td cla
|
||||
<span class="nv">name = </span><span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="nx">@proto</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">IS_STRING</span><span class="p">.</span><span class="nx">test</span> <span class="nx">name</span> <span class="k">then</span> <span class="s2">"[#{name}]"</span> <span class="k">else</span> <span class="s2">".#{name}"</span>
|
||||
|
||||
<span class="nx">isComplex</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">¶</a> </div> <h3>Index</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">¶</a> </div> <p>A <code>[ ... ]</code> indexed access into an array or object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Index = </span><span class="nx">class</span> <span class="nx">Index</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">isComplex</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">¶</a> </div> <h3>Index</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">¶</a> </div> <p>A <code>[ ... ]</code> indexed access into an array or object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Index = </span><span class="nx">class</span> <span class="nx">Index</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@index</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'index'</span><span class="p">]</span>
|
||||
@@ -415,7 +441,7 @@ an access into the object's prototype.</p> </td> <td cla
|
||||
<span class="p">(</span><span class="k">if</span> <span class="nx">@proto</span> <span class="k">then</span> <span class="s1">'.prototype'</span> <span class="k">else</span> <span class="s1">''</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"[#{ @index.compile o, LEVEL_PAREN }]"</span>
|
||||
|
||||
<span class="nx">isComplex</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@index</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">¶</a> </div> <h3>Range</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">¶</a> </div> <p>A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||
<span class="nx">@index</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">¶</a> </div> <h3>Range</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">¶</a> </div> <p>A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||
to specify a range for comprehensions, or as a value, to be expanded into the
|
||||
corresponding array of integers at runtime.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Range = </span><span class="nx">class</span> <span class="nx">Range</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
|
||||
@@ -423,7 +449,7 @@ corresponding array of integers at runtime.</p> </td> <t
|
||||
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@from</span><span class="p">,</span> <span class="nx">@to</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@exclusive = </span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">'exclusive'</span>
|
||||
<span class="vi">@equals = </span><span class="k">if</span> <span class="nx">@exclusive</span> <span class="k">then</span> <span class="s1">''</span> <span class="k">else</span> <span class="s1">'='</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">¶</a> </div> <p>Compiles the range's source variables -- where it starts and where it ends.
|
||||
<span class="vi">@equals = </span><span class="k">if</span> <span class="nx">@exclusive</span> <span class="k">then</span> <span class="s1">''</span> <span class="k">else</span> <span class="s1">'='</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">¶</a> </div> <p>Compiles the range's source variables -- where it starts and where it ends.
|
||||
But only if they need to be cached to avoid double evaluation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileVariables</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o = </span><span class="nx">merge</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">top</span><span class="o">:</span> <span class="kc">true</span><span class="p">)</span>
|
||||
<span class="p">[</span><span class="nx">@from</span><span class="p">,</span> <span class="nx">@fromVar</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@from</span><span class="p">.</span><span class="nx">cache</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
@@ -431,7 +457,7 @@ But only if they need to be cached to avoid double evaluation.</p> <
|
||||
<span class="p">[</span><span class="nx">@fromNum</span><span class="p">,</span> <span class="nx">@toNum</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">@fromVar</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLENUM</span><span class="p">),</span> <span class="nx">@toVar</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLENUM</span><span class="p">)]</span>
|
||||
<span class="nv">parts = </span><span class="p">[]</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@from</span> <span class="k">if</span> <span class="nx">@from</span> <span class="o">isnt</span> <span class="nx">@fromVar</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@to</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">¶</a> </div> <p>When compiled normally, the range returns the contents of the <em>for loop</em>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@to</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">¶</a> </div> <p>When compiled normally, the range returns the contents of the <em>for loop</em>
|
||||
needed to iterate over the values in the range. Used by comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@compileVariables</span> <span class="nx">o</span>
|
||||
<span class="k">return</span> <span class="nx">@compileArray</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">o</span><span class="p">.</span><span class="nx">index</span>
|
||||
@@ -439,11 +465,10 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
|
||||
<span class="nv">idx = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">'index'</span>
|
||||
<span class="nv">step = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">'step'</span>
|
||||
<span class="nv">vars = </span><span class="s2">"#{idx} = #{@from}"</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span> <span class="k">then</span> <span class="s2">", #{@to}"</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nv">intro = </span><span class="s2">"(#{@fromVar} <= #{@toVar} ? #{idx}"</span>
|
||||
<span class="nv">compare = </span><span class="s2">"#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})"</span>
|
||||
<span class="nv">stepPart = </span><span class="k">if</span> <span class="nx">step</span> <span class="k">then</span> <span class="nx">step</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="k">else</span> <span class="s1">'1'</span>
|
||||
<span class="nv">incr = </span><span class="k">if</span> <span class="nx">step</span> <span class="k">then</span> <span class="s2">"#{idx} += #{stepPart}"</span> <span class="k">else</span> <span class="s2">"#{intro} += #{stepPart} : #{idx} -= #{stepPart})"</span>
|
||||
<span class="s2">"#{vars}; #{compare}; #{incr}"</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">¶</a> </div> <p>Compile a simple range comprehension, with integers.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSimple</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">cond = </span><span class="s2">"#{@fromVar} <= #{@toVar}"</span>
|
||||
<span class="nv">compare = </span><span class="s2">"#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"</span>
|
||||
<span class="nv">incr = </span><span class="k">if</span> <span class="nx">step</span> <span class="k">then</span> <span class="s2">"#{idx} += #{step.compile(o)}"</span> <span class="k">else</span> <span class="s2">"#{cond} ? #{idx}++ : #{idx}--"</span>
|
||||
<span class="s2">"#{vars}; #{compare}; #{incr}"</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">¶</a> </div> <p>Compile a simple range comprehension, with integers.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSimple</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">[</span><span class="nx">from</span><span class="p">,</span> <span class="nx">to</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="o">+</span><span class="nx">@fromNum</span><span class="p">,</span> <span class="o">+</span><span class="nx">@toNum</span><span class="p">]</span>
|
||||
<span class="nv">idx = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">'index'</span>
|
||||
<span class="nv">step = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">'step'</span>
|
||||
@@ -451,7 +476,7 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
|
||||
<span class="k">if</span> <span class="nx">from</span> <span class="o"><=</span> <span class="nx">to</span>
|
||||
<span class="s2">"#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "</span><span class="c1">#{idx}++"}"</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s2">"#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "</span><span class="c1">#{idx}--"}"</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">¶</a> </div> <p>When used as a value, expand the range into the equivalent array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileArray</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="s2">"#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "</span><span class="c1">#{idx}--"}"</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">¶</a> </div> <p>When used as a value, expand the range into the equivalent array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileArray</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@fromNum</span> <span class="o">and</span> <span class="nx">@toNum</span> <span class="o">and</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">@fromNum</span> <span class="o">-</span> <span class="nx">@toNum</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">20</span>
|
||||
<span class="nv">range = </span><span class="p">[</span><span class="o">+</span><span class="nx">@fromNum</span><span class="p">..</span><span class="o">+</span><span class="nx">@toNum</span><span class="p">]</span>
|
||||
<span class="nx">range</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@exclusive</span>
|
||||
@@ -462,20 +487,20 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
|
||||
<span class="nv">pre = </span><span class="s2">"\n#{idt}#{result} = [];"</span>
|
||||
<span class="k">if</span> <span class="nx">@fromNum</span> <span class="o">and</span> <span class="nx">@toNum</span>
|
||||
<span class="nv">o.index = </span><span class="nx">i</span>
|
||||
<span class="nv">body = </span><span class="nx">@compileSimple</span> <span class="nx">o</span>
|
||||
<span class="nv">body = </span><span class="nx">@compileSimple</span> <span class="nx">o</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">vars = </span><span class="s2">"#{i} = #{@from}"</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span> <span class="k">then</span> <span class="s2">", #{@to}"</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nv">clause = </span><span class="s2">"#{@fromVar} <= #{@toVar} ?"</span>
|
||||
<span class="nv">body = </span><span class="s2">"var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"</span>
|
||||
<span class="nv">vars = </span><span class="s2">"#{i} = #{@from}"</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@to</span> <span class="o">isnt</span> <span class="nx">@toVar</span> <span class="k">then</span> <span class="s2">", #{@to}"</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nv">cond = </span><span class="s2">"#{@fromVar} <= #{@toVar}"</span>
|
||||
<span class="nv">body = </span><span class="s2">"var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--"</span>
|
||||
<span class="nv">post = </span><span class="s2">"{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"</span>
|
||||
<span class="s2">"(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)"</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">¶</a> </div> <h3>Slice</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">¶</a> </div> <p>An array slice literal. Unlike JavaScript's <code>Array#slice</code>, the second parameter
|
||||
<span class="s2">"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this, arguments)"</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">¶</a> </div> <h3>Slice</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-68">¶</a> </div> <p>An array slice literal. Unlike JavaScript's <code>Array#slice</code>, the second parameter
|
||||
specifies the index of the end of the slice, just as the first parameter
|
||||
is the index of the beginning.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Slice = </span><span class="nx">class</span> <span class="nx">Slice</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'range'</span><span class="p">]</span>
|
||||
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@range</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">super</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-68">¶</a> </div> <p>We have to be careful when trying to slice through the end of the array,
|
||||
<span class="k">super</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-69">¶</a> </div> <p>We have to be careful when trying to slice through the end of the array,
|
||||
<code>9e9</code> is used because not all implementations respect <code>undefined</code> or <code>1/0</code>.
|
||||
<code>9e9</code> should be safe because <code>9e9</code> > <code>2**32</code>, the max array length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">{</span><span class="nx">to</span><span class="p">,</span> <span class="nx">from</span><span class="p">}</span> <span class="o">=</span> <span class="nx">@range</span>
|
||||
@@ -488,7 +513,7 @@ is the index of the beginning.</p> </td> <td class="code
|
||||
<span class="p">(</span><span class="o">+</span><span class="nx">compiled</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s2">"(#{compiled} + 1) || 9e9"</span>
|
||||
<span class="s2">".slice(#{ fromStr }#{ toStr or '' })"</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-69">¶</a> </div> <h3>Obj</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-70">¶</a> </div> <p>An object literal, nothing fancy.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Obj = </span><span class="nx">class</span> <span class="nx">Obj</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="s2">".slice(#{ fromStr }#{ toStr or '' })"</span></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-70">¶</a> </div> <h3>Obj</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-71">¶</a> </div> <p>An object literal, nothing fancy.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Obj = </span><span class="nx">class</span> <span class="nx">Obj</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">props</span><span class="p">,</span> <span class="vi">@generated = </span><span class="kc">false</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@objects = @properties = </span><span class="nx">props</span> <span class="o">or</span> <span class="p">[]</span>
|
||||
|
||||
@@ -497,6 +522,9 @@ is the index of the beginning.</p> </td> <td class="code
|
||||
<span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">props = </span><span class="nx">@properties</span>
|
||||
<span class="k">return</span> <span class="p">(</span><span class="k">if</span> <span class="nx">@front</span> <span class="k">then</span> <span class="s1">'({})'</span> <span class="k">else</span> <span class="s1">'{}'</span><span class="p">)</span> <span class="nx">unless</span> <span class="nx">props</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="nx">@generated</span>
|
||||
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">props</span> <span class="k">when</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Value</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span> <span class="s1">'cannot have an implicit value in an implicit object'</span>
|
||||
<span class="nv">idt = </span><span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
|
||||
<span class="nv">lastNoncom = </span><span class="nx">@lastNonComment</span> <span class="nx">@properties</span>
|
||||
<span class="nv">props = </span><span class="k">for</span> <span class="nx">prop</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">props</span>
|
||||
@@ -520,17 +548,20 @@ is the index of the beginning.</p> </td> <td class="code
|
||||
|
||||
<span class="nx">assigns</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">prop</span> <span class="k">in</span> <span class="nx">@properties</span> <span class="k">when</span> <span class="nx">prop</span><span class="p">.</span><span class="nx">assigns</span> <span class="nx">name</span> <span class="k">then</span> <span class="k">return</span> <span class="kc">yes</span>
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-71">¶</a> </div> <h3>Arr</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-72">¶</a> </div> <p>An array literal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Arr = </span><span class="nx">class</span> <span class="nx">Arr</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-72">¶</a> </div> <h3>Arr</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-73">¶</a> </div> <p>An array literal.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Arr = </span><span class="nx">class</span> <span class="nx">Arr</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">objs</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@objects = </span><span class="nx">objs</span> <span class="o">or</span> <span class="p">[]</span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'objects'</span><span class="p">]</span>
|
||||
|
||||
<span class="nx">filterImplicitObjects</span><span class="o">:</span> <span class="nx">Call</span><span class="o">::</span><span class="nx">filterImplicitObjects</span>
|
||||
|
||||
<span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="s1">'[]'</span> <span class="nx">unless</span> <span class="nx">@objects</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
|
||||
<span class="k">return</span> <span class="nx">code</span> <span class="k">if</span> <span class="nv">code = </span><span class="nx">Splat</span><span class="p">.</span><span class="nx">compileSplattedArray</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">@objects</span>
|
||||
<span class="nv">code = </span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">obj</span> <span class="k">in</span> <span class="nx">@objects</span><span class="p">).</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
<span class="nv">objs = </span><span class="nx">@filterImplicitObjects</span> <span class="nx">@objects</span>
|
||||
<span class="k">return</span> <span class="nx">code</span> <span class="k">if</span> <span class="nv">code = </span><span class="nx">Splat</span><span class="p">.</span><span class="nx">compileSplattedArray</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">objs</span>
|
||||
<span class="nv">code = </span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">obj</span> <span class="k">in</span> <span class="nx">objs</span><span class="p">).</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
<span class="k">if</span> <span class="nx">code</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">'\n'</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span>
|
||||
<span class="s2">"[\n#{o.indent}#{code}\n#{@tab}]"</span>
|
||||
<span class="k">else</span>
|
||||
@@ -538,20 +569,20 @@ is the index of the beginning.</p> </td> <td class="code
|
||||
|
||||
<span class="nx">assigns</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">obj</span> <span class="k">in</span> <span class="nx">@objects</span> <span class="k">when</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">assigns</span> <span class="nx">name</span> <span class="k">then</span> <span class="k">return</span> <span class="kc">yes</span>
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-73">¶</a> </div> <h3>Class</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-74"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-74">¶</a> </div> <p>The CoffeeScript class definition.
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-74"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-74">¶</a> </div> <h3>Class</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-75"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-75">¶</a> </div> <p>The CoffeeScript class definition.
|
||||
Initialize a <strong>Class</strong> with its name, an optional superclass, and a
|
||||
list of prototype property assignments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Class = </span><span class="nx">class</span> <span class="nx">Class</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">,</span> <span class="vi">@body = </span><span class="k">new</span> <span class="nx">Expressions</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">,</span> <span class="vi">@body = </span><span class="k">new</span> <span class="nx">Block</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@boundFuncs = </span><span class="p">[]</span>
|
||||
<span class="vi">@body.classBody = </span><span class="kc">yes</span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'variable'</span><span class="p">,</span> <span class="s1">'parent'</span><span class="p">,</span> <span class="s1">'body'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-75"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-75">¶</a> </div> <p>Figure out the appropriate name for the constructor function of this class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">determineName</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'variable'</span><span class="p">,</span> <span class="s1">'parent'</span><span class="p">,</span> <span class="s1">'body'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-76"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-76">¶</a> </div> <p>Figure out the appropriate name for the constructor function of this class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">determineName</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">null</span> <span class="nx">unless</span> <span class="nx">@variable</span>
|
||||
<span class="nv">decl = </span><span class="k">if</span> <span class="nv">tail = </span><span class="nx">last</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">properties</span>
|
||||
<span class="nx">tail</span> <span class="k">instanceof</span> <span class="nx">Access</span> <span class="o">and</span> <span class="nx">tail</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">value</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">value</span>
|
||||
<span class="nx">decl</span> <span class="o">and=</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">decl</span><span class="p">)</span> <span class="o">and</span> <span class="nx">decl</span></pre></div> </td> </tr> <tr id="section-76"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-76">¶</a> </div> <p>For all <code>this</code>-references and bound functions in the class definition,
|
||||
<span class="nx">decl</span> <span class="o">and=</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">decl</span><span class="p">)</span> <span class="o">and</span> <span class="nx">decl</span></pre></div> </td> </tr> <tr id="section-77"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-77">¶</a> </div> <p>For all <code>this</code>-references and bound functions in the class definition,
|
||||
<code>this</code> is the Class being constructed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">setContext</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@body</span><span class="p">.</span><span class="nx">traverseChildren</span> <span class="kc">false</span><span class="p">,</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">classBody</span>
|
||||
@@ -559,12 +590,12 @@ list of prototype property assignments.</p> </td> <td cl
|
||||
<span class="nv">node.value = </span><span class="nx">name</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Code</span>
|
||||
<span class="nv">node.klass = </span><span class="nx">name</span>
|
||||
<span class="nv">node.context = </span><span class="nx">name</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span></pre></div> </td> </tr> <tr id="section-77"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-77">¶</a> </div> <p>Ensure that all functions bound to the instance are proxied in the
|
||||
<span class="nv">node.context = </span><span class="nx">name</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span></pre></div> </td> </tr> <tr id="section-78"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-78">¶</a> </div> <p>Ensure that all functions bound to the instance are proxied in the
|
||||
constructor.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addBoundFunctions</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@boundFuncs</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">for</span> <span class="nx">bvar</span> <span class="k">in</span> <span class="nx">@boundFuncs</span>
|
||||
<span class="nv">bname = </span><span class="nx">bvar</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="nx">@ctor</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s2">"this.#{bname} = #{utility 'bind'}(this.#{bname}, this);"</span></pre></div> </td> </tr> <tr id="section-78"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-78">¶</a> </div> <p>Merge the properties from a top-level object as prototypal properties
|
||||
<span class="nx">@ctor</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s2">"this.#{bname} = #{utility 'bind'}(this.#{bname}, this);"</span></pre></div> </td> </tr> <tr id="section-79"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-79">¶</a> </div> <p>Merge the properties from a top-level object as prototypal properties
|
||||
on the class.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addProperties</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">,</span> <span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">props = </span><span class="nx">node</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="nv">assign = </span><span class="nx">props</span><span class="p">.</span><span class="nx">shift</span><span class="p">()</span>
|
||||
@@ -587,14 +618,14 @@ on the class.</p> </td> <td class="code">
|
||||
<span class="k">if</span> <span class="nx">func</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">func</span><span class="p">.</span><span class="nx">bound</span>
|
||||
<span class="nx">@boundFuncs</span><span class="p">.</span><span class="nx">push</span> <span class="nx">base</span>
|
||||
<span class="nv">func.bound = </span><span class="kc">no</span>
|
||||
<span class="nx">assign</span></pre></div> </td> </tr> <tr id="section-79"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-79">¶</a> </div> <p>Walk the body of the class, looking for prototype properties to be converted.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">walkBody</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">assign</span></pre></div> </td> </tr> <tr id="section-80"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-80">¶</a> </div> <p>Walk the body of the class, looking for prototype properties to be converted.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">walkBody</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@traverseChildren</span> <span class="kc">false</span><span class="p">,</span> <span class="p">(</span><span class="nx">child</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">child</span> <span class="k">instanceof</span> <span class="nx">Class</span>
|
||||
<span class="k">if</span> <span class="nx">child</span> <span class="k">instanceof</span> <span class="nx">Expressions</span>
|
||||
<span class="k">if</span> <span class="nx">child</span> <span class="k">instanceof</span> <span class="nx">Block</span>
|
||||
<span class="k">for</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nv">exps = </span><span class="nx">child</span><span class="p">.</span><span class="nx">expressions</span>
|
||||
<span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Value</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">isObject</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
|
||||
<span class="nx">exps</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@addProperties</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">name</span>
|
||||
<span class="nv">child.expressions = exps = </span><span class="nx">flatten</span> <span class="nx">exps</span></pre></div> </td> </tr> <tr id="section-80"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-80">¶</a> </div> <p>Make sure that a constructor is defined for the class, and properly
|
||||
<span class="nv">child.expressions = exps = </span><span class="nx">flatten</span> <span class="nx">exps</span></pre></div> </td> </tr> <tr id="section-81"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-81">¶</a> </div> <p>Make sure that a constructor is defined for the class, and properly
|
||||
configured.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">ensureConstructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">@ctor</span>
|
||||
<span class="vi">@ctor = </span><span class="k">new</span> <span class="nx">Code</span>
|
||||
@@ -602,7 +633,7 @@ configured.</p> </td> <td class="code"> <d
|
||||
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="nx">@ctor</span>
|
||||
<span class="vi">@ctor.ctor = @ctor.name = </span><span class="nx">name</span>
|
||||
<span class="vi">@ctor.klass = </span><span class="kc">null</span>
|
||||
<span class="vi">@ctor.noReturn = </span><span class="kc">yes</span></pre></div> </td> </tr> <tr id="section-81"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-81">¶</a> </div> <p>Instead of generating the JavaScript string directly, we build up the
|
||||
<span class="vi">@ctor.noReturn = </span><span class="kc">yes</span></pre></div> </td> </tr> <tr id="section-82"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-82">¶</a> </div> <p>Instead of generating the JavaScript string directly, we build up the
|
||||
equivalent syntax tree and compile that, in pieces. You can see the
|
||||
constructor, property assignments, and inheritance getting built out below.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">decl = </span><span class="nx">@determineName</span><span class="p">()</span>
|
||||
@@ -611,17 +642,17 @@ constructor, property assignments, and inheritance getting built out below.</p>
|
||||
|
||||
<span class="nx">@setContext</span> <span class="nx">name</span>
|
||||
<span class="nx">@walkBody</span> <span class="nx">name</span>
|
||||
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Extends</span> <span class="nx">lname</span><span class="p">,</span> <span class="nx">@parent</span> <span class="k">if</span> <span class="nx">@parent</span>
|
||||
<span class="nx">@ensureConstructor</span> <span class="nx">name</span>
|
||||
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">splice</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Extends</span><span class="p">(</span><span class="nx">lname</span><span class="p">,</span> <span class="nx">@parent</span><span class="p">)</span> <span class="k">if</span> <span class="nx">@parent</span>
|
||||
<span class="nx">@body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">push</span> <span class="nx">lname</span>
|
||||
<span class="nx">@addBoundFunctions</span> <span class="nx">o</span>
|
||||
|
||||
<span class="nv">klass = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">Closure</span><span class="p">.</span><span class="nx">wrap</span><span class="p">(</span><span class="nx">@body</span><span class="p">),</span> <span class="kc">true</span>
|
||||
<span class="nv">klass = </span><span class="k">new</span> <span class="nx">Assign</span> <span class="nx">@variable</span><span class="p">,</span> <span class="nx">klass</span> <span class="k">if</span> <span class="nx">@variable</span>
|
||||
<span class="nx">klass</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-82"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-82">¶</a> </div> <h3>Assign</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-83"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-83">¶</a> </div> <p>The <strong>Assign</strong> is used to assign a local variable to value, or to set the
|
||||
<span class="nx">klass</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-83"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-83">¶</a> </div> <h3>Assign</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-84"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-84">¶</a> </div> <p>The <strong>Assign</strong> is used to assign a local variable to value, or to set the
|
||||
property of an object -- including within object literals.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Assign = </span><span class="nx">class</span> <span class="nx">Assign</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@variable</span><span class="p">,</span> <span class="nx">@value</span><span class="p">,</span> <span class="nx">@context</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@param = </span><span class="nx">options</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">param</span></pre></div> </td> </tr> <tr id="section-84"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-84">¶</a> </div> <p>Matchers for detecting class/method names</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">METHOD_DEF</span><span class="o">:</span> <span class="sr">/^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/</span>
|
||||
<span class="vi">@param = </span><span class="nx">options</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">param</span></pre></div> </td> </tr> <tr id="section-85"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-85">¶</a> </div> <p>Matchers for detecting class/method names</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">METHOD_DEF</span><span class="o">:</span> <span class="sr">/^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w\x7f-\uffff]*)$/</span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'variable'</span><span class="p">,</span> <span class="s1">'value'</span><span class="p">]</span>
|
||||
|
||||
@@ -629,7 +660,7 @@ property of an object -- including within object literals.</p> </td>
|
||||
<span class="err">@</span><span class="p">[</span><span class="k">if</span> <span class="nx">@context</span> <span class="o">is</span> <span class="s1">'object'</span> <span class="k">then</span> <span class="s1">'value'</span> <span class="k">else</span> <span class="s1">'variable'</span><span class="p">].</span><span class="nx">assigns</span> <span class="nx">name</span>
|
||||
|
||||
<span class="nx">unfoldSoak</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">unfoldSoak</span> <span class="nx">o</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="s1">'variable'</span></pre></div> </td> </tr> <tr id="section-85"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-85">¶</a> </div> <p>Compile an assignment, delegating to <code>compilePatternMatch</code> or
|
||||
<span class="nx">unfoldSoak</span> <span class="nx">o</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="s1">'variable'</span></pre></div> </td> </tr> <tr id="section-86"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-86">¶</a> </div> <p>Compile an assignment, delegating to <code>compilePatternMatch</code> or
|
||||
<code>compileSplice</code> if appropriate. Keep track of the name of the base object
|
||||
we've been assigned to, for correct internal references. If the variable
|
||||
has not been seen yet within the current scope, declare it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -638,29 +669,31 @@ has not been seen yet within the current scope, declare it.</p> </td
|
||||
<span class="k">return</span> <span class="nx">@compileSplice</span> <span class="nx">o</span> <span class="k">if</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">isSplice</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="nx">@compileConditional</span> <span class="nx">o</span> <span class="k">if</span> <span class="nx">@context</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'||='</span><span class="p">,</span> <span class="s1">'&&='</span><span class="p">,</span> <span class="s1">'?='</span><span class="p">]</span>
|
||||
<span class="nv">name = </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
<span class="k">if</span> <span class="nx">@value</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nv">match = </span><span class="nx">@METHOD_DEF</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">name</span>
|
||||
<span class="vi">@value.name = </span><span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="vi">@value.klass = </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">val = </span><span class="nx">@value</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
<span class="k">return</span> <span class="s2">"#{name}: #{val}"</span> <span class="k">if</span> <span class="nx">@context</span> <span class="o">is</span> <span class="s1">'object'</span>
|
||||
<span class="nx">unless</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">isAssignable</span><span class="p">()</span>
|
||||
<span class="nx">unless</span> <span class="nx">@context</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">isAssignable</span><span class="p">()</span>
|
||||
<span class="k">throw</span> <span class="nx">SyntaxError</span> <span class="s2">"\"#{ @variable.compile o }\" cannot be assigned."</span>
|
||||
<span class="nx">unless</span> <span class="nx">@context</span> <span class="o">or</span> <span class="nx">isValue</span> <span class="o">and</span> <span class="p">(</span><span class="nx">@variable</span><span class="p">.</span><span class="nx">namespaced</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">hasProperties</span><span class="p">())</span>
|
||||
<span class="k">if</span> <span class="nx">@param</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">add</span> <span class="nx">name</span><span class="p">,</span> <span class="s1">'var'</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">find</span> <span class="nx">name</span>
|
||||
<span class="k">if</span> <span class="nx">@value</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nv">match = </span><span class="nx">@METHOD_DEF</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">name</span>
|
||||
<span class="vi">@value.name = </span><span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="vi">@value.klass = </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">val = </span><span class="nx">@value</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
<span class="k">return</span> <span class="s2">"#{name}: #{val}"</span> <span class="k">if</span> <span class="nx">@context</span> <span class="o">is</span> <span class="s1">'object'</span>
|
||||
<span class="nv">val = </span><span class="nx">name</span> <span class="o">+</span> <span class="s2">" #{ @context or '=' } "</span> <span class="o">+</span> <span class="nx">val</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><=</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="nx">val</span> <span class="k">else</span> <span class="s2">"(#{val})"</span></pre></div> </td> </tr> <tr id="section-86"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-86">¶</a> </div> <p>Brief implementation of recursive pattern matching, when assigning array or
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><=</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="nx">val</span> <span class="k">else</span> <span class="s2">"(#{val})"</span></pre></div> </td> </tr> <tr id="section-87"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-87">¶</a> </div> <p>Brief implementation of recursive pattern matching, when assigning array or
|
||||
object literals to a value. Peeks at their properties to assign inner names.
|
||||
See the <a href="http://wiki.ecmascript.org/doku.php?id=harmony:destructuring">ECMAScript Harmony Wiki</a>
|
||||
for details.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compilePatternMatch</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">top = </span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">is</span> <span class="nx">LEVEL_TOP</span>
|
||||
<span class="p">{</span><span class="nx">value</span><span class="p">}</span> <span class="o">=</span> <span class="k">this</span>
|
||||
<span class="p">{</span><span class="nx">objects</span><span class="p">}</span> <span class="o">=</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">base</span>
|
||||
<span class="k">return</span> <span class="nx">value</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span> <span class="nx">unless</span> <span class="nv">olen = </span><span class="nx">objects</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">unless</span> <span class="nv">olen = </span><span class="nx">objects</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">code = </span><span class="nx">value</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_OP</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span>
|
||||
<span class="nv">isObject = </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">isObject</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">top</span> <span class="o">and</span> <span class="nx">olen</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="p">(</span><span class="nv">obj = </span><span class="nx">objects</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Splat</span></pre></div> </td> </tr> <tr id="section-87"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-87">¶</a> </div> <p>Unroll simplest cases: <code>{v} = x</code> -> <code>v = x.v</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span>
|
||||
<span class="k">if</span> <span class="nx">top</span> <span class="o">and</span> <span class="nx">olen</span> <span class="o">is</span> <span class="mi">1</span> <span class="o">and</span> <span class="p">(</span><span class="nv">obj = </span><span class="nx">objects</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Splat</span></pre></div> </td> </tr> <tr id="section-88"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-88">¶</a> </div> <p>Unroll simplest cases: <code>{v} = x</code> -> <code>v = x.v</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span>
|
||||
<span class="p">{</span><span class="nx">variable</span><span class="o">:</span> <span class="p">{</span><span class="nx">base</span><span class="o">:</span> <span class="nx">idx</span><span class="p">},</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">obj</span><span class="p">}</span> <span class="o">=</span> <span class="nx">obj</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">Parens</span>
|
||||
@@ -680,10 +713,10 @@ for details.</p> </td> <td class="code"> <
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">vvar</span><span class="p">)</span> <span class="o">or</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">assigns</span><span class="p">(</span><span class="nx">vvar</span><span class="p">)</span>
|
||||
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span> <span class="s2">"#{ ref = o.scope.freeVariable 'ref' } = #{vvar}"</span>
|
||||
<span class="nv">vvar = </span><span class="nx">ref</span>
|
||||
<span class="k">for</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">objects</span></pre></div> </td> </tr> <tr id="section-88"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-88">¶</a> </div> <p>A regular array pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">idx = </span><span class="nx">i</span>
|
||||
<span class="k">for</span> <span class="nx">obj</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">objects</span></pre></div> </td> </tr> <tr id="section-89"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-89">¶</a> </div> <p>A regular array pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">idx = </span><span class="nx">i</span>
|
||||
<span class="k">if</span> <span class="nx">isObject</span>
|
||||
<span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span></pre></div> </td> </tr> <tr id="section-89"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-89">¶</a> </div> <p>A regular object pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">{</span><span class="nx">variable</span><span class="o">:</span> <span class="p">{</span><span class="nx">base</span><span class="o">:</span> <span class="nx">idx</span><span class="p">},</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">obj</span><span class="p">}</span> <span class="o">=</span> <span class="nx">obj</span>
|
||||
<span class="k">else</span></pre></div> </td> </tr> <tr id="section-90"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-90">¶</a> </div> <p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">Parens</span>
|
||||
<span class="k">if</span> <span class="nx">obj</span> <span class="k">instanceof</span> <span class="nx">Assign</span></pre></div> </td> </tr> <tr id="section-90"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-90">¶</a> </div> <p>A regular object pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">{</span><span class="nx">variable</span><span class="o">:</span> <span class="p">{</span><span class="nx">base</span><span class="o">:</span> <span class="nx">idx</span><span class="p">},</span> <span class="nx">value</span><span class="o">:</span> <span class="nx">obj</span><span class="p">}</span> <span class="o">=</span> <span class="nx">obj</span>
|
||||
<span class="k">else</span></pre></div> </td> </tr> <tr id="section-91"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-91">¶</a> </div> <p>A shorthand <code>{a, b, @c} = val</code> pattern-match.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">base</span> <span class="k">instanceof</span> <span class="nx">Parens</span>
|
||||
<span class="p">[</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">idx</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">unwrapAll</span><span class="p">()).</span><span class="nx">cacheReference</span> <span class="nx">o</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">idx = </span><span class="k">if</span> <span class="nx">obj</span><span class="p">.</span><span class="k">this</span> <span class="k">then</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">properties</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span> <span class="k">else</span> <span class="nx">obj</span>
|
||||
@@ -710,11 +743,11 @@ for details.</p> </td> <td class="code"> <
|
||||
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">val</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="nx">param</span><span class="o">:</span> <span class="nx">@param</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span>
|
||||
<span class="nx">assigns</span><span class="p">.</span><span class="nx">push</span> <span class="nx">vvar</span> <span class="nx">unless</span> <span class="nx">top</span>
|
||||
<span class="nv">code = </span><span class="nx">assigns</span><span class="p">.</span><span class="nx">join</span> <span class="s1">', '</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-91"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-91">¶</a> </div> <p>When compiling a conditional assignment, take care to ensure that the
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-92"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-92">¶</a> </div> <p>When compiling a conditional assignment, take care to ensure that the
|
||||
operands are only evaluated once, even though we have to reference them
|
||||
more than once.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileConditional</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">[</span><span class="nx">left</span><span class="p">,</span> <span class="nx">rite</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">cacheReference</span> <span class="nx">o</span>
|
||||
<span class="k">new</span> <span class="nx">Op</span><span class="p">(</span><span class="nx">@context</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="nx">left</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">rite</span><span class="p">,</span> <span class="nx">@value</span><span class="p">,</span> <span class="s1">'='</span><span class="p">)).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-92"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-92">¶</a> </div> <p>Compile the assignment from an array splice literal, using JavaScript's
|
||||
<span class="k">new</span> <span class="nx">Op</span><span class="p">(</span><span class="nx">@context</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="nx">left</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">rite</span><span class="p">,</span> <span class="nx">@value</span><span class="p">,</span> <span class="s1">'='</span><span class="p">)).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-93"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-93">¶</a> </div> <p>Compile the assignment from an array splice literal, using JavaScript's
|
||||
<code>Array#splice</code> method.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileSplice</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">{</span><span class="nx">range</span><span class="o">:</span> <span class="p">{</span><span class="nx">from</span><span class="p">,</span> <span class="nx">to</span><span class="p">,</span> <span class="nx">exclusive</span><span class="p">}}</span> <span class="o">=</span> <span class="nx">@variable</span><span class="p">.</span><span class="nx">properties</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nv">name = </span><span class="nx">@variable</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
@@ -730,12 +763,12 @@ more than once.</p> </td> <td class="code">
|
||||
<span class="nv">to = </span><span class="s2">"9e9"</span>
|
||||
<span class="p">[</span><span class="nx">valDef</span><span class="p">,</span> <span class="nx">valRef</span><span class="p">]</span> <span class="o">=</span> <span class="nx">@value</span><span class="p">.</span><span class="nx">cache</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
<span class="nv">code = </span><span class="s2">"[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}"</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">></span> <span class="nx">LEVEL_TOP</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-93"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-93">¶</a> </div> <h3>Code</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-94"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-94">¶</a> </div> <p>A function definition. This is the only node that creates a new Scope.
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">></span> <span class="nx">LEVEL_TOP</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-94"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-94">¶</a> </div> <h3>Code</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-95"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-95">¶</a> </div> <p>A function definition. This is the only node that creates a new Scope.
|
||||
When for the purposes of walking the contents of a function body, the Code
|
||||
has no <em>children</em> -- they're within the inner scope.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Code = </span><span class="nx">class</span> <span class="nx">Code</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">params</span><span class="p">,</span> <span class="nx">body</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="vi">@params = </span><span class="nx">params</span> <span class="o">or</span> <span class="p">[]</span>
|
||||
<span class="vi">@body = </span><span class="nx">body</span> <span class="o">or</span> <span class="k">new</span> <span class="nx">Expressions</span>
|
||||
<span class="vi">@body = </span><span class="nx">body</span> <span class="o">or</span> <span class="k">new</span> <span class="nx">Block</span>
|
||||
<span class="vi">@bound = </span><span class="nx">tag</span> <span class="o">is</span> <span class="s1">'boundfunc'</span>
|
||||
<span class="vi">@context = </span><span class="s1">'this'</span> <span class="k">if</span> <span class="nx">@bound</span>
|
||||
|
||||
@@ -743,7 +776,7 @@ has no <em>children</em> -- they're within the inner scope.</p> </td
|
||||
|
||||
<span class="nx">isStatement</span><span class="o">:</span> <span class="o">-></span> <span class="o">!!</span><span class="nx">@ctor</span>
|
||||
|
||||
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-95"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-95">¶</a> </div> <p>Compilation creates a new scope unless explicitly asked to share with the
|
||||
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-96"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-96">¶</a> </div> <p>Compilation creates a new scope unless explicitly asked to share with the
|
||||
outer scope. Handles splat parameters in the parameter list by peeking at
|
||||
the JavaScript <code>arguments</code> objects. If the function is bound with the <code>=></code>
|
||||
arrow, generates a wrapper that saves the current value of <code>this</code> through
|
||||
@@ -752,10 +785,10 @@ a closure.</p> </td> <td class="code"> <di
|
||||
<span class="nv">o.scope.shared = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">'sharedScope'</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
|
||||
<span class="k">delete</span> <span class="nx">o</span><span class="p">.</span><span class="nx">bare</span>
|
||||
<span class="k">delete</span> <span class="nx">o</span><span class="p">.</span><span class="nx">globals</span>
|
||||
<span class="nv">vars = </span><span class="p">[]</span>
|
||||
<span class="nv">exprs = </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">param</span> <span class="k">in</span> <span class="nx">@params</span> <span class="k">when</span> <span class="nx">param</span><span class="p">.</span><span class="nx">splat</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">add</span> <span class="nx">param</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">value</span><span class="p">,</span> <span class="s1">'var'</span> <span class="k">if</span> <span class="nx">param</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">value</span>
|
||||
<span class="nv">splats = </span><span class="k">new</span> <span class="nx">Assign</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Arr</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">asReference</span> <span class="nx">o</span> <span class="k">for</span> <span class="nx">p</span> <span class="k">in</span> <span class="nx">@params</span><span class="p">)),</span>
|
||||
<span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'arguments'</span>
|
||||
<span class="k">break</span>
|
||||
@@ -784,9 +817,9 @@ a closure.</p> </td> <td class="code"> <di
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="s1">'}'</span>
|
||||
<span class="k">return</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="nx">code</span> <span class="k">if</span> <span class="nx">@ctor</span>
|
||||
<span class="k">return</span> <span class="nx">utility</span><span class="p">(</span><span class="s1">'bind'</span><span class="p">)</span> <span class="o">+</span> <span class="s2">"(#{code}, #{@context})"</span> <span class="k">if</span> <span class="nx">@bound</span>
|
||||
<span class="k">if</span> <span class="nx">@front</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-96"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-96">¶</a> </div> <p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope boundaries
|
||||
<span class="k">if</span> <span class="nx">@front</span> <span class="o">or</span> <span class="p">(</span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_ACCESS</span><span class="p">)</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-97"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-97">¶</a> </div> <p>Short-circuit <code>traverseChildren</code> method to prevent it from crossing scope boundaries
|
||||
unless <code>crossScope</code> is <code>true</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">traverseChildren</span><span class="o">:</span> <span class="p">(</span><span class="nx">crossScope</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">super</span><span class="p">(</span><span class="nx">crossScope</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="k">if</span> <span class="nx">crossScope</span></pre></div> </td> </tr> <tr id="section-97"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-97">¶</a> </div> <h3>Param</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-98">¶</a> </div> <p>A parameter in a function definition. Beyond a typical Javascript parameter,
|
||||
<span class="k">super</span><span class="p">(</span><span class="nx">crossScope</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="k">if</span> <span class="nx">crossScope</span></pre></div> </td> </tr> <tr id="section-98"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-98">¶</a> </div> <h3>Param</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-99">¶</a> </div> <p>A parameter in a function definition. Beyond a typical Javascript parameter,
|
||||
these parameters can also attach themselves to the context of the function,
|
||||
as well as be a splat, gathering up a group of parameters into an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Param = </span><span class="nx">class</span> <span class="nx">Param</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@name</span><span class="p">,</span> <span class="nx">@value</span><span class="p">,</span> <span class="nx">@splat</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -809,7 +842,7 @@ as well as be a splat, gathering up a group of parameters into an array.</p>
|
||||
<span class="vi">@reference = </span><span class="nx">node</span>
|
||||
|
||||
<span class="nx">isComplex</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@name</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-99"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-99">¶</a> </div> <h3>Splat</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-100">¶</a> </div> <p>A splat, either as a parameter to a function, an argument to a call,
|
||||
<span class="nx">@name</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-100"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-100">¶</a> </div> <h3>Splat</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-101">¶</a> </div> <p>A splat, either as a parameter to a function, an argument to a call,
|
||||
or as part of a destructuring assignment.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Splat = </span><span class="nx">class</span> <span class="nx">Splat</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'name'</span><span class="p">]</span>
|
||||
@@ -823,7 +856,7 @@ or as part of a destructuring assignment.</p> </td> <td
|
||||
<span class="nx">@name</span><span class="p">.</span><span class="nx">assigns</span> <span class="nx">name</span>
|
||||
|
||||
<span class="nx">compile</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@index</span><span class="o">?</span> <span class="k">then</span> <span class="nx">@compileParam</span> <span class="nx">o</span> <span class="k">else</span> <span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-101"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-101">¶</a> </div> <p>Utility function that converts arbitrary number of elements, mixed with
|
||||
<span class="k">if</span> <span class="nx">@index</span><span class="o">?</span> <span class="k">then</span> <span class="nx">@compileParam</span> <span class="nx">o</span> <span class="k">else</span> <span class="nx">@name</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-102">¶</a> </div> <p>Utility function that converts arbitrary number of elements, mixed with
|
||||
splats, to a proper array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">@compileSplattedArray</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">list</span><span class="p">,</span> <span class="nx">apply</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">index = </span><span class="o">-</span><span class="mi">1</span>
|
||||
<span class="k">continue</span> <span class="k">while</span> <span class="p">(</span><span class="nv">node = </span><span class="nx">list</span><span class="p">[</span><span class="o">++</span><span class="nx">index</span><span class="p">])</span> <span class="o">and</span> <span class="nx">node</span> <span class="o">not</span> <span class="k">instanceof</span> <span class="nx">Splat</span>
|
||||
@@ -840,7 +873,7 @@ splats, to a proper array.</p> </td> <td class="code">
|
||||
<span class="k">else</span> <span class="s2">"[#{code}]"</span>
|
||||
<span class="k">return</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="s2">".concat(#{ args.slice(1).join ', ' })"</span> <span class="k">if</span> <span class="nx">index</span> <span class="o">is</span> <span class="mi">0</span>
|
||||
<span class="nv">base = </span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span> <span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">list</span><span class="p">.</span><span class="nx">slice</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span>
|
||||
<span class="s2">"[#{ base.join ', ' }].concat(#{ args.join ', ' })"</span></pre></div> </td> </tr> <tr id="section-102"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-102">¶</a> </div> <h3>While</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-103"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-103">¶</a> </div> <p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
||||
<span class="s2">"[#{ base.join ', ' }].concat(#{ args.join ', ' })"</span></pre></div> </td> </tr> <tr id="section-103"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-103">¶</a> </div> <h3>While</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-104"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-104">¶</a> </div> <p>A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
||||
it, all other loops can be manufactured. Useful in cases where you need more
|
||||
flexibility or more speed than a comprehension can provide.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.While = </span><span class="nx">class</span> <span class="nx">While</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">condition</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -863,7 +896,7 @@ flexibility or more speed than a comprehension can provide.</p> </td
|
||||
<span class="k">return</span> <span class="kc">no</span> <span class="nx">unless</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">for</span> <span class="nx">node</span> <span class="k">in</span> <span class="nx">expressions</span>
|
||||
<span class="k">return</span> <span class="nx">node</span> <span class="k">if</span> <span class="nx">node</span><span class="p">.</span><span class="nx">jumps</span> <span class="nx">loop</span><span class="o">:</span> <span class="kc">yes</span>
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-104"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-104">¶</a> </div> <p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript
|
||||
<span class="kc">no</span></pre></div> </td> </tr> <tr id="section-105"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-105">¶</a> </div> <p>The main difference from a JavaScript <em>while</em> is that the CoffeeScript
|
||||
<em>while</em> can be used as a part of a larger expression -- while loops may
|
||||
return an array containing the computed result of each iteration.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
|
||||
@@ -876,27 +909,30 @@ return an array containing the computed result of each iteration.</p>
|
||||
<span class="nv">rvar = </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">freeVariable</span> <span class="s1">'results'</span>
|
||||
<span class="nv">set = </span><span class="s2">"#{@tab}#{rvar} = [];\n"</span>
|
||||
<span class="nv">body = </span><span class="nx">Push</span><span class="p">.</span><span class="nx">wrap</span> <span class="nx">rvar</span><span class="p">,</span> <span class="nx">body</span> <span class="k">if</span> <span class="nx">body</span>
|
||||
<span class="nv">body = </span><span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="k">new</span> <span class="nx">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@guard</span>
|
||||
<span class="nv">body = </span><span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="k">new</span> <span class="nx">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@guard</span>
|
||||
<span class="nv">body = </span><span class="s2">"\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"</span>
|
||||
<span class="nv">code = </span><span class="nx">set</span> <span class="o">+</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="s2">"while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"</span>
|
||||
<span class="k">if</span> <span class="nx">@returns</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="s2">"\n#{@tab}return #{rvar};"</span>
|
||||
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-105"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-105">¶</a> </div> <h3>Op</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-106"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-106">¶</a> </div> <p>Simple Arithmetic and logical operations. Performs some conversion from
|
||||
<span class="nx">code</span></pre></div> </td> </tr> <tr id="section-106"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-106">¶</a> </div> <h3>Op</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-107"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-107">¶</a> </div> <p>Simple Arithmetic and logical operations. Performs some conversion from
|
||||
CoffeeScript operations into their JavaScript equivalents.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Op = </span><span class="nx">class</span> <span class="nx">Op</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">op</span><span class="p">,</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">second</span><span class="p">,</span> <span class="nx">flip</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="k">new</span> <span class="nx">In</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">second</span> <span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">'in'</span>
|
||||
<span class="k">return</span> <span class="k">new</span> <span class="nx">Call</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">first</span><span class="p">.</span><span class="nx">params</span> <span class="o">or</span> <span class="p">[]</span> <span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">'do'</span>
|
||||
<span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">'do'</span>
|
||||
<span class="nv">call = </span><span class="k">new</span> <span class="nx">Call</span> <span class="nx">first</span><span class="p">,</span> <span class="nx">first</span><span class="p">.</span><span class="nx">params</span> <span class="o">or</span> <span class="p">[]</span>
|
||||
<span class="nv">call.do = </span><span class="kc">yes</span>
|
||||
<span class="k">return</span> <span class="nx">call</span>
|
||||
<span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">'new'</span>
|
||||
<span class="k">return</span> <span class="nx">first</span><span class="p">.</span><span class="nx">newInstance</span><span class="p">()</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Call</span>
|
||||
<span class="nv">first = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">first</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">first</span><span class="p">.</span><span class="nx">bound</span>
|
||||
<span class="k">return</span> <span class="nx">first</span><span class="p">.</span><span class="nx">newInstance</span><span class="p">()</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Call</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">first</span><span class="p">.</span><span class="nx">do</span>
|
||||
<span class="nv">first = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">first</span> <span class="k">if</span> <span class="nx">first</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">first</span><span class="p">.</span><span class="nx">bound</span> <span class="o">or</span> <span class="nx">first</span><span class="p">.</span><span class="nx">do</span>
|
||||
<span class="vi">@operator = </span><span class="nx">CONVERSIONS</span><span class="p">[</span><span class="nx">op</span><span class="p">]</span> <span class="o">or</span> <span class="nx">op</span>
|
||||
<span class="vi">@first = </span><span class="nx">first</span>
|
||||
<span class="vi">@second = </span><span class="nx">second</span>
|
||||
<span class="vi">@flip = </span><span class="o">!!</span><span class="nx">flip</span>
|
||||
<span class="k">return</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-107"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-107">¶</a> </div> <p>The map of conversions from CoffeeScript to JavaScript symbols.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">CONVERSIONS =</span>
|
||||
<span class="k">return</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-108"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-108">¶</a> </div> <p>The map of conversions from CoffeeScript to JavaScript symbols.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">CONVERSIONS =</span>
|
||||
<span class="s1">'=='</span><span class="o">:</span> <span class="s1">'==='</span>
|
||||
<span class="s1">'!='</span><span class="o">:</span> <span class="s1">'!=='</span>
|
||||
<span class="s1">'of'</span><span class="o">:</span> <span class="s1">'in'</span></pre></div> </td> </tr> <tr id="section-108"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-108">¶</a> </div> <p>The map of invertible operators.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">INVERSIONS =</span>
|
||||
<span class="s1">'of'</span><span class="o">:</span> <span class="s1">'in'</span></pre></div> </td> </tr> <tr id="section-109"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-109">¶</a> </div> <p>The map of invertible operators.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">INVERSIONS =</span>
|
||||
<span class="s1">'!=='</span><span class="o">:</span> <span class="s1">'==='</span>
|
||||
<span class="s1">'==='</span><span class="o">:</span> <span class="s1">'!=='</span>
|
||||
|
||||
@@ -905,7 +941,7 @@ CoffeeScript operations into their JavaScript equivalents.</p> </td>
|
||||
<span class="nx">isSimpleNumber</span><span class="o">:</span> <span class="nx">NO</span>
|
||||
|
||||
<span class="nx">isUnary</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="o">not</span> <span class="nx">@second</span></pre></div> </td> </tr> <tr id="section-109"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-109">¶</a> </div> <p>Am I capable of
|
||||
<span class="o">not</span> <span class="nx">@second</span></pre></div> </td> </tr> <tr id="section-110"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-110">¶</a> </div> <p>Am I capable of
|
||||
<a href="http://docs.python.org/reference/expressions.html#notin">Python-style comparison chaining</a>?</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">isChainable</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@operator</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="s1">'==='</span><span class="p">,</span> <span class="s1">'!=='</span><span class="p">]</span>
|
||||
|
||||
@@ -946,7 +982,7 @@ CoffeeScript operations into their JavaScript equivalents.</p> </td>
|
||||
<span class="vi">@first.front = </span><span class="nx">@front</span>
|
||||
<span class="nv">code = </span><span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span><span class="p">)</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="nx">@operator</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span>
|
||||
<span class="nx">@second</span><span class="p">.</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><=</span> <span class="nx">LEVEL_OP</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-110"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-110">¶</a> </div> <p>Mimic Python's chained comparisons when multiple comparison operators are
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><=</span> <span class="nx">LEVEL_OP</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-111"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-111">¶</a> </div> <p>Mimic Python's chained comparisons when multiple comparison operators are
|
||||
used sequentially. For example:</p>
|
||||
|
||||
<pre><code>bin/coffee -e 'console.log 50 < 65 > 10'
|
||||
@@ -959,21 +995,22 @@ true
|
||||
|
||||
<span class="nx">compileExistence</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">isComplex</span><span class="p">()</span>
|
||||
<span class="nv">ref = </span><span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">freeVariable</span> <span class="s1">'ref'</span>
|
||||
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="nx">ref</span><span class="p">),</span> <span class="nx">@first</span>
|
||||
<span class="nv">ref = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">freeVariable</span> <span class="s1">'ref'</span>
|
||||
<span class="nv">fst = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">@first</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">fst = </span><span class="nx">@first</span>
|
||||
<span class="nv">ref = </span><span class="nx">fst</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">+</span> <span class="s2">" ? #{ref} : #{ @second.compile o, LEVEL_LIST }"</span></pre></div> </td> </tr> <tr id="section-111"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-111">¶</a> </div> <p>Compile a unary <strong>Op</strong>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileUnary</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">ref = </span><span class="nx">fst</span>
|
||||
<span class="k">new</span> <span class="nx">If</span><span class="p">(</span><span class="k">new</span> <span class="nx">Existence</span><span class="p">(</span><span class="nx">fst</span><span class="p">),</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">type</span><span class="o">:</span> <span class="s1">'if'</span><span class="p">).</span><span class="nx">addElse</span><span class="p">(</span><span class="nx">@second</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span></pre></div> </td> </tr> <tr id="section-112"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-112">¶</a> </div> <p>Compile a unary <strong>Op</strong>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileUnary</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">parts = </span><span class="p">[</span><span class="nv">op = </span><span class="nx">@operator</span><span class="p">]</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="s1">' '</span> <span class="k">if</span> <span class="nx">op</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'new'</span><span class="p">,</span> <span class="s1">'typeof'</span><span class="p">,</span> <span class="s1">'delete'</span><span class="p">]</span> <span class="o">or</span>
|
||||
<span class="nx">op</span> <span class="k">in</span> <span class="p">[</span><span class="s1">'+'</span><span class="p">,</span> <span class="s1">'-'</span><span class="p">]</span> <span class="o">and</span> <span class="nx">@first</span> <span class="k">instanceof</span> <span class="nx">Op</span> <span class="o">and</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">operator</span> <span class="o">is</span> <span class="nx">op</span>
|
||||
<span class="vi">@first = </span><span class="k">new</span> <span class="nx">Parens</span> <span class="nx">@first</span> <span class="k">if</span> <span class="nx">op</span> <span class="o">is</span> <span class="s1">'new'</span> <span class="o">and</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">isStatement</span> <span class="nx">o</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">push</span> <span class="nx">@first</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">reverse</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@flip</span>
|
||||
<span class="nx">parts</span><span class="p">.</span><span class="nx">join</span> <span class="s1">''</span>
|
||||
|
||||
<span class="nx">toString</span><span class="o">:</span> <span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="nx">@operator</span></pre></div> </td> </tr> <tr id="section-112"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-112">¶</a> </div> <h3>In</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.In = </span><span class="nx">class</span> <span class="nx">In</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="nx">@operator</span></pre></div> </td> </tr> <tr id="section-113"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-113">¶</a> </div> <h3>In</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.In = </span><span class="nx">class</span> <span class="nx">In</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@object</span><span class="p">,</span> <span class="nx">@array</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'object'</span><span class="p">,</span> <span class="s1">'array'</span><span class="p">]</span>
|
||||
@@ -991,6 +1028,7 @@ true
|
||||
<span class="p">[</span><span class="nx">cmp</span><span class="p">,</span> <span class="nx">cnj</span><span class="p">]</span> <span class="o">=</span> <span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</span> <span class="p">[</span><span class="s1">' !== '</span><span class="p">,</span> <span class="s1">' && '</span><span class="p">]</span> <span class="k">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">tests = </span><span class="k">for</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">@array</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">objects</span>
|
||||
<span class="p">(</span><span class="k">if</span> <span class="nx">i</span> <span class="k">then</span> <span class="nx">ref</span> <span class="k">else</span> <span class="nx">sub</span><span class="p">)</span> <span class="o">+</span> <span class="nx">cmp</span> <span class="o">+</span> <span class="nx">item</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span>
|
||||
<span class="k">return</span> <span class="s1">'false'</span> <span class="k">if</span> <span class="nx">tests</span><span class="p">.</span><span class="nx">length</span> <span class="o">is</span> <span class="mi">0</span>
|
||||
<span class="nv">tests = </span><span class="nx">tests</span><span class="p">.</span><span class="nx">join</span> <span class="nx">cnj</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><</span> <span class="nx">LEVEL_OP</span> <span class="k">then</span> <span class="nx">tests</span> <span class="k">else</span> <span class="s2">"(#{tests})"</span>
|
||||
|
||||
@@ -1003,7 +1041,7 @@ true
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><</span> <span class="nx">LEVEL_LIST</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span>
|
||||
|
||||
<span class="nx">toString</span><span class="o">:</span> <span class="p">(</span><span class="nx">idt</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</span> <span class="s1">'!'</span> <span class="k">else</span> <span class="s1">''</span></pre></div> </td> </tr> <tr id="section-113"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-113">¶</a> </div> <h3>Try</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-114"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-114">¶</a> </div> <p>A classic <em>try/catch/finally</em> block.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Try = </span><span class="nx">class</span> <span class="nx">Try</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="k">super</span> <span class="nx">idt</span><span class="p">,</span> <span class="nx">@constructor</span><span class="p">.</span><span class="nx">name</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</span> <span class="s1">'!'</span> <span class="k">else</span> <span class="s1">''</span></pre></div> </td> </tr> <tr id="section-114"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-114">¶</a> </div> <h3>Try</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-115"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-115">¶</a> </div> <p>A classic <em>try/catch/finally</em> block.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Try = </span><span class="nx">class</span> <span class="nx">Try</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@attempt</span><span class="p">,</span> <span class="nx">@error</span><span class="p">,</span> <span class="nx">@recovery</span><span class="p">,</span> <span class="nx">@ensure</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'attempt'</span><span class="p">,</span> <span class="s1">'recovery'</span><span class="p">,</span> <span class="s1">'ensure'</span><span class="p">]</span>
|
||||
@@ -1015,7 +1053,7 @@ true
|
||||
<span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="vi">@attempt = </span><span class="nx">@attempt</span> <span class="p">.</span><span class="nx">makeReturn</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@attempt</span>
|
||||
<span class="vi">@recovery = </span><span class="nx">@recovery</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()</span> <span class="k">if</span> <span class="nx">@recovery</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-115"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-115">¶</a> </div> <p>Compilation is more or less as you would expect -- the <em>finally</em> clause
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-116"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-116">¶</a> </div> <p>Compilation is more or less as you would expect -- the <em>finally</em> clause
|
||||
is optional, the <em>catch</em> is not.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
|
||||
<span class="nv">errorPart = </span><span class="k">if</span> <span class="nx">@error</span> <span class="k">then</span> <span class="s2">" (#{ @error.compile o }) "</span> <span class="k">else</span> <span class="s1">' '</span>
|
||||
@@ -1027,16 +1065,16 @@ is optional, the <em>catch</em> is not.</p> </td> <td cl
|
||||
<span class="s2"> #{@tab}try {</span>
|
||||
<span class="s2"> #{ @attempt.compile o, LEVEL_TOP }</span>
|
||||
<span class="s2"> #{@tab}}#{ catchPart or '' }</span>
|
||||
<span class="s2"> """</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@ensure</span> <span class="k">then</span> <span class="s2">" finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}"</span> <span class="k">else</span> <span class="s1">''</span></pre></div> </td> </tr> <tr id="section-116"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-116">¶</a> </div> <h3>Throw</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-117"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-117">¶</a> </div> <p>Simple node to throw an exception.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Throw = </span><span class="nx">class</span> <span class="nx">Throw</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="s2"> """</span> <span class="o">+</span> <span class="k">if</span> <span class="nx">@ensure</span> <span class="k">then</span> <span class="s2">" finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}"</span> <span class="k">else</span> <span class="s1">''</span></pre></div> </td> </tr> <tr id="section-117"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-117">¶</a> </div> <h3>Throw</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-118"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-118">¶</a> </div> <p>Simple node to throw an exception.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Throw = </span><span class="nx">class</span> <span class="nx">Throw</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@expression</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'expression'</span><span class="p">]</span>
|
||||
|
||||
<span class="nx">isStatement</span><span class="o">:</span> <span class="nx">YES</span>
|
||||
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-118"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-118">¶</a> </div> <p>A <strong>Throw</strong> is already a return, of sorts...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">makeReturn</span><span class="o">:</span> <span class="nx">THIS</span>
|
||||
<span class="nx">jumps</span><span class="o">:</span> <span class="nx">NO</span></pre></div> </td> </tr> <tr id="section-119"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-119">¶</a> </div> <p>A <strong>Throw</strong> is already a return, of sorts...</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">makeReturn</span><span class="o">:</span> <span class="nx">THIS</span>
|
||||
|
||||
<span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@tab</span> <span class="o">+</span> <span class="s2">"throw #{ @expression.compile o };"</span></pre></div> </td> </tr> <tr id="section-119"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-119">¶</a> </div> <h3>Existence</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-120"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-120">¶</a> </div> <p>Checks a variable for existence -- not <em>null</em> and not <em>undefined</em>. This is
|
||||
<span class="nx">@tab</span> <span class="o">+</span> <span class="s2">"throw #{ @expression.compile o };"</span></pre></div> </td> </tr> <tr id="section-120"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-120">¶</a> </div> <h3>Existence</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-121"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-121">¶</a> </div> <p>Checks a variable for existence -- not <em>null</em> and not <em>undefined</em>. This is
|
||||
similar to <code>.nil?</code> in Ruby, and avoids having to consult a JavaScript truth
|
||||
table.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Existence = </span><span class="nx">class</span> <span class="nx">Existence</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@expression</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -1049,13 +1087,13 @@ table.</p> </td> <td class="code"> <div cl
|
||||
<span class="nv">code = </span><span class="nx">@expression</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_OP</span>
|
||||
<span class="nv">code = </span><span class="k">if</span> <span class="nx">IDENTIFIER</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">code</span><span class="p">)</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">o</span><span class="p">.</span><span class="nx">scope</span><span class="p">.</span><span class="nx">check</span> <span class="nx">code</span>
|
||||
<span class="k">if</span> <span class="nx">@negated</span>
|
||||
<span class="s2">"typeof #{code} == \"undefined\" || #{code} === null"</span>
|
||||
<span class="s2">"typeof #{code} === \"undefined\" || #{code} === null"</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s2">"typeof #{code} != \"undefined\" && #{code} !== null"</span>
|
||||
<span class="s2">"typeof #{code} !== \"undefined\" && #{code} !== null"</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">sym = </span><span class="k">if</span> <span class="nx">@negated</span> <span class="k">then</span> <span class="s1">'=='</span> <span class="k">else</span> <span class="s1">'!='</span>
|
||||
<span class="s2">"#{code} #{sym} null"</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><=</span> <span class="nx">LEVEL_COND</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-121"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-121">¶</a> </div> <h3>Parens</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-122"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-122">¶</a> </div> <p>An extra set of parentheses, specified explicitly in the source. At one time
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><=</span> <span class="nx">LEVEL_COND</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-122"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-122">¶</a> </div> <h3>Parens</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-123"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-123">¶</a> </div> <p>An extra set of parentheses, specified explicitly in the source. At one time
|
||||
we tried to clean up the results by detecting and removing redundant
|
||||
parentheses, but no longer -- you can put in as many as you please.</p>
|
||||
|
||||
@@ -1076,7 +1114,7 @@ parentheses, but no longer -- you can put in as many as you please.</p>
|
||||
<span class="nv">code = </span><span class="nx">expr</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_PAREN</span>
|
||||
<span class="nv">bare = </span><span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o"><</span> <span class="nx">LEVEL_OP</span> <span class="o">and</span> <span class="p">(</span><span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Op</span> <span class="o">or</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Call</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">For</span> <span class="o">and</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">returns</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="nx">bare</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-123"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-123">¶</a> </div> <h3>For</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-124"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-124">¶</a> </div> <p>CoffeeScript's replacement for the <em>for</em> loop is our array and object
|
||||
<span class="k">if</span> <span class="nx">bare</span> <span class="k">then</span> <span class="nx">code</span> <span class="k">else</span> <span class="s2">"(#{code})"</span></pre></div> </td> </tr> <tr id="section-124"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-124">¶</a> </div> <h3>For</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-125"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-125">¶</a> </div> <p>CoffeeScript's replacement for the <em>for</em> loop is our array and object
|
||||
comprehensions, that compile into <em>for</em> loops here. They also act as an
|
||||
expression, able to return the result of each filtered iteration.</p>
|
||||
|
||||
@@ -1085,7 +1123,7 @@ the current index of the loop as a second parameter. Unlike Ruby blocks,
|
||||
you can map and filter in a single pass.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.For = </span><span class="nx">class</span> <span class="nx">For</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">body</span><span class="p">,</span> <span class="nx">source</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">{</span><span class="nx">@source</span><span class="p">,</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">@step</span><span class="p">,</span> <span class="nx">@name</span><span class="p">,</span> <span class="nx">@index</span><span class="p">}</span> <span class="o">=</span> <span class="nx">source</span>
|
||||
<span class="vi">@body = </span><span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">body</span><span class="p">]</span>
|
||||
<span class="vi">@body = </span><span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">body</span><span class="p">]</span>
|
||||
<span class="vi">@own = </span><span class="o">!!</span><span class="nx">source</span><span class="p">.</span><span class="nx">own</span>
|
||||
<span class="vi">@object = </span><span class="o">!!</span><span class="nx">source</span><span class="p">.</span><span class="nx">object</span>
|
||||
<span class="p">[</span><span class="nx">@name</span><span class="p">,</span> <span class="nx">@index</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">@index</span><span class="p">,</span> <span class="nx">@name</span><span class="p">]</span> <span class="k">if</span> <span class="nx">@object</span>
|
||||
@@ -1104,11 +1142,11 @@ you can map and filter in a single pass.</p> </td> <td c
|
||||
|
||||
<span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="vi">@returns = </span><span class="kc">yes</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-125"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-125">¶</a> </div> <p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-126"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-126">¶</a> </div> <p>Welcome to the hairiest method in all of CoffeeScript. Handles the inner
|
||||
loop, filtering, stepping, and result saving for array, object, and range
|
||||
comprehensions. Some of the generated code can be shared in common, and
|
||||
some cannot.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileNode</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">body = </span><span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">@body</span><span class="p">]</span>
|
||||
<span class="nv">body = </span><span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">@body</span><span class="p">]</span>
|
||||
<span class="nv">lastJumps = </span><span class="nx">last</span><span class="p">(</span><span class="nx">body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">)</span><span class="o">?</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span>
|
||||
<span class="vi">@returns = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">lastJumps</span> <span class="o">and</span> <span class="nx">lastJumps</span> <span class="k">instanceof</span> <span class="nx">Return</span>
|
||||
<span class="nv">source = </span><span class="k">if</span> <span class="nx">@range</span> <span class="k">then</span> <span class="nx">@source</span><span class="p">.</span><span class="nx">base</span> <span class="k">else</span> <span class="nx">@source</span>
|
||||
@@ -1142,7 +1180,7 @@ some cannot.</p> </td> <td class="code"> <
|
||||
<span class="nv">returnResult = </span><span class="s2">"\n#{@tab}return #{rvar};"</span>
|
||||
<span class="nv">body = </span><span class="nx">Push</span><span class="p">.</span><span class="nx">wrap</span> <span class="nx">rvar</span><span class="p">,</span> <span class="nx">body</span>
|
||||
<span class="k">if</span> <span class="nx">@guard</span>
|
||||
<span class="nv">body = </span><span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="k">new</span> <span class="nx">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span>
|
||||
<span class="nv">body = </span><span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="k">new</span> <span class="nx">If</span> <span class="nx">@guard</span><span class="p">,</span> <span class="nx">body</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">@pattern</span>
|
||||
<span class="nx">body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Assign</span> <span class="nx">@name</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s2">"#{svar}[#{ivar}]"</span>
|
||||
<span class="nx">defPart</span> <span class="o">+=</span> <span class="nx">@pluckDirectCall</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">body</span>
|
||||
@@ -1175,7 +1213,7 @@ some cannot.</p> </td> <td class="code"> <
|
||||
<span class="nx">args</span><span class="p">.</span><span class="nx">unshift</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'this'</span>
|
||||
<span class="nx">body</span><span class="p">.</span><span class="nx">expressions</span><span class="p">[</span><span class="nx">idx</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Call</span> <span class="nx">base</span><span class="p">,</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">args</span>
|
||||
<span class="nx">defs</span> <span class="o">+=</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="k">new</span> <span class="nx">Assign</span><span class="p">(</span><span class="nx">ref</span><span class="p">,</span> <span class="nx">fn</span><span class="p">).</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span><span class="p">)</span> <span class="o">+</span> <span class="s1">';\n'</span>
|
||||
<span class="nx">defs</span></pre></div> </td> </tr> <tr id="section-126"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-126">¶</a> </div> <h3>Switch</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-127"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-127">¶</a> </div> <p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Switch = </span><span class="nx">class</span> <span class="nx">Switch</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">defs</span></pre></div> </td> </tr> <tr id="section-127"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-127">¶</a> </div> <h3>Switch</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-128"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-128">¶</a> </div> <p>A JavaScript <em>switch</em> statement. Converts into a returnable expression on-demand.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Switch = </span><span class="nx">class</span> <span class="nx">Switch</span> <span class="k">extends</span> <span class="nx">Base</span>
|
||||
<span class="nx">constructor</span><span class="o">:</span> <span class="p">(</span><span class="nx">@subject</span><span class="p">,</span> <span class="nx">@cases</span><span class="p">,</span> <span class="nx">@otherwise</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'subject'</span><span class="p">,</span> <span class="s1">'cases'</span><span class="p">,</span> <span class="s1">'otherwise'</span><span class="p">]</span>
|
||||
@@ -1203,11 +1241,10 @@ some cannot.</p> </td> <td class="code"> <
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">body</span> <span class="o">+</span> <span class="s1">'\n'</span> <span class="k">if</span> <span class="nv">body = </span><span class="nx">block</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span>
|
||||
<span class="k">break</span> <span class="k">if</span> <span class="nx">i</span> <span class="o">is</span> <span class="nx">@cases</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">@otherwise</span>
|
||||
<span class="nv">expr = </span><span class="nx">@lastNonComment</span> <span class="nx">block</span><span class="p">.</span><span class="nx">expressions</span>
|
||||
<span class="nv">jumper = </span><span class="nx">expr</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">expr</span> <span class="o">or</span> <span class="o">not</span> <span class="nx">jumper</span> <span class="o">or</span> <span class="p">(</span><span class="nx">jumper</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">jumper</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">'debugger'</span><span class="p">)</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">idt2</span> <span class="o">+</span> <span class="s1">'break;\n'</span>
|
||||
<span class="k">continue</span> <span class="k">if</span> <span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Return</span> <span class="o">or</span> <span class="p">(</span><span class="nx">expr</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span> <span class="o">and</span> <span class="nx">expr</span><span class="p">.</span><span class="nx">value</span> <span class="o">isnt</span> <span class="s1">'debugger'</span><span class="p">)</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">idt2</span> <span class="o">+</span> <span class="s1">'break;\n'</span>
|
||||
<span class="nx">code</span> <span class="o">+=</span> <span class="nx">idt1</span> <span class="o">+</span> <span class="s2">"default:\n#{ @otherwise.compile o, LEVEL_TOP }\n"</span> <span class="k">if</span> <span class="nx">@otherwise</span> <span class="o">and</span> <span class="nx">@otherwise</span><span class="p">.</span><span class="nx">expressions</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nx">code</span> <span class="o">+</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="s1">'}'</span></pre></div> </td> </tr> <tr id="section-128"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-128">¶</a> </div> <h3>If</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-129"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-129">¶</a> </div> <p><em>If/else</em> statements. Acts as an expression by pushing down requested returns
|
||||
<span class="nx">code</span> <span class="o">+</span> <span class="nx">@tab</span> <span class="o">+</span> <span class="s1">'}'</span></pre></div> </td> </tr> <tr id="section-129"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-129">¶</a> </div> <h3>If</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-130"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-130">¶</a> </div> <p><em>If/else</em> statements. Acts as an expression by pushing down requested returns
|
||||
to the last line of each clause.</p>
|
||||
|
||||
<p>Single-expression <strong>Ifs</strong> are compiled into conditional operators if possible,
|
||||
@@ -1221,13 +1258,13 @@ because ternaries are already proper expressions, and don't need conversion.</p>
|
||||
<span class="nx">children</span><span class="o">:</span> <span class="p">[</span><span class="s1">'condition'</span><span class="p">,</span> <span class="s1">'body'</span><span class="p">,</span> <span class="s1">'elseBody'</span><span class="p">]</span>
|
||||
|
||||
<span class="nx">bodyNode</span><span class="o">:</span> <span class="o">-></span> <span class="nx">@body</span><span class="o">?</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span>
|
||||
<span class="nx">elseBodyNode</span><span class="o">:</span> <span class="o">-></span> <span class="nx">@elseBody</span><span class="o">?</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-130"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-130">¶</a> </div> <p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addElse</span><span class="o">:</span> <span class="p">(</span><span class="nx">elseBody</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">elseBodyNode</span><span class="o">:</span> <span class="o">-></span> <span class="nx">@elseBody</span><span class="o">?</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-131"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-131">¶</a> </div> <p>Rewrite a chain of <strong>Ifs</strong> to add a default case as the final <em>else</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">addElse</span><span class="o">:</span> <span class="p">(</span><span class="nx">elseBody</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">@isChain</span>
|
||||
<span class="nx">@elseBodyNode</span><span class="p">().</span><span class="nx">addElse</span> <span class="nx">elseBody</span>
|
||||
<span class="k">else</span>
|
||||
<span class="vi">@isChain = </span><span class="nx">elseBody</span> <span class="k">instanceof</span> <span class="nx">If</span>
|
||||
<span class="vi">@elseBody = </span><span class="nx">@ensureExpressions</span> <span class="nx">elseBody</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-131"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-131">¶</a> </div> <p>The <strong>If</strong> only compiles into a statement if either of its bodies needs
|
||||
<span class="vi">@elseBody = </span><span class="nx">@ensureBlock</span> <span class="nx">elseBody</span>
|
||||
<span class="k">this</span></pre></div> </td> </tr> <tr id="section-132"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-132">¶</a> </div> <p>The <strong>If</strong> only compiles into a statement if either of its bodies needs
|
||||
to be a statement. Otherwise a conditional operator is safe.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">isStatement</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">o</span><span class="o">?</span><span class="p">.</span><span class="nx">level</span> <span class="o">is</span> <span class="nx">LEVEL_TOP</span> <span class="o">or</span>
|
||||
<span class="nx">@bodyNode</span><span class="p">().</span><span class="nx">isStatement</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">or</span> <span class="nx">@elseBodyNode</span><span class="p">()</span><span class="o">?</span><span class="p">.</span><span class="nx">isStatement</span><span class="p">(</span><span class="nx">o</span><span class="p">)</span>
|
||||
@@ -1238,17 +1275,17 @@ to be a statement. Otherwise a conditional operator is safe.</p> </t
|
||||
<span class="k">if</span> <span class="nx">@isStatement</span> <span class="nx">o</span> <span class="k">then</span> <span class="nx">@compileStatement</span> <span class="nx">o</span> <span class="k">else</span> <span class="nx">@compileExpression</span> <span class="nx">o</span>
|
||||
|
||||
<span class="nx">makeReturn</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@body</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="nx">@body</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
|
||||
<span class="nx">@elseBody</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="nx">@elseBody</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
|
||||
<span class="nx">@body</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Block</span> <span class="p">[</span><span class="nx">@body</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
|
||||
<span class="nx">@elseBody</span> <span class="o">and=</span> <span class="k">new</span> <span class="nx">Block</span> <span class="p">[</span><span class="nx">@elseBody</span><span class="p">.</span><span class="nx">makeReturn</span><span class="p">()]</span>
|
||||
<span class="k">this</span>
|
||||
|
||||
<span class="nx">ensureExpressions</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Expressions</span> <span class="k">then</span> <span class="nx">node</span> <span class="k">else</span> <span class="k">new</span> <span class="nx">Expressions</span> <span class="p">[</span><span class="nx">node</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-132"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-132">¶</a> </div> <p>Compile the <strong>If</strong> as a regular <em>if-else</em> statement. Flattened chains
|
||||
<span class="nx">ensureBlock</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">if</span> <span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Block</span> <span class="k">then</span> <span class="nx">node</span> <span class="k">else</span> <span class="k">new</span> <span class="nx">Block</span> <span class="p">[</span><span class="nx">node</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-133"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-133">¶</a> </div> <p>Compile the <strong>If</strong> as a regular <em>if-else</em> statement. Flattened chains
|
||||
force inner <em>else</em> bodies into statement form.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileStatement</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">child = </span><span class="nx">del</span> <span class="nx">o</span><span class="p">,</span> <span class="s1">'chainChild'</span>
|
||||
<span class="nv">cond = </span><span class="nx">@condition</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_PAREN</span>
|
||||
<span class="nx">o</span><span class="p">.</span><span class="nx">indent</span> <span class="o">+=</span> <span class="nx">TAB</span>
|
||||
<span class="nv">body = </span><span class="nx">@ensureExpressions</span><span class="p">(</span><span class="nx">@body</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="nv">body = </span><span class="nx">@ensureBlock</span><span class="p">(</span><span class="nx">@body</span><span class="p">).</span><span class="nx">compile</span> <span class="nx">o</span>
|
||||
<span class="nv">body = </span><span class="s2">"\n#{body}\n#{@tab}"</span> <span class="k">if</span> <span class="nx">body</span>
|
||||
<span class="nv">ifPart = </span><span class="s2">"if (#{cond}) {#{body}}"</span>
|
||||
<span class="nv">ifPart = </span><span class="nx">@tab</span> <span class="o">+</span> <span class="nx">ifPart</span> <span class="nx">unless</span> <span class="nx">child</span>
|
||||
@@ -1258,7 +1295,7 @@ force inner <em>else</em> bodies into statement form.</p> </td>
|
||||
<span class="nv">o.chainChild = </span><span class="kc">yes</span>
|
||||
<span class="nx">@elseBody</span><span class="p">.</span><span class="nx">unwrap</span><span class="p">().</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_TOP</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s2">"{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"</span></pre></div> </td> </tr> <tr id="section-133"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-133">¶</a> </div> <p>Compile the If as a conditional operator.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileExpression</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="s2">"{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"</span></pre></div> </td> </tr> <tr id="section-134"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-134">¶</a> </div> <p>Compile the If as a conditional operator.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">compileExpression</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">cond = </span><span class="nx">@condition</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_COND</span>
|
||||
<span class="nv">body = </span><span class="nx">@bodyNode</span><span class="p">().</span><span class="nx">compile</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span>
|
||||
<span class="nv">alt = </span><span class="k">if</span> <span class="nx">@elseBodyNode</span><span class="p">()</span> <span class="k">then</span> <span class="nx">@elseBodyNode</span><span class="p">().</span><span class="nx">compile</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">LEVEL_LIST</span><span class="p">)</span> <span class="k">else</span> <span class="s1">'void 0'</span>
|
||||
@@ -1266,38 +1303,37 @@ force inner <em>else</em> bodies into statement form.</p> </td>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">level</span> <span class="o">>=</span> <span class="nx">LEVEL_COND</span> <span class="k">then</span> <span class="s2">"(#{code})"</span> <span class="k">else</span> <span class="nx">code</span>
|
||||
|
||||
<span class="nx">unfoldSoak</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nx">@soak</span> <span class="o">and</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-134"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-134">¶</a> </div> <h2>Faux-Nodes</h2>
|
||||
<span class="nx">@soak</span> <span class="o">and</span> <span class="k">this</span></pre></div> </td> </tr> <tr id="section-135"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-135">¶</a> </div> <h2>Faux-Nodes</h2>
|
||||
|
||||
<p>Faux-nodes are never created by the grammar, but are used during code
|
||||
generation to generate other combinations of nodes.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-135"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-135">¶</a> </div> <h3>Push</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-136"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-136">¶</a> </div> <p>The <strong>Push</strong> creates the tree for <code>array.push(value)</code>,
|
||||
generation to generate other combinations of nodes.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-136"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-136">¶</a> </div> <h3>Push</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-137"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-137">¶</a> </div> <p>The <strong>Push</strong> creates the tree for <code>array.push(value)</code>,
|
||||
which is helpful for recording the result arrays from comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">Push =</span>
|
||||
<span class="nx">wrap</span><span class="o">:</span> <span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">exps</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">exps</span> <span class="k">if</span> <span class="nx">exps</span><span class="p">.</span><span class="nx">isEmpty</span><span class="p">()</span> <span class="o">or</span> <span class="nx">last</span><span class="p">(</span><span class="nx">exps</span><span class="p">.</span><span class="nx">expressions</span><span class="p">).</span><span class="nx">jumps</span><span class="p">()</span>
|
||||
<span class="nx">exps</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Call</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="nx">name</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'push'</span><span class="p">]),</span> <span class="p">[</span><span class="nx">exps</span><span class="p">.</span><span class="nx">pop</span><span class="p">()]</span></pre></div> </td> </tr> <tr id="section-137"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-137">¶</a> </div> <h3>Closure</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-138"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-138">¶</a> </div> <p>A faux-node used to wrap an expressions body in a closure.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">Closure =</span></pre></div> </td> </tr> <tr id="section-139"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-139">¶</a> </div> <p>Wrap the expressions body, unless it contains a pure statement,
|
||||
<span class="nx">exps</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Call</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="nx">name</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Access</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'push'</span><span class="p">]),</span> <span class="p">[</span><span class="nx">exps</span><span class="p">.</span><span class="nx">pop</span><span class="p">()]</span></pre></div> </td> </tr> <tr id="section-138"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-138">¶</a> </div> <h3>Closure</h3> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-139"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-139">¶</a> </div> <p>A faux-node used to wrap an expressions body in a closure.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">Closure =</span></pre></div> </td> </tr> <tr id="section-140"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-140">¶</a> </div> <p>Wrap the expressions body, unless it contains a pure statement,
|
||||
in which case, no dice. If the body mentions <code>this</code> or <code>arguments</code>,
|
||||
then make sure that the closure wrapper preserves the original values.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">wrap</span><span class="o">:</span> <span class="p">(</span><span class="nx">expressions</span><span class="p">,</span> <span class="nx">statement</span><span class="p">,</span> <span class="nx">noReturn</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">expressions</span> <span class="k">if</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">jumps</span><span class="p">()</span>
|
||||
<span class="nv">func = </span><span class="k">new</span> <span class="nx">Code</span> <span class="p">[],</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">expressions</span><span class="p">]</span>
|
||||
<span class="nv">func = </span><span class="k">new</span> <span class="nx">Code</span> <span class="p">[],</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">expressions</span><span class="p">]</span>
|
||||
<span class="nv">args = </span><span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nv">mentionsArgs = </span><span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalArgs</span><span class="p">)</span> <span class="o">or</span>
|
||||
<span class="p">(</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalThis</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="nv">mentionsArgs = </span><span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalArgs</span><span class="p">)</span> <span class="o">or</span> <span class="nx">expressions</span><span class="p">.</span><span class="nx">contains</span> <span class="nx">@literalThis</span>
|
||||
<span class="nv">meth = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="k">if</span> <span class="nx">mentionsArgs</span> <span class="k">then</span> <span class="s1">'apply'</span> <span class="k">else</span> <span class="s1">'call'</span>
|
||||
<span class="nv">args = </span><span class="p">[</span><span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'this'</span><span class="p">]</span>
|
||||
<span class="nx">args</span><span class="p">.</span><span class="nx">push</span> <span class="k">new</span> <span class="nx">Literal</span> <span class="s1">'arguments'</span> <span class="k">if</span> <span class="nx">mentionsArgs</span>
|
||||
<span class="nv">func = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">func</span><span class="p">,</span> <span class="p">[</span><span class="k">new</span> <span class="nx">Access</span> <span class="nx">meth</span><span class="p">]</span>
|
||||
<span class="nv">func.noReturn = </span><span class="nx">noReturn</span>
|
||||
<span class="nv">call = </span><span class="k">new</span> <span class="nx">Call</span> <span class="nx">func</span><span class="p">,</span> <span class="nx">args</span>
|
||||
<span class="k">if</span> <span class="nx">statement</span> <span class="k">then</span> <span class="nx">Expressions</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">call</span><span class="p">]</span> <span class="k">else</span> <span class="nx">call</span>
|
||||
<span class="k">if</span> <span class="nx">statement</span> <span class="k">then</span> <span class="nx">Block</span><span class="p">.</span><span class="nx">wrap</span> <span class="p">[</span><span class="nx">call</span><span class="p">]</span> <span class="k">else</span> <span class="nx">call</span>
|
||||
|
||||
<span class="nx">literalArgs</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">'arguments'</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">node</span><span class="p">.</span><span class="nx">asKey</span>
|
||||
<span class="nx">literalThis</span><span class="o">:</span> <span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Literal</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">value</span> <span class="o">is</span> <span class="s1">'this'</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">node</span><span class="p">.</span><span class="nx">asKey</span><span class="p">)</span> <span class="o">or</span>
|
||||
<span class="p">(</span><span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-140"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-140">¶</a> </div> <p>Unfold a node's child if soak, then tuck the node under created <code>If</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">unfoldSoak = </span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">parent</span><span class="p">,</span> <span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">node</span> <span class="k">instanceof</span> <span class="nx">Code</span> <span class="o">and</span> <span class="nx">node</span><span class="p">.</span><span class="nx">bound</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-141"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-141">¶</a> </div> <p>Unfold a node's child if soak, then tuck the node under created <code>If</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">unfoldSoak = </span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">parent</span><span class="p">,</span> <span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">unless</span> <span class="nv">ifn = </span><span class="nx">parent</span><span class="p">[</span><span class="nx">name</span><span class="p">].</span><span class="nx">unfoldSoak</span> <span class="nx">o</span>
|
||||
<span class="nx">parent</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">ifn</span><span class="p">.</span><span class="nx">body</span>
|
||||
<span class="nv">ifn.body = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">parent</span>
|
||||
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-141"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-141">¶</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre><span class="nv">UTILITIES =</span></pre></div> </td> </tr> <tr id="section-142"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-142">¶</a> </div> <p>Correctly set up a prototype chain for inheritance, including a reference
|
||||
<span class="nx">ifn</span></pre></div> </td> </tr> <tr id="section-142"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-142">¶</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre><span class="nv">UTILITIES =</span></pre></div> </td> </tr> <tr id="section-143"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-143">¶</a> </div> <p>Correctly set up a prototype chain for inheritance, including a reference
|
||||
to the superclass for <code>super()</code> calls, and copies of any static properties.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">extends</span><span class="o">:</span> <span class="s1">'''</span>
|
||||
<span class="s1"> function(child, parent) {</span>
|
||||
<span class="s1"> for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }</span>
|
||||
@@ -1307,26 +1343,25 @@ to the superclass for <code>super()</code> calls, and copies of any static prope
|
||||
<span class="s1"> child.__super__ = parent.prototype;</span>
|
||||
<span class="s1"> return child;</span>
|
||||
<span class="s1"> }</span>
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-143"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-143">¶</a> </div> <p>Create a function bound to the current value of "this".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">bind</span><span class="o">:</span> <span class="s1">'''</span>
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-144"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-144">¶</a> </div> <p>Create a function bound to the current value of "this".</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">bind</span><span class="o">:</span> <span class="s1">'''</span>
|
||||
<span class="s1"> function(fn, me){ return function(){ return fn.apply(me, arguments); }; }</span>
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-144"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-144">¶</a> </div> <p>Discover if an item is in an array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">indexOf</span><span class="o">:</span> <span class="s1">'''</span>
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-145"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-145">¶</a> </div> <p>Discover if an item is in an array.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">indexOf</span><span class="o">:</span> <span class="s1">'''</span>
|
||||
<span class="s1"> Array.prototype.indexOf || function(item) {</span>
|
||||
<span class="s1"> for (var i = 0, l = this.length; i < l; i++) {</span>
|
||||
<span class="s1"> if (this[i] === item) return i;</span>
|
||||
<span class="s1"> }</span>
|
||||
<span class="s1"> return -1;</span>
|
||||
<span class="s1"> }</span>
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-145"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-145">¶</a> </div> <p>Shortcuts to speed up the lookup time for native functions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasProp</span><span class="o">:</span> <span class="s1">'Object.prototype.hasOwnProperty'</span>
|
||||
<span class="nx">slice</span> <span class="o">:</span> <span class="s1">'Array.prototype.slice'</span></pre></div> </td> </tr> <tr id="section-146"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-146">¶</a> </div> <p>Levels indicates a node's position in the AST. Useful for knowing if
|
||||
<span class="s1"> '''</span></pre></div> </td> </tr> <tr id="section-146"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-146">¶</a> </div> <p>Shortcuts to speed up the lookup time for native functions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">hasProp</span><span class="o">:</span> <span class="s1">'Object.prototype.hasOwnProperty'</span>
|
||||
<span class="nx">slice</span> <span class="o">:</span> <span class="s1">'Array.prototype.slice'</span></pre></div> </td> </tr> <tr id="section-147"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-147">¶</a> </div> <p>Levels indicates a node's position in the AST. Useful for knowing if
|
||||
parens are necessary or superfluous.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">LEVEL_TOP = </span><span class="mi">1</span> <span class="c1"># ...;</span>
|
||||
<span class="nv">LEVEL_PAREN = </span><span class="mi">2</span> <span class="c1"># (...)</span>
|
||||
<span class="nv">LEVEL_LIST = </span><span class="mi">3</span> <span class="c1"># [...]</span>
|
||||
<span class="nv">LEVEL_COND = </span><span class="mi">4</span> <span class="c1"># ... ? x : y</span>
|
||||
<span class="nv">LEVEL_OP = </span><span class="mi">5</span> <span class="c1"># !...</span>
|
||||
<span class="nv">LEVEL_ACCESS = </span><span class="mi">6</span> <span class="c1"># ...[0]</span></pre></div> </td> </tr> <tr id="section-147"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-147">¶</a> </div> <p>Tabs are two spaces for pretty printing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">TAB = </span><span class="s1">' '</span></pre></div> </td> </tr> <tr id="section-148"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-148">¶</a> </div> <p>Trim out all trailing whitespace, so that the generated code plays nice
|
||||
with Git.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">TRAILING_WHITESPACE = </span><span class="sr">/[ \t]+$/gm</span>
|
||||
<span class="nv">LEVEL_ACCESS = </span><span class="mi">6</span> <span class="c1"># ...[0]</span></pre></div> </td> </tr> <tr id="section-148"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-148">¶</a> </div> <p>Tabs are two spaces for pretty printing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">TAB = </span><span class="s1">' '</span>
|
||||
|
||||
<span class="nv">IDENTIFIER = </span><span class="sr">/^[$A-Za-z_][$\w]*$/</span>
|
||||
<span class="nv">IDENTIFIER = </span><span class="sr">/^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/</span>
|
||||
<span class="nv">SIMPLENUM = </span><span class="sr">/^[+-]?\d+$/</span></pre></div> </td> </tr> <tr id="section-149"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-149">¶</a> </div> <p>Is a literal value a string?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IS_STRING = </span><span class="sr">/^['"]/</span></pre></div> </td> </tr> <tr id="section-150"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-150">¶</a> </div> <h2>Utility Functions</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-151"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-151">¶</a> </div> <p>Helper for ensuring that utility functions are assigned at the top level.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">utility = </span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">ref = </span><span class="s2">"__#{name}"</span>
|
||||
<span class="nx">Scope</span><span class="p">.</span><span class="nx">root</span><span class="p">.</span><span class="nx">assign</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">UTILITIES</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span>
|
||||
|
||||
@@ -39,7 +39,7 @@ for interpreting the options object.</p> </td> <td class
|
||||
<span class="k">break</span>
|
||||
<span class="nx">options</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
|
||||
of the valid options, for <code>--help</code> and such.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">help</span><span class="o">:</span> <span class="o">-></span>
|
||||
<span class="nv">lines = </span><span class="p">[</span><span class="s1">'Available options:'</span><span class="p">]</span>
|
||||
<span class="nv">lines = </span><span class="p">[]</span>
|
||||
<span class="nx">lines</span><span class="p">.</span><span class="nx">unshift</span> <span class="s2">"#{@banner}\n"</span> <span class="k">if</span> <span class="nx">@banner</span>
|
||||
<span class="k">for</span> <span class="nx">rule</span> <span class="k">in</span> <span class="nx">@rules</span>
|
||||
<span class="nv">spaces = </span><span class="mi">15</span> <span class="o">-</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">longFlag</span><span class="p">.</span><span class="nx">length</span>
|
||||
|
||||
@@ -4,20 +4,60 @@ 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 <strong>stdio</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdio = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</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">stdio</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span> <span class="o">+</span> <span class="s1">'\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></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">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 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">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">console</span><span class="p">.</span><span class="nx">log</span> <span class="nx">val</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="nx">error</span> <span class="nx">err</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</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="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdio</span>
|
||||
of exiting.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">run = </span><span class="nx">do</span> <span class="o">-></span>
|
||||
<span class="nv">sandbox =</span>
|
||||
<span class="nx">require</span><span class="o">:</span> <span class="nx">require</span>
|
||||
<span class="nx">module</span> <span class="o">:</span> <span class="p">{</span> <span class="nx">exports</span><span class="o">:</span> <span class="p">{}</span> <span class="p">}</span>
|
||||
<span class="nx">sandbox</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="o">=</span> <span class="nx">global</span><span class="p">[</span><span class="nx">g</span><span class="p">]</span> <span class="k">for</span> <span class="nx">g</span> <span class="k">of</span> <span class="nx">global</span>
|
||||
<span class="nv">sandbox.global = </span><span class="nx">sandbox</span>
|
||||
<span class="nv">sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = </span><span class="nx">sandbox</span>
|
||||
<span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">code = </span><span class="nx">backlog</span> <span class="o">+=</span> <span class="s1">'\n'</span> <span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="nx">code</span><span class="p">[</span><span class="nx">code</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'\\'</span>
|
||||
<span class="k">return</span> <span class="nv">backlog = </span><span class="nx">backlog</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">backlog</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">backlog = </span><span class="s1">''</span>
|
||||
<span class="k">try</span>
|
||||
<span class="nv">val = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="nx">code</span><span class="p">,</span> <span class="p">{</span>
|
||||
<span class="nx">sandbox</span><span class="p">,</span>
|
||||
<span class="nx">bare</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span>
|
||||
<span class="nx">filename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="p">}</span>
|
||||
<span class="nx">unless</span> <span class="nx">val</span> <span class="o">is</span> <span class="kc">undefined</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">inspect</span><span class="p">(</span><span class="nx">val</span><span class="p">,</span> <span class="kc">no</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">enableColours</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'\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-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <h1>Autocompletion</h1> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Regexes to match complete-able bits of text.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">ACCESSOR = </span><span class="sr">/\s*([\w\.]+)(?:\.(\w*))$/</span>
|
||||
<span class="nv">SIMPLEVAR = </span><span class="sr">/\s*(\w*)$/i</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</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-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</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">runInThisContext</span> <span class="nx">obj</span>
|
||||
<span class="k">catch</span> <span class="nx">error</span>
|
||||
<span class="k">return</span> <span class="p">[[],</span> <span class="nx">text</span><span class="p">]</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">prefix</span><span class="p">,</span> <span class="nx">getPropertyNames</span> <span class="nx">val</span>
|
||||
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">prefix</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</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="nx">text</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">SIMPLEVAR</span><span class="p">)</span><span class="o">?</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nv">scope = </span><span class="nx">Script</span><span class="p">.</span><span class="nx">runInThisContext</span> <span class="s1">'this'</span>
|
||||
<span class="nv">completions = </span><span class="nx">getCompletions</span> <span class="nx">free</span><span class="p">,</span> <span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">RESERVED</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">getPropertyNames</span> <span class="nx">scope</span><span class="p">)</span>
|
||||
<span class="p">[</span><span class="nx">completions</span><span class="p">,</span> <span class="nx">free</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</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-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Return all "own" properties of an object.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">getPropertyNames = </span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">name</span> <span class="k">for</span> <span class="nx">own</span> <span class="nx">name</span> <span class="k">of</span> <span class="nx">obj</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</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="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">stdio</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="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">stdio</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'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="nx">prompt</span><span class="p">()</span>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -114,6 +117,7 @@ deal with them.</p> </td> <td class="code">
|
||||
<span class="nv">seenSingle = </span><span class="kc">no</span>
|
||||
<span class="nv">noCall = </span><span class="kc">no</span> <span class="k">if</span> <span class="nx">tag</span> <span class="k">in</span> <span class="nx">LINEBREAKS</span>
|
||||
<span class="nv">token.call = </span><span class="kc">yes</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'?'</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>
|
||||
|
||||
@@ -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>Expressions</strong> node is belongs to, which is
|
||||
as well as a reference to the <strong>Block</strong> node is belongs to, which is
|
||||
where it should declare its variables, and a reference to the function that
|
||||
it wraps.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">constructor</span><span class="o">:</span><span class="p">(</span><span class="nx">@parent</span><span class="p">,</span> <span class="nx">@expressions</span><span class="p">,</span> <span class="nx">@method</span><span class="p">)</span> <span class="o">-></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>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html> <html> <head> <title>underscore.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> underscore.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">¶</a> </div> <p><strong>Underscore.coffee
|
||||
(c) 2010 Jeremy Ashkenas, DocumentCloud Inc.</strong>
|
||||
(c) 2011 Jeremy Ashkenas, DocumentCloud Inc.</strong>
|
||||
Underscore is freely distributable under the terms of the
|
||||
<a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a>.
|
||||
Portions of Underscore are inspired by or borrowed from
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -80,10 +80,10 @@
|
||||
<div class="screenshadow bl"></div>
|
||||
<div class="screenshadow br"></div>
|
||||
<div id="repl_source_wrap">
|
||||
<textarea id="repl_source" rows="100">alert "Hello CoffeeScript!"</textarea>
|
||||
<textarea id="repl_source" rows="100" spellcheck="false">alert "Hello CoffeeScript!"</textarea>
|
||||
</div>
|
||||
<div id="repl_results_wrap"><pre id="repl_results"></pre></div>
|
||||
<div class="minibutton dark run">Run</div>
|
||||
<div class="minibutton dark run" title="Ctrl-Enter">Run</div>
|
||||
<br class="clear" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.0.0">1.0.0</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.0">1.1.0</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -166,17 +166,21 @@
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
npm install coffee-script</pre>
|
||||
npm install -g coffee-script</pre>
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
<p>
|
||||
(Leave off the <tt>-g</tt> if you don't wish to install globally.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you'd prefer to install the latest master version of CoffeeScript, you
|
||||
can clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/master">the source</a> directly.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
sudo bin/cake install</pre>
|
||||
@@ -219,10 +223,11 @@ sudo bin/cake install</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-j, --join</code></td>
|
||||
<td><code>-j, --join [FILE]</code></td>
|
||||
<td>
|
||||
Before compiling, concatenate all scripts together in the order they
|
||||
were passed. Useful for building large projects.
|
||||
were passed, and write them into the specified file.
|
||||
Useful for building large projects.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -326,7 +331,7 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
Concatenate a list of files into a single script:<br />
|
||||
<tt>coffee -o lib/ --join --compile src/*.coffee</tt>
|
||||
<tt>coffee --join project.js --compile src/*.coffee</tt>
|
||||
</li>
|
||||
<li>
|
||||
Print out the compiled JS from a one-liner:<br />
|
||||
@@ -479,11 +484,13 @@ Expressions
|
||||
over arrays, objects, and ranges. Comprehensions replace (and compile into)
|
||||
<b>for</b> loops, with optional guard clauses and the value of the current array index.
|
||||
Unlike for loops, array comprehensions are expressions, and can be returned
|
||||
and assigned. They should be able to handle most places where you otherwise
|
||||
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
|
||||
and assigned.
|
||||
</p>
|
||||
<%= code_for('array_comprehensions') %>
|
||||
<p>
|
||||
Comprehensions should be able to handle most places where you otherwise
|
||||
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>:
|
||||
<tt>shortNames = (name for name in list when name.length < 5)</tt><br />
|
||||
If you know the start and end of your loop, or would like to step through
|
||||
in fixed-size increments, you can use a range to specify the start and
|
||||
end of your comprehension.
|
||||
@@ -540,7 +547,7 @@ Expressions
|
||||
<b class="header">Array Slicing and Splicing with Ranges</b>
|
||||
Ranges can also be used to extract slices of arrays.
|
||||
With two dots (<tt>3..6</tt>), the range is inclusive (<tt>3, 4, 5, 6</tt>);
|
||||
with three docs (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
with three dots (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
</p>
|
||||
<%= code_for('slices', 'middle') %>
|
||||
<p>
|
||||
@@ -699,15 +706,15 @@ Expressions
|
||||
in a single assignable expression.
|
||||
</p>
|
||||
<p>
|
||||
Constructor functions are named, to better support reflection. In the
|
||||
example below for the first class, <tt>this.constructor.name is "Animal"</tt>.
|
||||
Constructor functions are named, to better support helpful stack traces.
|
||||
</p>
|
||||
<%= code_for('classes', true) %>
|
||||
<p>
|
||||
If structuring your prototypes classically isn't your cup of tea, CoffeeScript
|
||||
provides a couple of lower-level conveniences. The <tt>extends</tt> operator
|
||||
helps with proper prototype setup, <tt>::</tt> gives you
|
||||
quick access to an object's prototype, and <tt>super()</tt>
|
||||
helps with proper prototype setup, and can be used to create an inheritance
|
||||
chain between any pair of constructor functions; <tt>::</tt> gives you
|
||||
quick access to an object's prototype; and <tt>super()</tt>
|
||||
is converted into a call against the immediate ancestor's method of the same name.
|
||||
</p>
|
||||
<%= code_for('prototypes', '"one_two".dasherize()') %>
|
||||
@@ -840,7 +847,7 @@ Expressions
|
||||
<p>
|
||||
Sometimes you'd like to pass a block comment through to the generated
|
||||
JavaScript. For example, when you need to embed a licensing header at
|
||||
the top of a file. Block comments, which mirror the synax for heredocs,
|
||||
the top of a file. Block comments, which mirror the syntax for heredocs,
|
||||
are preserved in the generated code.
|
||||
</p>
|
||||
<%= code_for('block_comment') %>
|
||||
@@ -921,6 +928,10 @@ Expressions
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
|
||||
a zero-configuration Rack server, with comprehensive annotated source.
|
||||
</li>
|
||||
<li>
|
||||
<b>frank06</b>'s <a href="http://riakjs.org/">riak-js</a>, a Node.js client for
|
||||
<a href="http://www.basho.com/Riak.html">Riak</a>, with support for HTTP
|
||||
@@ -930,6 +941,10 @@ Expressions
|
||||
<b>technoweenie</b>'s <a href="https://github.com/technoweenie/coffee-resque">Coffee-Resque</a>,
|
||||
a port of <a href="https://github.com/defunkt/resque">Resque</a> for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
|
||||
A headless, full-stack, faux-browser testing library for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
|
||||
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
|
||||
@@ -943,10 +958,6 @@ Expressions
|
||||
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
|
||||
<a href="http://rack.rubyforge.org/">Rack</a> server.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://sstephenson.github.com/strscan-js/">StringScanner</a>,
|
||||
a simple tokenizer and lexical scanner for JavaScript strings.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
@@ -969,103 +980,23 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://github.com/jashkenas/coffee-script/issues">CoffeeScript Issues</a><br />
|
||||
Bugs reports, feature requests, and general discussion all belong here.
|
||||
Bug reports, feature proposals, and ideas for changes to the language belong here.
|
||||
</li>
|
||||
<li>
|
||||
If you'd like to chat, stop by <tt>#coffeescript</tt> on Freenode in the
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
<a href="https://groups.google.com/forum/#!forum/coffeescript">CoffeeScript Google Group</a><br />
|
||||
If you'd like to ask a question, the mailing list is a good place to get help.
|
||||
</li>
|
||||
<li>
|
||||
<b>satyr</b>'s <a href="http://github.com/satyr/coco">Coco</a>
|
||||
— 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>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>chrislloyd</b>'s <a href="http://github.com/chrislloyd/roast">Roast</a>
|
||||
— a CoffeeScript compiler plug-in that allows you to include external
|
||||
source files.
|
||||
</li>
|
||||
<li>
|
||||
<b>andrzejsliwa</b>'s <a href="http://github.com/andrzejsliwa/coffeeapp">CoffeeApp</a>
|
||||
— 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>
|
||||
|
||||
@@ -1088,6 +1019,38 @@ Expressions
|
||||
<span id="change_log" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.0
|
||||
<span class="timestamp"> – <small>May 1, 2011</small></span>
|
||||
</b>
|
||||
When running via <tt>coffee</tt> executable, <tt>process.argv</tt> and
|
||||
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
|
||||
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
|
||||
The output in the REPL is now colorized, like Node's is.
|
||||
Giving your concatenated CoffeeScripts a name when using <tt>--join</tt> is now mandatory.
|
||||
Fix for lexing compound division <tt>/=</tt> as a regex accidentally.
|
||||
All <tt>text/coffeescript</tt> tags should now execute in the order they're included.
|
||||
Fixed an issue with extended subclasses using external constructor functions.
|
||||
Fixed an edge-case infinite loop in <tt>addImplicitParentheses</tt>.
|
||||
Fixed exponential slowdown with long chains of function calls.
|
||||
Globals no longer leak into the CoffeeScript REPL.
|
||||
Function calls can be used as default values for parameters.
|
||||
Splatted parameters are declared local to the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.0.1
|
||||
<span class="timestamp"> – <small>Jan 31, 2011</small></span>
|
||||
</b>
|
||||
Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility
|
||||
with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing
|
||||
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
|
||||
Stopped requiring the core Node.js <tt>"util"</tt> module for
|
||||
back-compatibility with Node.js 0.2.5. Fixed a case where a
|
||||
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
|
||||
statement. Optimized empty objects in destructuring assignment.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.0.0
|
||||
@@ -1562,7 +1525,7 @@ Expressions
|
||||
$('#repl_source').keyup -> compileSource()
|
||||
|
||||
# Eval the compiled js.
|
||||
$('.minibutton.run').click ->
|
||||
evalJS = ->
|
||||
try
|
||||
eval window.compiledJS
|
||||
catch error then alert error
|
||||
@@ -1578,6 +1541,8 @@ Expressions
|
||||
closeMenus = ->
|
||||
$('.navigation.active').removeClass 'active'
|
||||
|
||||
$('.minibutton.run').click evalJS
|
||||
|
||||
# Bind navigation buttons to open the menus.
|
||||
$('.navigation').click (e) ->
|
||||
return if e.target.tagName.toLowerCase() is 'a'
|
||||
@@ -1589,9 +1554,15 @@ Expressions
|
||||
$(this).addClass 'active'
|
||||
false
|
||||
|
||||
$(document.body).click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
# Dismiss console if Escape pressed or click falls outside console
|
||||
# Trigger Run button on Ctrl-Enter
|
||||
$(document.body)
|
||||
.keydown (e) ->
|
||||
closeMenus() if e.which == 27
|
||||
evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length
|
||||
.click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
|
||||
$('#open_webchat').click ->
|
||||
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
CoffeeScript Compiler v1.0.0
|
||||
CoffeeScript Compiler v1.1.0
|
||||
Released under the MIT License
|
||||
*/
|
||||
@@ -1,10 +1,10 @@
|
||||
var fileName, _fn, _i, _len;
|
||||
_fn = function(fileName) {
|
||||
return fs.readFile(fileName, function(err, contents) {
|
||||
return compile(fileName, contents.toString());
|
||||
var filename, _fn, _i, _len;
|
||||
_fn = function(filename) {
|
||||
return fs.readFile(filename, function(err, contents) {
|
||||
return compile(filename, contents.toString());
|
||||
});
|
||||
};
|
||||
for (_i = 0, _len = list.length; _i < _len; _i++) {
|
||||
fileName = list[_i];
|
||||
_fn(fileName);
|
||||
filename = list[_i];
|
||||
_fn(filename);
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
var footprints, solipsism;
|
||||
if ((typeof mind != "undefined" && mind !== null) && !(typeof world != "undefined" && world !== null)) {
|
||||
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
|
||||
solipsism = true;
|
||||
}
|
||||
typeof speed != "undefined" && speed !== null ? speed : speed = 75;
|
||||
footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";
|
||||
if (typeof speed !== "undefined" && speed !== null) {
|
||||
speed;
|
||||
} else {
|
||||
speed = 75;
|
||||
};
|
||||
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
|
||||
@@ -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,5 +1,5 @@
|
||||
# **Underscore.coffee
|
||||
# (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.**
|
||||
# (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.**
|
||||
# Underscore is freely distributable under the terms of the
|
||||
# [MIT license](http://en.wikipedia.org/wiki/MIT_License).
|
||||
# Portions of Underscore are inspired by or borrowed from
|
||||
|
||||
File diff suppressed because one or more lines are too long
269
index.html
269
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.0">1.0.0</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/1.1.0">1.1.0</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -170,7 +170,7 @@ math <span class="Keyword">=</span> {
|
||||
winner <span class="Keyword">=</span> arguments[<span class="Number">0</span>], runners <span class="Keyword">=</span> <span class="Number">2</span> <span class="Keyword"><=</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>
|
||||
@@ -294,10 +298,11 @@ sudo bin/cake install</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-j, --join</code></td>
|
||||
<td><code>-j, --join [FILE]</code></td>
|
||||
<td>
|
||||
Before compiling, concatenate all scripts together in the order they
|
||||
were passed. Useful for building large projects.
|
||||
were passed, and write them into the specified file.
|
||||
Useful for building large projects.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -401,7 +406,7 @@ Expressions
|
||||
</li>
|
||||
<li>
|
||||
Concatenate a list of files into a single script:<br />
|
||||
<tt>coffee -o lib/ --join --compile src/*.coffee</tt>
|
||||
<tt>coffee --join project.js --compile src/*.coffee</tt>
|
||||
</li>
|
||||
<li>
|
||||
Print out the compiled JS from a one-liner:<br />
|
||||
@@ -752,8 +757,7 @@ alert("The Field: " + rest);;'>run</div><br class='clear' /></div>
|
||||
over arrays, objects, and ranges. Comprehensions replace (and compile into)
|
||||
<b>for</b> loops, with optional guard clauses and the value of the current array index.
|
||||
Unlike for loops, array comprehensions are expressions, and can be returned
|
||||
and assigned. They should be able to handle most places where you otherwise
|
||||
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>.
|
||||
and assigned.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Eat lunch.</span>
|
||||
eat food <span class="Keyword">for</span> food <span class="Keyword">in</span> [<span class="String"><span class="String">'</span>toast<span class="String">'</span></span>, <span class="String"><span class="String">'</span>cheese<span class="String">'</span></span>, <span class="String"><span class="String">'</span>wine<span class="String">'</span></span>]
|
||||
@@ -765,6 +769,9 @@ _ref <span class="Keyword">=</span> [<span class="String"><span class="String">'
|
||||
}
|
||||
</pre><script>window.example9 = "# Eat lunch.\neat food for food in ['toast', 'cheese', 'wine']\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example9);'>load</div><br class='clear' /></div>
|
||||
<p>
|
||||
Comprehensions should be able to handle most places where you otherwise
|
||||
would use a loop, <b>each</b>/<b>forEach</b>, <b>map</b>, or <b>select</b>/<b>filter</b>:
|
||||
<tt>shortNames = (name for name in list when name.length < 5)</tt><br />
|
||||
If you know the start and end of your loop, or would like to step through
|
||||
in fixed-size increments, you can use a range to specify the start and
|
||||
end of your comprehension.
|
||||
@@ -911,28 +918,28 @@ lyrics = (function() {
|
||||
provides the <tt>do</tt> keyword, which immediately invokes a passed function,
|
||||
forwarding any arguments.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Keyword">for</span> fileName <span class="Keyword">in</span> list
|
||||
<span class="Keyword">do</span> <span class="FunctionArgument">(fileName)</span> <span class="Storage">-></span>
|
||||
fs.readFile fileName, <span class="FunctionArgument">(err, contents)</span> <span class="Storage">-></span>
|
||||
compile fileName, contents.toString()
|
||||
</pre><pre class="idle"><span class="Storage">var</span> fileName, _fn, _i, _len;
|
||||
<span class="FunctionName">_fn</span> = <span class="Storage">function</span>(<span class="FunctionArgument">fileName</span>) {
|
||||
<span class="Keyword">return</span> fs.readFile(fileName, <span class="Storage">function</span>(err, contents) {
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">compile</span>(fileName, contents.<span class="LibraryFunction">toString</span>());
|
||||
<div class='code'><pre class="idle"><span class="Keyword">for</span> filename <span class="Keyword">in</span> list
|
||||
<span class="Keyword">do</span> <span class="FunctionArgument">(filename)</span> <span class="Storage">-></span>
|
||||
fs.readFile filename, <span class="FunctionArgument">(err, contents)</span> <span class="Storage">-></span>
|
||||
compile filename, contents.toString()
|
||||
</pre><pre class="idle"><span class="Storage">var</span> filename, _fn, _i, _len;
|
||||
<span class="FunctionName">_fn</span> = <span class="Storage">function</span>(<span class="FunctionArgument">filename</span>) {
|
||||
<span class="Keyword">return</span> fs.readFile(filename, <span class="Storage">function</span>(err, contents) {
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">compile</span>(filename, contents.<span class="LibraryFunction">toString</span>());
|
||||
});
|
||||
};
|
||||
<span class="Keyword">for</span> (_i <span class="Keyword">=</span> <span class="Number">0</span>, _len <span class="Keyword">=</span> list.<span class="LibraryConstant">length</span>; _i <span class="Keyword"><</span> _len; _i<span class="Keyword">++</span>) {
|
||||
fileName <span class="Keyword">=</span> list[_i];
|
||||
_fn(fileName);
|
||||
filename <span class="Keyword">=</span> list[_i];
|
||||
_fn(filename);
|
||||
}
|
||||
</pre><script>window.example13 = "for fileName in list\n do (fileName) ->\n fs.readFile fileName, (err, contents) ->\n compile fileName, contents.toString()"</script><div class='minibutton load' onclick='javascript: loadConsole(example13);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example13 = "for filename in list\n do (filename) ->\n fs.readFile filename, (err, contents) ->\n compile filename, contents.toString()"</script><div class='minibutton load' onclick='javascript: loadConsole(example13);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="slices" class="bookmark"></span>
|
||||
<b class="header">Array Slicing and Splicing with Ranges</b>
|
||||
Ranges can also be used to extract slices of arrays.
|
||||
With two dots (<tt>3..6</tt>), the range is inclusive (<tt>3, 4, 5, 6</tt>);
|
||||
with three docs (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
with three dots (<tt>3...6</tt>), the range excludes the end (<tt>3, 4, 5</tt>).
|
||||
</p>
|
||||
<div class='code'><pre class="idle">numbers <span class="Keyword">=</span> [<span class="Number">0</span>, <span class="Number">1</span>, <span class="Number">2</span>, <span class="Number">3</span>, <span class="Number">4</span>, <span class="Number">5</span>, <span class="Number">6</span>, <span class="Number">7</span>, <span class="Number">8</span>, <span class="Number">9</span>]
|
||||
|
||||
@@ -1199,17 +1206,25 @@ footprints <span class="Keyword">=</span> yeti <span class="Keyword">?</span> <s
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Storage">var</span> footprints, solipsism;
|
||||
<span class="Keyword">if</span> ((<span class="Keyword">typeof</span> mind <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">"</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="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;
|
||||
} <span class="Keyword">else</span> {
|
||||
speed <span class="Keyword">=</span> <span class="Number">75</span>;
|
||||
};
|
||||
footprints <span class="Keyword">=</span> <span class="Keyword">typeof</span> yeti <span class="Keyword">!</span><span class="Keyword">==</span> <span class="String"><span class="String">"</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;
|
||||
} else {
|
||||
speed = 75;
|
||||
};
|
||||
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";;alert(footprints);'>run: footprints</div><br class='clear' /></div>
|
||||
<p>
|
||||
The accessor variant of the existential operator <tt>?.</tt> can be used to soak
|
||||
up null references in a chain of properties. Use it instead
|
||||
@@ -1251,8 +1266,7 @@ zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.d
|
||||
in a single assignable expression.
|
||||
</p>
|
||||
<p>
|
||||
Constructor functions are named, to better support reflection. In the
|
||||
example below for the first class, <tt>this.constructor.name is "Animal"</tt>.
|
||||
Constructor functions are named, to better support helpful stack traces.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Storage">class</span> <span class="TypeName">Animal</span>
|
||||
<span class="FunctionName">constructor</span><span class="Keyword">:</span> <span class="FunctionArgument">(@name)</span> <span class="Storage">-></span>
|
||||
@@ -1370,8 +1384,9 @@ tom.move();;'>run</div><br class='clear' /></div>
|
||||
<p>
|
||||
If structuring your prototypes classically isn't your cup of tea, CoffeeScript
|
||||
provides a couple of lower-level conveniences. The <tt>extends</tt> operator
|
||||
helps with proper prototype setup, <tt>::</tt> gives you
|
||||
quick access to an object's prototype, and <tt>super()</tt>
|
||||
helps with proper prototype setup, and can be used to create an inheritance
|
||||
chain between any pair of constructor functions; <tt>::</tt> gives you
|
||||
quick access to an object's prototype; and <tt>super()</tt>
|
||||
is converted into a call against the immediate ancestor's method of the same name.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="FunctionName">String::dasherize </span><span class="Keyword">=</span> <span class="Keyword">-</span><span class="Keyword">></span>
|
||||
@@ -1706,20 +1721,20 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
<p>
|
||||
Sometimes you'd like to pass a block comment through to the generated
|
||||
JavaScript. For example, when you need to embed a licensing header at
|
||||
the top of a file. Block comments, which mirror the synax for heredocs,
|
||||
the top of a file. Block comments, which mirror the syntax for heredocs,
|
||||
are preserved in the generated code.
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">###</span></span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.0.0</span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.1.0</span>
|
||||
<span class="Comment">Released under the MIT License</span>
|
||||
<span class="Comment"><span class="Comment">###</span></span>
|
||||
|
||||
|
||||
</pre><pre class="idle"><span class="Comment"><span class="Comment">/*</span></span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.0.0</span>
|
||||
<span class="Comment">CoffeeScript Compiler v1.1.0</span>
|
||||
<span class="Comment">Released under the MIT License</span>
|
||||
<span class="Comment"><span class="Comment">*/</span></span>
|
||||
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.0.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
|
||||
</pre><script>window.example37 = "###\nCoffeeScript Compiler v1.1.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="regexes" class="bookmark"></span>
|
||||
@@ -1829,6 +1844,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://pow.cx/">Pow</a>,
|
||||
a zero-configuration Rack server, with comprehensive annotated source.
|
||||
</li>
|
||||
<li>
|
||||
<b>frank06</b>'s <a href="http://riakjs.org/">riak-js</a>, a Node.js client for
|
||||
<a href="http://www.basho.com/Riak.html">Riak</a>, with support for HTTP
|
||||
@@ -1838,6 +1857,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<b>technoweenie</b>'s <a href="https://github.com/technoweenie/coffee-resque">Coffee-Resque</a>,
|
||||
a port of <a href="https://github.com/defunkt/resque">Resque</a> for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>assaf</b>'s <a href="http://zombie.labnotes.org/">Zombie.js</a>,
|
||||
A headless, full-stack, faux-browser testing library for Node.js.
|
||||
</li>
|
||||
<li>
|
||||
<b>jashkenas</b>' <a href="documentation/docs/underscore.html">Underscore.coffee</a>, a port
|
||||
of the <a href="http://documentcloud.github.com/underscore/">Underscore.js</a>
|
||||
@@ -1851,10 +1874,6 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
|
||||
<a href="http://rack.rubyforge.org/">Rack</a> server.
|
||||
</li>
|
||||
<li>
|
||||
<b>sstephenson</b>'s <a href="http://sstephenson.github.com/strscan-js/">StringScanner</a>,
|
||||
a simple tokenizer and lexical scanner for JavaScript strings.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
@@ -1877,103 +1896,23 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://github.com/jashkenas/coffee-script/issues">CoffeeScript Issues</a><br />
|
||||
Bugs reports, feature requests, and general discussion all belong here.
|
||||
Bug reports, feature proposals, and ideas for changes to the language belong here.
|
||||
</li>
|
||||
<li>
|
||||
If you'd like to chat, stop by <tt>#coffeescript</tt> on Freenode in the
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
<a href="https://groups.google.com/forum/#!forum/coffeescript">CoffeeScript Google Group</a><br />
|
||||
If you'd like to ask a question, the mailing list is a good place to get help.
|
||||
</li>
|
||||
<li>
|
||||
<b>satyr</b>'s <a href="http://github.com/satyr/coco">Coco</a>
|
||||
— 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>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>chrislloyd</b>'s <a href="http://github.com/chrislloyd/roast">Roast</a>
|
||||
— a CoffeeScript compiler plug-in that allows you to include external
|
||||
source files.
|
||||
</li>
|
||||
<li>
|
||||
<b>andrzejsliwa</b>'s <a href="http://github.com/andrzejsliwa/coffeeapp">CoffeeApp</a>
|
||||
— 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>
|
||||
|
||||
@@ -1996,6 +1935,38 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<span id="change_log" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.1.0
|
||||
<span class="timestamp"> – <small>May 1, 2011</small></span>
|
||||
</b>
|
||||
When running via <tt>coffee</tt> executable, <tt>process.argv</tt> and
|
||||
friends now report <tt>coffee</tt> instead of <tt>node</tt>.
|
||||
Better compatibility with <b>Node.js 0.4.x</b> module lookup changes.
|
||||
The output in the REPL is now colorized, like Node's is.
|
||||
Giving your concatenated CoffeeScripts a name when using <tt>--join</tt> is now mandatory.
|
||||
Fix for lexing compound division <tt>/=</tt> as a regex accidentally.
|
||||
All <tt>text/coffeescript</tt> tags should now execute in the order they're included.
|
||||
Fixed an issue with extended subclasses using external constructor functions.
|
||||
Fixed an edge-case infinite loop in <tt>addImplicitParentheses</tt>.
|
||||
Fixed exponential slowdown with long chains of function calls.
|
||||
Globals no longer leak into the CoffeeScript REPL.
|
||||
Function calls can be used as default values for parameters.
|
||||
Splatted parameters are declared local to the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.0.1
|
||||
<span class="timestamp"> – <small>Jan 31, 2011</small></span>
|
||||
</b>
|
||||
Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility
|
||||
with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing
|
||||
<tt>return</tt> and <tt>return undefined</tt> are now optimized away.
|
||||
Stopped requiring the core Node.js <tt>"util"</tt> module for
|
||||
back-compatibility with Node.js 0.2.5. Fixed a case where a
|
||||
conditional <tt>return</tt> would cause fallthrough in a <tt>switch</tt>
|
||||
statement. Optimized empty objects in destructuring assignment.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">1.0.0
|
||||
@@ -2470,7 +2441,7 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
$('#repl_source').keyup -> compileSource()
|
||||
|
||||
# Eval the compiled js.
|
||||
$('.minibutton.run').click ->
|
||||
evalJS = ->
|
||||
try
|
||||
eval window.compiledJS
|
||||
catch error then alert error
|
||||
@@ -2486,6 +2457,8 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
closeMenus = ->
|
||||
$('.navigation.active').removeClass 'active'
|
||||
|
||||
$('.minibutton.run').click evalJS
|
||||
|
||||
# Bind navigation buttons to open the menus.
|
||||
$('.navigation').click (e) ->
|
||||
return if e.target.tagName.toLowerCase() is 'a'
|
||||
@@ -2497,9 +2470,15 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
$(this).addClass 'active'
|
||||
false
|
||||
|
||||
$(document.body).click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
# Dismiss console if Escape pressed or click falls outside console
|
||||
# Trigger Run button on Ctrl-Enter
|
||||
$(document.body)
|
||||
.keydown (e) ->
|
||||
closeMenus() if e.which == 27
|
||||
evalJS() if e.which == 13 and (e.metaKey or e.ctrlKey) and $('.minibutton.run:visible').length
|
||||
.click (e) ->
|
||||
return false if $(e.target).hasClass('minibutton')
|
||||
closeMenus()
|
||||
|
||||
$('#open_webchat').click ->
|
||||
$(this).replaceWith $('<iframe src="http://webchat.freenode.net/?channels=coffeescript" width="625" height="400"></iframe>')
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
args = process.argv.slice(2);
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
|
||||
fileName: 'Cakefile'
|
||||
filename: 'Cakefile'
|
||||
});
|
||||
oparse = new optparse.OptionParser(switches);
|
||||
if (!args.length) {
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
(function() {
|
||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref;
|
||||
var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
vm = require('vm');
|
||||
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
|
||||
parser = require('./parser').parser;
|
||||
if (require.extensions) {
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
var content;
|
||||
content = compile(fs.readFileSync(filename, 'utf8'));
|
||||
content = compile(fs.readFileSync(filename, 'utf8'), {
|
||||
filename: filename
|
||||
});
|
||||
return module._compile(content, filename);
|
||||
};
|
||||
} else if (require.registerExtension) {
|
||||
@@ -15,7 +18,7 @@
|
||||
return compile(content);
|
||||
});
|
||||
}
|
||||
exports.VERSION = '1.0.0';
|
||||
exports.VERSION = '1.1.0';
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.helpers = require('./helpers');
|
||||
exports.compile = compile = function(code, options) {
|
||||
@@ -25,8 +28,8 @@
|
||||
try {
|
||||
return (parser.parse(lexer.tokenize(code))).compile(options);
|
||||
} catch (err) {
|
||||
if (options.fileName) {
|
||||
err.message = "In " + options.fileName + ", " + err.message;
|
||||
if (options.filename) {
|
||||
err.message = "In " + options.filename + ", " + err.message;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
@@ -42,15 +45,19 @@
|
||||
}
|
||||
};
|
||||
exports.run = function(code, options) {
|
||||
var root;
|
||||
var Module, root;
|
||||
root = module;
|
||||
while (root.parent) {
|
||||
root = root.parent;
|
||||
}
|
||||
root.filename = fs.realpathSync(options.fileName || '.');
|
||||
root.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
if (root.moduleCache) {
|
||||
root.moduleCache = {};
|
||||
}
|
||||
if (process.binding('natives').module) {
|
||||
Module = require('module').Module;
|
||||
root.paths = Module._nodeModulePaths(path.dirname(options.filename));
|
||||
}
|
||||
if (path.extname(root.filename) !== '.coffee' || require.extensions) {
|
||||
return root._compile(compile(code, options), root.filename);
|
||||
} else {
|
||||
@@ -58,16 +65,34 @@
|
||||
}
|
||||
};
|
||||
exports.eval = function(code, options) {
|
||||
var __dirname, __filename;
|
||||
__filename = options.fileName;
|
||||
__dirname = path.dirname(__filename);
|
||||
return eval(compile(code, options));
|
||||
var g, js, sandbox;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
sandbox = options.sandbox;
|
||||
if (!sandbox) {
|
||||
sandbox = {
|
||||
require: require,
|
||||
module: {
|
||||
exports: {}
|
||||
}
|
||||
};
|
||||
for (g in global) {
|
||||
sandbox[g] = global[g];
|
||||
}
|
||||
sandbox.global = sandbox;
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox;
|
||||
}
|
||||
sandbox.__filename = options.filename || 'eval';
|
||||
sandbox.__dirname = path.dirname(sandbox.__filename);
|
||||
js = compile("_=(" + (code.trim()) + ")", options);
|
||||
return vm.runInNewContext(js, sandbox, sandbox.__filename);
|
||||
};
|
||||
lexer = new Lexer;
|
||||
parser.lexer = {
|
||||
lex: function() {
|
||||
var tag, _ref;
|
||||
_ref = this.tokens[this.pos++] || [''], tag = _ref[0], this.yytext = _ref[1], this.yylineno = _ref[2];
|
||||
var tag, _ref2;
|
||||
_ref2 = this.tokens[this.pos++] || [''], tag = _ref2[0], this.yytext = _ref2[1], this.yylineno = _ref2[2];
|
||||
return tag;
|
||||
},
|
||||
setInput: function(tokens) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
(function() {
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, util, version, watch, writeJs, _ref;
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compileScript, compileScripts, compileStdio, contents, exec, forkNode, fs, helpers, lint, loadRequires, optionParser, optparse, opts, parseOptions, path, printLine, printTokens, printWarn, sources, spawn, usage, version, watch, writeJs, _ref;
|
||||
fs = require('fs');
|
||||
path = require('path');
|
||||
util = require('util');
|
||||
helpers = require('./helpers');
|
||||
optparse = require('./optparse');
|
||||
CoffeeScript = require('./coffee-script');
|
||||
@@ -16,7 +15,7 @@
|
||||
return process.binding('stdio').writeError(line + '\n');
|
||||
};
|
||||
BANNER = 'Usage: coffee [options] path/to/script.coffee';
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-j', '--join', 'concatenate the scripts before compiling'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['--nodejs [ARGS]', 'pass options through to the "node" binary'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
SWITCHES = [['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-j', '--join [FILE]', 'concatenate the scripts before compiling'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-b', '--bare', 'compile without the top-level function wrapper'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-n', '--nodes', 'print the parse tree that Jison produces'], ['--nodejs [ARGS]', 'pass options through to the "node" binary'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']];
|
||||
opts = {};
|
||||
sources = [];
|
||||
contents = [];
|
||||
@@ -32,6 +31,9 @@
|
||||
if (opts.version) {
|
||||
return version();
|
||||
}
|
||||
if (opts.require) {
|
||||
loadRequires();
|
||||
}
|
||||
if (opts.interactive) {
|
||||
return require('./repl');
|
||||
}
|
||||
@@ -48,6 +50,8 @@
|
||||
opts.literals = sources.splice(1).concat(opts.literals);
|
||||
}
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat(opts.literals);
|
||||
process.argv[0] = 'coffee';
|
||||
process.execPath = process.mainModule.filename;
|
||||
return compileScripts();
|
||||
};
|
||||
compileScripts = function() {
|
||||
@@ -58,25 +62,28 @@
|
||||
base = path.join(source);
|
||||
compile = function(source, topLevel) {
|
||||
return path.exists(source, function(exists) {
|
||||
if (!exists) {
|
||||
if (topLevel && !exists) {
|
||||
throw new Error("File not found: " + source);
|
||||
}
|
||||
return fs.stat(source, function(err, stats) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
if (stats.isDirectory()) {
|
||||
return fs.readdir(source, function(err, files) {
|
||||
var file, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = files.length; _i < _len; _i++) {
|
||||
file = files[_i];
|
||||
_results.push(compile(path.join(source, file)));
|
||||
var file, _j, _len2, _results2;
|
||||
_results2 = [];
|
||||
for (_j = 0, _len2 = files.length; _j < _len2; _j++) {
|
||||
file = files[_j];
|
||||
_results2.push(compile(path.join(source, file)));
|
||||
}
|
||||
return _results;
|
||||
return _results2;
|
||||
});
|
||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
||||
fs.readFile(source, function(err, code) {
|
||||
if (opts.join) {
|
||||
contents[sources.indexOf(source)] = code.toString();
|
||||
if (helpers.compact(contents).length === sources.length) {
|
||||
if (helpers.compact(contents).length > 0) {
|
||||
return compileJoin();
|
||||
}
|
||||
} else {
|
||||
@@ -95,16 +102,9 @@
|
||||
return _results;
|
||||
};
|
||||
compileScript = function(file, input, base) {
|
||||
var o, options, req, t, task, _i, _len, _ref;
|
||||
var o, options, t, task;
|
||||
o = opts;
|
||||
options = compileOptions(file);
|
||||
if (o.require) {
|
||||
_ref = o.require;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
req = _ref[_i];
|
||||
require(helpers.starts(req, '.') ? fs.realpathSync(req) : req);
|
||||
}
|
||||
}
|
||||
try {
|
||||
t = task = {
|
||||
file: file,
|
||||
@@ -157,7 +157,18 @@
|
||||
compileJoin = function() {
|
||||
var code;
|
||||
code = contents.join('\n');
|
||||
return compileScript("concatenation", code, "concatenation");
|
||||
return compileScript(opts.join, code, opts.join);
|
||||
};
|
||||
loadRequires = function() {
|
||||
var realFilename, req, _i, _len, _ref2;
|
||||
realFilename = module.filename;
|
||||
module.filename = '.';
|
||||
_ref2 = opts.require;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
req = _ref2[_i];
|
||||
require(req);
|
||||
}
|
||||
return module.filename = realFilename;
|
||||
};
|
||||
watch = function(source, base) {
|
||||
return fs.watchFile(source, {
|
||||
@@ -190,7 +201,7 @@
|
||||
if (err) {
|
||||
return printLine(err.message);
|
||||
} else if (opts.compile && opts.watch) {
|
||||
return util.log("compiled " + source);
|
||||
return console.log("" + ((new Date).toLocaleTimeString()) + " - compiled " + source);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -217,11 +228,11 @@
|
||||
printTokens = function(tokens) {
|
||||
var strings, tag, token, value;
|
||||
strings = (function() {
|
||||
var _i, _len, _ref, _results;
|
||||
var _i, _len, _ref2, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
|
||||
token = tokens[_i];
|
||||
_ref = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref[0], value = _ref[1];
|
||||
_ref2 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref2[0], value = _ref2[1];
|
||||
_results.push("[" + tag + " " + value + "]");
|
||||
}
|
||||
return _results;
|
||||
@@ -237,9 +248,9 @@
|
||||
o.print = !!(o.print || (o.eval || o.stdio && o.compile));
|
||||
return sources = o.arguments;
|
||||
};
|
||||
compileOptions = function(fileName) {
|
||||
compileOptions = function(filename) {
|
||||
return {
|
||||
fileName: fileName,
|
||||
filename: filename,
|
||||
bare: opts.bare
|
||||
};
|
||||
};
|
||||
@@ -255,11 +266,9 @@
|
||||
});
|
||||
};
|
||||
usage = function() {
|
||||
printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
||||
return process.exit(0);
|
||||
return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
|
||||
};
|
||||
version = function() {
|
||||
printLine("CoffeeScript version " + CoffeeScript.VERSION);
|
||||
return process.exit(0);
|
||||
return printLine("CoffeeScript version " + CoffeeScript.VERSION);
|
||||
};
|
||||
}).call(this);
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
}
|
||||
action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
|
||||
action = action.replace(/\bnew /g, '$&yy.');
|
||||
action = action.replace(/\b(?:Expressions\.wrap|extend)\b/g, 'yy.$&');
|
||||
action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
|
||||
return [patternString, "$$ = " + action + ";", options];
|
||||
};
|
||||
grammar = {
|
||||
Root: [
|
||||
o('', function() {
|
||||
return new Expressions;
|
||||
return new Block;
|
||||
}), o('Body'), o('Block TERMINATOR')
|
||||
],
|
||||
Body: [
|
||||
o('Line', function() {
|
||||
return Expressions.wrap([$1]);
|
||||
return Block.wrap([$1]);
|
||||
}), o('Body TERMINATOR Line', function() {
|
||||
return $1.push($3);
|
||||
}), o('Body TERMINATOR')
|
||||
@@ -35,7 +35,7 @@
|
||||
Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class')],
|
||||
Block: [
|
||||
o('INDENT OUTDENT', function() {
|
||||
return new Expressions;
|
||||
return new Block;
|
||||
}), o('INDENT Body OUTDENT', function() {
|
||||
return $2;
|
||||
})
|
||||
@@ -58,7 +58,12 @@
|
||||
}), o('REGEX', function() {
|
||||
return new Literal($1);
|
||||
}), o('BOOL', function() {
|
||||
return new Literal($1 === 'undefined' ? 'void 0' : $1);
|
||||
var val;
|
||||
val = new Literal($1);
|
||||
if ($1 === 'undefined') {
|
||||
val.isUndefined = true;
|
||||
}
|
||||
return val;
|
||||
})
|
||||
],
|
||||
Assign: [
|
||||
@@ -164,13 +169,11 @@
|
||||
return new Access($2, 'proto');
|
||||
}), o('::', function() {
|
||||
return new Access(new Literal('prototype'));
|
||||
}), o('Index'), o('Slice', function() {
|
||||
return new Slice($1);
|
||||
})
|
||||
}), o('Index')
|
||||
],
|
||||
Index: [
|
||||
o('INDEX_START Expression INDEX_END', function() {
|
||||
return new Index($2);
|
||||
o('INDEX_START IndexValue INDEX_END', function() {
|
||||
return $2;
|
||||
}), o('INDEX_SOAK Index', function() {
|
||||
return extend($2, {
|
||||
soak: true
|
||||
@@ -181,6 +184,13 @@
|
||||
});
|
||||
})
|
||||
],
|
||||
IndexValue: [
|
||||
o('Expression', function() {
|
||||
return new Index($1);
|
||||
}), o('Slice', function() {
|
||||
return new Slice($1);
|
||||
})
|
||||
],
|
||||
Object: [
|
||||
o('{ AssignList OptComma }', function() {
|
||||
return new Obj($2, $1.generated);
|
||||
@@ -275,12 +285,12 @@
|
||||
})
|
||||
],
|
||||
Slice: [
|
||||
o('INDEX_START Expression RangeDots Expression INDEX_END', function() {
|
||||
return new Range($2, $4, $3);
|
||||
}), o('INDEX_START Expression RangeDots INDEX_END', function() {
|
||||
return new Range($2, null, $3);
|
||||
}), o('INDEX_START RangeDots Expression INDEX_END', function() {
|
||||
return new Range(null, $3, $2);
|
||||
o('Expression RangeDots Expression', function() {
|
||||
return new Range($1, $3, $2);
|
||||
}), o('Expression RangeDots', function() {
|
||||
return new Range($1, null, $2);
|
||||
}), o('RangeDots Expression', function() {
|
||||
return new Range(null, $2, $1);
|
||||
})
|
||||
],
|
||||
ArgList: [
|
||||
@@ -352,9 +362,9 @@
|
||||
o('WhileSource Block', function() {
|
||||
return $1.addBody($2);
|
||||
}), o('Statement WhileSource', function() {
|
||||
return $2.addBody(Expressions.wrap([$1]));
|
||||
return $2.addBody(Block.wrap([$1]));
|
||||
}), o('Expression WhileSource', function() {
|
||||
return $2.addBody(Expressions.wrap([$1]));
|
||||
return $2.addBody(Block.wrap([$1]));
|
||||
}), o('Loop', function() {
|
||||
return $1;
|
||||
})
|
||||
@@ -363,7 +373,7 @@
|
||||
o('LOOP Block', function() {
|
||||
return new While(new Literal('true')).addBody($2);
|
||||
}), o('LOOP Expression', function() {
|
||||
return new While(new Literal('true')).addBody(Expressions.wrap([$2]));
|
||||
return new While(new Literal('true')).addBody(Block.wrap([$2]));
|
||||
})
|
||||
],
|
||||
For: [
|
||||
@@ -481,18 +491,18 @@
|
||||
return $1.addElse(new If($4, $5, {
|
||||
type: $3
|
||||
}));
|
||||
}), o('IfBlock ELSE Block', function() {
|
||||
return $1.addElse($3);
|
||||
})
|
||||
],
|
||||
If: [
|
||||
o('IfBlock'), o('Statement POST_IF Expression', function() {
|
||||
return new If($3, Expressions.wrap([$1]), {
|
||||
o('IfBlock'), o('IfBlock ELSE Block', function() {
|
||||
return $1.addElse($3);
|
||||
}), o('Statement POST_IF Expression', function() {
|
||||
return new If($3, Block.wrap([$1]), {
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
}), o('Expression POST_IF Expression', function() {
|
||||
return new If($3, Expressions.wrap([$1]), {
|
||||
return new If($3, Block.wrap([$1]), {
|
||||
type: $2,
|
||||
statement: true
|
||||
});
|
||||
|
||||
107
lib/lexer.js
107
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;
|
||||
@@ -15,6 +15,9 @@
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
if (WHITESPACE.test(code)) {
|
||||
code = "\n" + code;
|
||||
}
|
||||
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
|
||||
this.code = code;
|
||||
this.line = opts.line || 0;
|
||||
@@ -34,7 +37,7 @@
|
||||
return (new Rewriter).rewrite(this.tokens);
|
||||
};
|
||||
Lexer.prototype.identifierToken = function() {
|
||||
var colon, forcedIdentifier, id, input, match, prev, tag, _ref, _ref2;
|
||||
var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
|
||||
if (!(match = IDENTIFIER.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
@@ -43,11 +46,11 @@
|
||||
this.token('OWN', id);
|
||||
return id.length;
|
||||
}
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && !prev.spaced && ((_ref = prev[0]) === '.' || _ref === '?.' || _ref === '@' || _ref === '::');
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
|
||||
tag = 'IDENTIFIER';
|
||||
if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) {
|
||||
tag = id.toUpperCase();
|
||||
if (tag === 'WHEN' && (_ref2 = this.tag(), __indexOf.call(LINE_BREAK, _ref2) >= 0)) {
|
||||
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
|
||||
tag = 'LEADING_WHEN';
|
||||
} else if (tag === 'FOR') {
|
||||
this.seenFor = true;
|
||||
@@ -78,8 +81,8 @@
|
||||
}
|
||||
}
|
||||
if (!forcedIdentifier) {
|
||||
if (COFFEE_ALIASES.hasOwnProperty(id)) {
|
||||
id = COFFEE_ALIASES[id];
|
||||
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
|
||||
id = COFFEE_ALIAS_MAP[id];
|
||||
}
|
||||
tag = (function() {
|
||||
switch (id) {
|
||||
@@ -172,7 +175,6 @@
|
||||
return 0;
|
||||
}
|
||||
comment = match[0], here = match[1];
|
||||
this.line += count(comment, '\n');
|
||||
if (here) {
|
||||
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
|
||||
herecomment: true,
|
||||
@@ -180,6 +182,7 @@
|
||||
}));
|
||||
this.token('TERMINATOR', '\n');
|
||||
}
|
||||
this.line += count(comment, '\n');
|
||||
return comment.length;
|
||||
};
|
||||
Lexer.prototype.jsToken = function() {
|
||||
@@ -191,7 +194,7 @@
|
||||
return script.length;
|
||||
};
|
||||
Lexer.prototype.regexToken = function() {
|
||||
var match, prev, regex, _ref;
|
||||
var match, prev, regex, _ref2;
|
||||
if (this.chunk.charAt(0) !== '/') {
|
||||
return 0;
|
||||
}
|
||||
@@ -199,7 +202,7 @@
|
||||
return this.heregexToken(match);
|
||||
}
|
||||
prev = last(this.tokens);
|
||||
if (prev && (_ref = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref) >= 0)) {
|
||||
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (!(match = REGEX.exec(this.chunk))) {
|
||||
@@ -210,7 +213,7 @@
|
||||
return regex.length;
|
||||
};
|
||||
Lexer.prototype.heregexToken = function(match) {
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref, _ref2, _ref3, _ref4;
|
||||
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
|
||||
heregex = match[0], body = match[1], flags = match[2];
|
||||
if (0 > body.indexOf('#{')) {
|
||||
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
|
||||
@@ -220,11 +223,11 @@
|
||||
this.token('IDENTIFIER', 'RegExp');
|
||||
this.tokens.push(['CALL_START', '(']);
|
||||
tokens = [];
|
||||
_ref = this.interpolateString(body, {
|
||||
_ref2 = this.interpolateString(body, {
|
||||
regex: true
|
||||
});
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
_ref2 = _ref[_i], tag = _ref2[0], value = _ref2[1];
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
_ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
|
||||
if (tag === 'TOKENS') {
|
||||
tokens.push.apply(tokens, value);
|
||||
} else {
|
||||
@@ -237,10 +240,10 @@
|
||||
tokens.push(['+', '+']);
|
||||
}
|
||||
tokens.pop();
|
||||
if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') {
|
||||
if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
|
||||
this.tokens.push(['STRING', '""'], ['+', '+']);
|
||||
}
|
||||
(_ref4 = this.tokens).push.apply(_ref4, tokens);
|
||||
(_ref5 = this.tokens).push.apply(_ref5, tokens);
|
||||
if (flags) {
|
||||
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
|
||||
}
|
||||
@@ -337,7 +340,7 @@
|
||||
return this;
|
||||
};
|
||||
Lexer.prototype.literalToken = function() {
|
||||
var match, prev, tag, value, _ref, _ref2, _ref3, _ref4;
|
||||
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
|
||||
if (match = OPERATOR.exec(this.chunk)) {
|
||||
value = match[0];
|
||||
if (CODE.test(value)) {
|
||||
@@ -349,10 +352,10 @@
|
||||
tag = value;
|
||||
prev = last(this.tokens);
|
||||
if (value === '=' && prev) {
|
||||
if (!prev[1].reserved && (_ref = prev[1], __indexOf.call(JS_FORBIDDEN, _ref) >= 0)) {
|
||||
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
|
||||
this.assignmentError();
|
||||
}
|
||||
if ((_ref2 = prev[1]) === '||' || _ref2 === '&&') {
|
||||
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
|
||||
prev[0] = 'COMPOUND_ASSIGN';
|
||||
prev[1] += '=';
|
||||
return value.length;
|
||||
@@ -373,12 +376,12 @@
|
||||
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
|
||||
tag = 'LOGIC';
|
||||
} else if (prev && !prev.spaced) {
|
||||
if (value === '(' && (_ref3 = prev[0], __indexOf.call(CALLABLE, _ref3) >= 0)) {
|
||||
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
}
|
||||
tag = 'CALL_START';
|
||||
} else if (value === '[' && (_ref4 = prev[0], __indexOf.call(INDEXABLE, _ref4) >= 0)) {
|
||||
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
|
||||
tag = 'INDEX_START';
|
||||
switch (prev[0]) {
|
||||
case '?':
|
||||
@@ -393,15 +396,19 @@
|
||||
return value.length;
|
||||
};
|
||||
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
||||
var attempt, herecomment, indent, match, _ref;
|
||||
var attempt, herecomment, indent, match, _ref2;
|
||||
indent = options.indent, herecomment = options.herecomment;
|
||||
if (herecomment && 0 > doc.indexOf('\n')) {
|
||||
return doc;
|
||||
}
|
||||
if (!herecomment) {
|
||||
if (herecomment) {
|
||||
if (HEREDOC_ILLEGAL.test(doc)) {
|
||||
throw new Error("block comment cannot contain \"*/\", starting on line " + (this.line + 1));
|
||||
}
|
||||
if (doc.indexOf('\n') <= 0) {
|
||||
return doc;
|
||||
}
|
||||
} else {
|
||||
while (match = HEREDOC_INDENT.exec(doc)) {
|
||||
attempt = match[1];
|
||||
if (indent === null || (0 < (_ref = attempt.length) && _ref < indent.length)) {
|
||||
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
|
||||
indent = attempt;
|
||||
}
|
||||
}
|
||||
@@ -432,7 +439,7 @@
|
||||
case 'CALL_START':
|
||||
if (stack.length) {
|
||||
stack.pop();
|
||||
} else {
|
||||
} else if (tok[0] === '(') {
|
||||
tok[0] = 'PARAM_START';
|
||||
return this;
|
||||
}
|
||||
@@ -450,9 +457,9 @@
|
||||
throw SyntaxError("Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned");
|
||||
};
|
||||
Lexer.prototype.balancedString = function(str, end) {
|
||||
var i, letter, prev, stack, _ref;
|
||||
var i, letter, prev, stack, _ref2;
|
||||
stack = [end];
|
||||
for (i = 1, _ref = str.length; (1 <= _ref ? i < _ref : i > _ref); (1 <= _ref ? i += 1 : i -= 1)) {
|
||||
for (i = 1, _ref2 = str.length; 1 <= _ref2 ? i < _ref2 : i > _ref2; 1 <= _ref2 ? i++ : i--) {
|
||||
switch (letter = str.charAt(i)) {
|
||||
case '\\':
|
||||
i++;
|
||||
@@ -477,7 +484,7 @@
|
||||
throw new Error("missing " + (stack.pop()) + ", starting on line " + (this.line + 1));
|
||||
};
|
||||
Lexer.prototype.interpolateString = function(str, options) {
|
||||
var expr, heredoc, i, inner, interpolated, letter, nested, pi, regex, tag, tokens, value, _len, _ref, _ref2, _ref3;
|
||||
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _len, _ref2, _ref3, _ref4;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -503,14 +510,16 @@
|
||||
rewrite: false
|
||||
});
|
||||
nested.pop();
|
||||
if (((_ref = nested[0]) != null ? _ref[0] : void 0) === 'TERMINATOR') {
|
||||
if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
|
||||
nested.shift();
|
||||
}
|
||||
if (nested.length > 1) {
|
||||
nested.unshift(['(', '(']);
|
||||
nested.push([')', ')']);
|
||||
if (len = nested.length) {
|
||||
if (len > 1) {
|
||||
nested.unshift(['(', '(']);
|
||||
nested.push([')', ')']);
|
||||
}
|
||||
tokens.push(['TOKENS', nested]);
|
||||
}
|
||||
tokens.push(['TOKENS', nested]);
|
||||
}
|
||||
i += expr.length;
|
||||
pi = i + 1;
|
||||
@@ -531,12 +540,12 @@
|
||||
this.token('(', '(');
|
||||
}
|
||||
for (i = 0, _len = tokens.length; i < _len; i++) {
|
||||
_ref2 = tokens[i], tag = _ref2[0], value = _ref2[1];
|
||||
_ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
|
||||
if (i) {
|
||||
this.token('+', '+');
|
||||
}
|
||||
if (tag === 'TOKENS') {
|
||||
(_ref3 = this.tokens).push.apply(_ref3, value);
|
||||
(_ref4 = this.tokens).push.apply(_ref4, value);
|
||||
} else {
|
||||
this.token('STRING', this.makeString(value, '"', heredoc));
|
||||
}
|
||||
@@ -582,7 +591,7 @@
|
||||
})();
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
||||
for (op in COFFEE_ALIASES = {
|
||||
COFFEE_ALIAS_MAP = {
|
||||
and: '&&',
|
||||
or: '||',
|
||||
is: '==',
|
||||
@@ -592,13 +601,20 @@
|
||||
no: 'false',
|
||||
on: 'true',
|
||||
off: 'false'
|
||||
}) {
|
||||
COFFEE_KEYWORDS.push(op);
|
||||
}
|
||||
};
|
||||
COFFEE_ALIASES = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (key in COFFEE_ALIAS_MAP) {
|
||||
_results.push(key);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
|
||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf'];
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS);
|
||||
IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;
|
||||
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
|
||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i;
|
||||
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
@@ -608,13 +624,14 @@
|
||||
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
|
||||
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
|
||||
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
|
||||
REGEX = /^\/(?!\s)[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
|
||||
REGEX = /^\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/[imgy]{0,4}(?!\w)/;
|
||||
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
|
||||
HEREGEX_OMIT = /\s+(?:#.*)?/g;
|
||||
MULTILINER = /\n/g;
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
|
||||
LINE_CONTINUER = /^\s*(?:,|\??\.(?!\.)|::)/;
|
||||
HEREDOC_ILLEGAL = /\*\//;
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
|
||||
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
|
||||
TRAILING_SPACES = /\s+$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
|
||||
|
||||
663
lib/nodes.js
663
lib/nodes.js
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@
|
||||
};
|
||||
OptionParser.prototype.help = function() {
|
||||
var letPart, lines, rule, spaces, _i, _len, _ref;
|
||||
lines = ['Available options:'];
|
||||
lines = [];
|
||||
if (this.banner) {
|
||||
lines.unshift("" + this.banner + "\n");
|
||||
}
|
||||
|
||||
281
lib/parser.js
281
lib/parser.js
File diff suppressed because one or more lines are too long
126
lib/repl.js
126
lib/repl.js
@@ -1,41 +1,113 @@
|
||||
(function() {
|
||||
var CoffeeScript, error, helpers, readline, repl, run, stdio;
|
||||
var ACCESSOR, CoffeeScript, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, getPropertyNames, inspect, readline, repl, run, stdin, stdout;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers');
|
||||
readline = require('readline');
|
||||
stdio = process.openStdin();
|
||||
inspect = require('util').inspect;
|
||||
Script = require('vm').Script;
|
||||
enableColours = false;
|
||||
if (process.platform !== 'win32') {
|
||||
enableColours = !process.env.NODE_DISABLE_COLORS;
|
||||
}
|
||||
stdin = process.openStdin();
|
||||
stdout = process.stdout;
|
||||
error = function(err) {
|
||||
return stdio.write((err.stack || err.toString()) + '\n\n');
|
||||
return stdout.write((err.stack || err.toString()) + '\n\n');
|
||||
};
|
||||
helpers.extend(global, {
|
||||
quit: function() {
|
||||
return process.exit(0);
|
||||
}
|
||||
});
|
||||
run = function(buffer) {
|
||||
var val;
|
||||
try {
|
||||
val = CoffeeScript.eval(buffer.toString(), {
|
||||
bare: true,
|
||||
globals: true,
|
||||
fileName: 'repl'
|
||||
});
|
||||
if (val !== void 0) {
|
||||
console.log(val);
|
||||
backlog = '';
|
||||
run = (function() {
|
||||
var g, sandbox;
|
||||
sandbox = {
|
||||
require: require,
|
||||
module: {
|
||||
exports: {}
|
||||
}
|
||||
} catch (err) {
|
||||
error(err);
|
||||
};
|
||||
for (g in global) {
|
||||
sandbox[g] = global[g];
|
||||
}
|
||||
return repl.prompt();
|
||||
sandbox.global = sandbox;
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox;
|
||||
return function(buffer) {
|
||||
var code, val;
|
||||
code = backlog += '\n' + buffer.toString();
|
||||
if (code[code.length - 1] === '\\') {
|
||||
return backlog = backlog.slice(0, backlog.length - 1);
|
||||
}
|
||||
backlog = '';
|
||||
try {
|
||||
val = CoffeeScript.eval(code, {
|
||||
sandbox: sandbox,
|
||||
bare: true,
|
||||
filename: 'repl'
|
||||
});
|
||||
if (val !== void 0) {
|
||||
process.stdout.write(inspect(val, false, 2, enableColours) + '\n');
|
||||
}
|
||||
} catch (err) {
|
||||
error(err);
|
||||
}
|
||||
return repl.prompt();
|
||||
};
|
||||
})();
|
||||
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
|
||||
SIMPLEVAR = /\s*(\w*)$/i;
|
||||
autocomplete = function(text) {
|
||||
return completeAttribute(text) || completeVariable(text) || [[], text];
|
||||
};
|
||||
completeAttribute = function(text) {
|
||||
var all, completions, match, obj, prefix, val;
|
||||
if (match = text.match(ACCESSOR)) {
|
||||
all = match[0], obj = match[1], prefix = match[2];
|
||||
try {
|
||||
val = Script.runInThisContext(obj);
|
||||
} catch (error) {
|
||||
return [[], text];
|
||||
}
|
||||
completions = getCompletions(prefix, getPropertyNames(val));
|
||||
return [completions, prefix];
|
||||
}
|
||||
};
|
||||
completeVariable = function(text) {
|
||||
var completions, free, scope, _ref;
|
||||
if (free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0) {
|
||||
scope = Script.runInThisContext('this');
|
||||
completions = getCompletions(free, CoffeeScript.RESERVED.concat(getPropertyNames(scope)));
|
||||
return [completions, free];
|
||||
}
|
||||
};
|
||||
getCompletions = function(prefix, candidates) {
|
||||
var el, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
|
||||
el = candidates[_i];
|
||||
if (el.indexOf(prefix) === 0) {
|
||||
_results.push(el);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
getPropertyNames = function(obj) {
|
||||
var name, _results;
|
||||
_results = [];
|
||||
for (name in obj) {
|
||||
if (!__hasProp.call(obj, name)) continue;
|
||||
_results.push(name);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
process.on('uncaughtException', error);
|
||||
repl = readline.createInterface(stdio);
|
||||
if (readline.createInterface.length < 3) {
|
||||
repl = readline.createInterface(stdin, autocomplete);
|
||||
stdin.on('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
} else {
|
||||
repl = readline.createInterface(stdin, stdout, autocomplete);
|
||||
}
|
||||
repl.setPrompt('coffee> ');
|
||||
stdio.on('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
repl.on('close', function() {
|
||||
return stdio.destroy();
|
||||
return stdin.destroy();
|
||||
});
|
||||
repl.on('line', run);
|
||||
repl.prompt();
|
||||
|
||||
@@ -121,7 +121,10 @@
|
||||
return ((tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':')) || (tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT'));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
|
||||
var tok;
|
||||
tok = ['}', '}', token[2]];
|
||||
tok.generated = true;
|
||||
return this.tokens.splice(i, 0, tok);
|
||||
};
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var ago, idx, tag, tok, value, _ref, _ref2;
|
||||
@@ -173,12 +176,15 @@
|
||||
if (prev && !prev.spaced && tag === '?') {
|
||||
token.call = true;
|
||||
}
|
||||
if (token.fromThen) {
|
||||
return 1;
|
||||
}
|
||||
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref3 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref3) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
|
||||
return 1;
|
||||
}
|
||||
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
this.detectEnd(i + 1, function(token, i) {
|
||||
var post, _ref;
|
||||
var post, _ref4;
|
||||
tag = token[0];
|
||||
if (!seenSingle && token.fromThen) {
|
||||
return true;
|
||||
@@ -189,7 +195,7 @@
|
||||
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
|
||||
return true;
|
||||
}
|
||||
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
|
||||
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref4 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref4) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
|
||||
}, action);
|
||||
if (prev[0] === '?') {
|
||||
prev[0] = 'FUNC_EXIST';
|
||||
@@ -222,8 +228,8 @@
|
||||
indent.generated = outdent.generated = true;
|
||||
tokens.splice(i + 1, 0, indent);
|
||||
condition = function(token, i) {
|
||||
var _ref;
|
||||
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
|
||||
var _ref3;
|
||||
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
|
||||
|
||||
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.0",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.2.5"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib"
|
||||
},
|
||||
"main" : "./lib/coffee-script",
|
||||
"bin": {
|
||||
"coffee": "./bin/coffee",
|
||||
"cake": "./bin/cake"
|
||||
}
|
||||
"name": "coffee-script",
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.1.0",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=0.2.5"
|
||||
},
|
||||
"directories" : {
|
||||
"lib" : "./lib"
|
||||
},
|
||||
"main" : "./lib/coffee-script",
|
||||
"bin": {
|
||||
"coffee": "./bin/coffee",
|
||||
"cake": "./bin/cake"
|
||||
},
|
||||
"homepage": "http://coffeescript.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jashkenas/coffee-script.git"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -47,7 +47,7 @@ exports.run = ->
|
||||
path.exists 'Cakefile', (exists) ->
|
||||
throw new Error("Cakefile not found in #{process.cwd()}") unless exists
|
||||
args = process.argv.slice 2
|
||||
CoffeeScript.run fs.readFileSync('Cakefile').toString(), fileName: 'Cakefile'
|
||||
CoffeeScript.run fs.readFileSync('Cakefile').toString(), filename: 'Cakefile'
|
||||
oparse = new optparse.OptionParser switches
|
||||
return printTasks() unless args.length
|
||||
options = oparse.parse(args)
|
||||
|
||||
@@ -8,19 +8,20 @@
|
||||
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
vm = require 'vm'
|
||||
{Lexer,RESERVED} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
|
||||
# TODO: Remove registerExtension when fully deprecated.
|
||||
if require.extensions
|
||||
require.extensions['.coffee'] = (module, filename) ->
|
||||
content = compile fs.readFileSync filename, 'utf8'
|
||||
content = compile fs.readFileSync(filename, 'utf8'), {filename}
|
||||
module._compile content, filename
|
||||
else if require.registerExtension
|
||||
require.registerExtension '.coffee', (content) -> compile content
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '1.0.0'
|
||||
exports.VERSION = '1.1.0'
|
||||
|
||||
# Words that cannot be used as identifiers in CoffeeScript code
|
||||
exports.RESERVED = RESERVED
|
||||
@@ -34,7 +35,7 @@ exports.compile = compile = (code, options = {}) ->
|
||||
try
|
||||
(parser.parse lexer.tokenize code).compile options
|
||||
catch err
|
||||
err.message = "In #{options.fileName}, #{err.message}" if options.fileName
|
||||
err.message = "In #{options.filename}, #{err.message}" if options.filename
|
||||
throw err
|
||||
|
||||
# Tokenize a string of CoffeeScript code, and return the array of tokens.
|
||||
@@ -57,10 +58,19 @@ exports.run = (code, options) ->
|
||||
root = module
|
||||
while root.parent
|
||||
root = root.parent
|
||||
|
||||
# Set the filename.
|
||||
root.filename = fs.realpathSync options.fileName or '.'
|
||||
root.filename = process.argv[1] =
|
||||
if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
|
||||
# Clear the module cache.
|
||||
root.moduleCache = {} if root.moduleCache
|
||||
|
||||
# Assign paths for node_modules loading
|
||||
if process.binding('natives').module
|
||||
{Module} = require 'module'
|
||||
root.paths = Module._nodeModulePaths path.dirname options.filename
|
||||
|
||||
# Compile.
|
||||
if path.extname(root.filename) isnt '.coffee' or require.extensions
|
||||
root._compile compile(code, options), root.filename
|
||||
@@ -69,10 +79,19 @@ exports.run = (code, options) ->
|
||||
|
||||
# Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
|
||||
# The CoffeeScript REPL uses this to run the input.
|
||||
exports.eval = (code, options) ->
|
||||
__filename = options.fileName
|
||||
__dirname = path.dirname __filename
|
||||
eval compile code, options
|
||||
exports.eval = (code, options = {}) ->
|
||||
sandbox = options.sandbox
|
||||
unless sandbox
|
||||
sandbox =
|
||||
require: require
|
||||
module : { exports: {} }
|
||||
sandbox[g] = global[g] for g of global
|
||||
sandbox.global = sandbox
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
|
||||
sandbox.__filename = options.filename || 'eval'
|
||||
sandbox.__dirname = path.dirname sandbox.__filename
|
||||
js = compile "_=(#{code.trim()})", options
|
||||
vm.runInNewContext js, sandbox, sandbox.__filename
|
||||
|
||||
# Instantiate a Lexer for our use here.
|
||||
lexer = new Lexer
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
# External dependencies.
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
util = require 'util'
|
||||
helpers = require './helpers'
|
||||
optparse = require './optparse'
|
||||
CoffeeScript = require './coffee-script'
|
||||
@@ -30,7 +29,7 @@ SWITCHES = [
|
||||
['-c', '--compile', 'compile to JavaScript and save as .js files']
|
||||
['-i', '--interactive', 'run an interactive CoffeeScript REPL']
|
||||
['-o', '--output [DIR]', 'set the directory for compiled JavaScript']
|
||||
['-j', '--join', 'concatenate the scripts before compiling']
|
||||
['-j', '--join [FILE]', 'concatenate the scripts before compiling']
|
||||
['-w', '--watch', 'watch scripts for changes, and recompile']
|
||||
['-p', '--print', 'print the compiled JavaScript to stdout']
|
||||
['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
|
||||
@@ -59,6 +58,7 @@ exports.run = ->
|
||||
return forkNode() if opts.nodejs
|
||||
return usage() if opts.help
|
||||
return version() if opts.version
|
||||
loadRequires() if opts.require
|
||||
return require './repl' if opts.interactive
|
||||
return compileStdio() if opts.stdio
|
||||
return compileScript null, sources[0] if opts.eval
|
||||
@@ -66,6 +66,8 @@ exports.run = ->
|
||||
if opts.run
|
||||
opts.literals = sources.splice(1).concat opts.literals
|
||||
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
|
||||
process.argv[0] = 'coffee'
|
||||
process.execPath = process.mainModule.filename
|
||||
compileScripts()
|
||||
|
||||
# Asynchronously read in each CoffeeScript in a list of source files and
|
||||
@@ -76,8 +78,9 @@ compileScripts = ->
|
||||
base = path.join(source)
|
||||
compile = (source, topLevel) ->
|
||||
path.exists source, (exists) ->
|
||||
throw new Error "File not found: #{source}" unless exists
|
||||
throw new Error "File not found: #{source}" if topLevel and not exists
|
||||
fs.stat source, (err, stats) ->
|
||||
throw err if err
|
||||
if stats.isDirectory()
|
||||
fs.readdir source, (err, files) ->
|
||||
for file in files
|
||||
@@ -86,7 +89,7 @@ compileScripts = ->
|
||||
fs.readFile source, (err, code) ->
|
||||
if opts.join
|
||||
contents[sources.indexOf source] = code.toString()
|
||||
compileJoin() if helpers.compact(contents).length is sources.length
|
||||
compileJoin() if helpers.compact(contents).length > 0
|
||||
else
|
||||
compileScript(source, code.toString(), base)
|
||||
watch source, base if opts.watch and not opts.join
|
||||
@@ -98,8 +101,6 @@ compileScripts = ->
|
||||
compileScript = (file, input, base) ->
|
||||
o = opts
|
||||
options = compileOptions file
|
||||
if o.require
|
||||
require(if helpers.starts(req, '.') then fs.realpathSync(req) else req) for req in o.require
|
||||
try
|
||||
t = task = {file, input, options}
|
||||
CoffeeScript.emit 'compile', task
|
||||
@@ -133,7 +134,14 @@ compileStdio = ->
|
||||
# them together.
|
||||
compileJoin = ->
|
||||
code = contents.join '\n'
|
||||
compileScript "concatenation", code, "concatenation"
|
||||
compileScript opts.join, code, opts.join
|
||||
|
||||
# Load files that are to-be-required before compilation occurs.
|
||||
loadRequires = ->
|
||||
realFilename = module.filename
|
||||
module.filename = '.'
|
||||
require req for req in opts.require
|
||||
module.filename = realFilename
|
||||
|
||||
# Watch a source CoffeeScript file using `fs.watchFile`, recompiling it every
|
||||
# time the file is updated. May be used in combination with other options,
|
||||
@@ -157,8 +165,10 @@ writeJs = (source, js, base) ->
|
||||
compile = ->
|
||||
js = ' ' if js.length <= 0
|
||||
fs.writeFile jsPath, js, (err) ->
|
||||
if err then printLine err.message
|
||||
else if opts.compile and opts.watch then util.log "compiled #{source}"
|
||||
if err
|
||||
printLine err.message
|
||||
else if opts.compile and opts.watch
|
||||
console.log "#{(new Date).toLocaleTimeString()} - compiled #{source}"
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p #{dir}", compile
|
||||
|
||||
@@ -191,7 +201,7 @@ parseOptions = ->
|
||||
sources = o.arguments
|
||||
|
||||
# The compile-time options to pass to the CoffeeScript compiler.
|
||||
compileOptions = (fileName) -> {fileName, bare: opts.bare}
|
||||
compileOptions = (filename) -> {filename, bare: opts.bare}
|
||||
|
||||
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
|
||||
# the `node` binary, preserving the other options.
|
||||
@@ -208,9 +218,7 @@ forkNode = ->
|
||||
# shown.
|
||||
usage = ->
|
||||
printLine (new optparse.OptionParser SWITCHES, BANNER).help()
|
||||
process.exit 0
|
||||
|
||||
# Print the `--version` message and exit.
|
||||
version = ->
|
||||
printLine "CoffeeScript version #{CoffeeScript.VERSION}"
|
||||
process.exit 0
|
||||
|
||||
@@ -35,7 +35,7 @@ o = (patternString, action, options) ->
|
||||
return [patternString, '$$ = $1;', options] unless action
|
||||
action = if match = unwrap.exec action then match[1] else "(#{action}())"
|
||||
action = action.replace /\bnew /g, '$&yy.'
|
||||
action = action.replace /\b(?:Expressions\.wrap|extend)\b/g, 'yy.$&'
|
||||
action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
|
||||
[patternString, "$$ = #{action};", options]
|
||||
|
||||
# Grammatical Rules
|
||||
@@ -56,19 +56,19 @@ grammar =
|
||||
# The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
|
||||
# all parsing must end here.
|
||||
Root: [
|
||||
o '', -> new Expressions
|
||||
o '', -> new Block
|
||||
o 'Body'
|
||||
o 'Block TERMINATOR'
|
||||
]
|
||||
|
||||
# Any list of statements and expressions, separated by line breaks or semicolons.
|
||||
Body: [
|
||||
o 'Line', -> Expressions.wrap [$1]
|
||||
o 'Line', -> Block.wrap [$1]
|
||||
o 'Body TERMINATOR Line', -> $1.push $3
|
||||
o 'Body TERMINATOR'
|
||||
]
|
||||
|
||||
# Expressions and statements, which make up a line in a body.
|
||||
# Block and statements, which make up a line in a body.
|
||||
Line: [
|
||||
o 'Expression'
|
||||
o 'Statement'
|
||||
@@ -84,7 +84,7 @@ grammar =
|
||||
|
||||
# All the different types of expressions in our language. The basic unit of
|
||||
# CoffeeScript is the **Expression** -- everything that can be an expression
|
||||
# is one. Expressions serve as the building blocks of many other rules, making
|
||||
# is one. Block serve as the building blocks of many other rules, making
|
||||
# them somewhat circular.
|
||||
Expression: [
|
||||
o 'Value'
|
||||
@@ -104,7 +104,7 @@ grammar =
|
||||
# will convert some postfix forms into blocks for us, by adjusting the
|
||||
# token stream.
|
||||
Block: [
|
||||
o 'INDENT OUTDENT', -> new Expressions
|
||||
o 'INDENT OUTDENT', -> new Block
|
||||
o 'INDENT Body OUTDENT', -> $2
|
||||
]
|
||||
|
||||
@@ -127,7 +127,9 @@ grammar =
|
||||
o 'JS', -> new Literal $1
|
||||
o 'REGEX', -> new Literal $1
|
||||
o 'BOOL', ->
|
||||
new Literal if $1 is 'undefined' then 'void 0' else $1
|
||||
val = new Literal $1
|
||||
val.isUndefined = yes if $1 is 'undefined'
|
||||
val
|
||||
]
|
||||
|
||||
# Assignment of a variable, property, or index to a value.
|
||||
@@ -164,7 +166,7 @@ grammar =
|
||||
]
|
||||
|
||||
# The **Code** node is the function literal. It's defined by an indented block
|
||||
# of **Expressions** preceded by a function arrow, with an optional parameter
|
||||
# of **Block** preceded by a function arrow, with an optional parameter
|
||||
# list.
|
||||
Code: [
|
||||
o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4
|
||||
@@ -244,15 +246,19 @@ grammar =
|
||||
o ':: Identifier', -> new Access $2, 'proto'
|
||||
o '::', -> new Access new Literal 'prototype'
|
||||
o 'Index'
|
||||
o 'Slice', -> new Slice $1
|
||||
]
|
||||
|
||||
# Indexing into an object or array using bracket notation.
|
||||
Index: [
|
||||
o 'INDEX_START Expression INDEX_END', -> new Index $2
|
||||
o 'INDEX_START IndexValue INDEX_END', -> $2
|
||||
o 'INDEX_SOAK Index', -> extend $2, soak : yes
|
||||
o 'INDEX_PROTO Index', -> extend $2, proto: yes
|
||||
]
|
||||
|
||||
IndexValue: [
|
||||
o 'Expression', -> new Index $1
|
||||
o 'Slice', -> new Slice $1
|
||||
]
|
||||
|
||||
# In CoffeeScript, an object literal is simply a list of assignments.
|
||||
Object: [
|
||||
@@ -332,9 +338,9 @@ grammar =
|
||||
|
||||
# Array slice literals.
|
||||
Slice: [
|
||||
o 'INDEX_START Expression RangeDots Expression INDEX_END', -> new Range $2, $4, $3
|
||||
o 'INDEX_START Expression RangeDots INDEX_END', -> new Range $2, null, $3
|
||||
o 'INDEX_START RangeDots Expression INDEX_END', -> new Range null, $3, $2
|
||||
o 'Expression RangeDots Expression', -> new Range $1, $3, $2
|
||||
o 'Expression RangeDots', -> new Range $1, null, $2
|
||||
o 'RangeDots Expression', -> new Range null, $2, $1
|
||||
]
|
||||
|
||||
# The **ArgList** is both the list of objects passed into a function call,
|
||||
@@ -348,7 +354,7 @@ grammar =
|
||||
o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
|
||||
]
|
||||
|
||||
# Valid arguments are Expressions or Splats.
|
||||
# Valid arguments are Block or Splats.
|
||||
Arg: [
|
||||
o 'Expression'
|
||||
o 'Splat'
|
||||
@@ -401,14 +407,14 @@ grammar =
|
||||
# or postfix, with a single expression. There is no do..while.
|
||||
While: [
|
||||
o 'WhileSource Block', -> $1.addBody $2
|
||||
o 'Statement WhileSource', -> $2.addBody Expressions.wrap [$1]
|
||||
o 'Expression WhileSource', -> $2.addBody Expressions.wrap [$1]
|
||||
o 'Statement WhileSource', -> $2.addBody Block.wrap [$1]
|
||||
o 'Expression WhileSource', -> $2.addBody Block.wrap [$1]
|
||||
o 'Loop', -> $1
|
||||
]
|
||||
|
||||
Loop: [
|
||||
o 'LOOP Block', -> new While(new Literal 'true').addBody $2
|
||||
o 'LOOP Expression', -> new While(new Literal 'true').addBody Expressions.wrap [$2]
|
||||
o 'LOOP Expression', -> new While(new Literal 'true').addBody Block.wrap [$2]
|
||||
]
|
||||
|
||||
# Array, object, and range comprehensions, at the most generic level.
|
||||
@@ -483,15 +489,15 @@ grammar =
|
||||
IfBlock: [
|
||||
o 'IF Expression Block', -> new If $2, $3, type: $1
|
||||
o 'IfBlock ELSE IF Expression Block', -> $1.addElse new If $4, $5, type: $3
|
||||
o 'IfBlock ELSE Block', -> $1.addElse $3
|
||||
]
|
||||
|
||||
# The full complement of *if* expressions, including postfix one-liner
|
||||
# *if* and *unless*.
|
||||
If: [
|
||||
o 'IfBlock'
|
||||
o 'Statement POST_IF Expression', -> new If $3, Expressions.wrap([$1]), type: $2, statement: true
|
||||
o 'Expression POST_IF Expression', -> new If $3, Expressions.wrap([$1]), type: $2, statement: true
|
||||
o 'IfBlock ELSE Block', -> $1.addElse $3
|
||||
o 'Statement POST_IF Expression', -> new If $3, Block.wrap([$1]), type: $2, statement: true
|
||||
o 'Expression POST_IF Expression', -> new If $3, Block.wrap([$1]), type: $2, statement: true
|
||||
]
|
||||
|
||||
# Arithmetic and logical operators, working on one or more operands.
|
||||
|
||||
@@ -32,6 +32,7 @@ exports.Lexer = class Lexer
|
||||
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
||||
# unless explicitly asked not to.
|
||||
tokenize: (code, opts = {}) ->
|
||||
code = "\n#{code}" if WHITESPACE.test code
|
||||
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
|
||||
|
||||
@code = code # The remainder of the source code.
|
||||
@@ -79,7 +80,8 @@ exports.Lexer = class Lexer
|
||||
@token 'OWN', id
|
||||
return id.length
|
||||
forcedIdentifier = colon or
|
||||
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
|
||||
(prev = last @tokens) and (prev[0] in ['.', '?.', '::'] or
|
||||
not prev.spaced and prev[0] is '@')
|
||||
tag = 'IDENTIFIER'
|
||||
|
||||
if id in JS_KEYWORDS or
|
||||
@@ -112,7 +114,7 @@ exports.Lexer = class Lexer
|
||||
@identifierError id
|
||||
|
||||
unless forcedIdentifier
|
||||
id = COFFEE_ALIASES[id] if COFFEE_ALIASES.hasOwnProperty id
|
||||
id = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
|
||||
tag = switch id
|
||||
when '!' then 'UNARY'
|
||||
when '==', '!=' then 'COMPARE'
|
||||
@@ -169,11 +171,11 @@ exports.Lexer = class Lexer
|
||||
commentToken: ->
|
||||
return 0 unless match = @chunk.match COMMENT
|
||||
[comment, here] = match
|
||||
@line += count comment, '\n'
|
||||
if here
|
||||
@token 'HERECOMMENT', @sanitizeHeredoc here,
|
||||
herecomment: true, indent: Array(@indent + 1).join(' ')
|
||||
@token 'TERMINATOR', '\n'
|
||||
@line += count comment, '\n'
|
||||
comment.length
|
||||
|
||||
# Matches JavaScript interpolated directly into the source via backticks.
|
||||
@@ -342,8 +344,11 @@ exports.Lexer = class Lexer
|
||||
# erasing all external indentation on the left-hand side.
|
||||
sanitizeHeredoc: (doc, options) ->
|
||||
{indent, herecomment} = options
|
||||
return doc if herecomment and 0 > doc.indexOf '\n'
|
||||
unless herecomment
|
||||
if herecomment
|
||||
if HEREDOC_ILLEGAL.test doc
|
||||
throw new Error "block comment cannot contain \"*/\", starting on line #{@line + 1}"
|
||||
return doc if doc.indexOf('\n') <= 0
|
||||
else
|
||||
while match = HEREDOC_INDENT.exec doc
|
||||
attempt = match[1]
|
||||
indent = attempt if indent is null or 0 < attempt.length < indent.length
|
||||
@@ -366,7 +371,7 @@ exports.Lexer = class Lexer
|
||||
stack.push tok
|
||||
when '(', 'CALL_START'
|
||||
if stack.length then stack.pop()
|
||||
else
|
||||
else if tok[0] is '('
|
||||
tok[0] = 'PARAM_START'
|
||||
return this
|
||||
this
|
||||
@@ -438,10 +443,11 @@ exports.Lexer = class Lexer
|
||||
nested = new Lexer().tokenize inner, line: @line, rewrite: off
|
||||
nested.pop()
|
||||
nested.shift() if nested[0]?[0] is 'TERMINATOR'
|
||||
if nested.length > 1
|
||||
nested.unshift ['(', '(']
|
||||
nested.push [')', ')']
|
||||
tokens.push ['TOKENS', nested]
|
||||
if len = nested.length
|
||||
if len > 1
|
||||
nested.unshift ['(', '(']
|
||||
nested.push [')', ')']
|
||||
tokens.push ['TOKENS', nested]
|
||||
i += expr.length
|
||||
pi = i + 1
|
||||
tokens.push ['NEOSTRING', str.slice pi] if i > pi < str.length
|
||||
@@ -506,7 +512,8 @@ JS_KEYWORDS = [
|
||||
|
||||
# CoffeeScript-only keywords.
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when']
|
||||
COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
||||
|
||||
COFFEE_ALIAS_MAP =
|
||||
and : '&&'
|
||||
or : '||'
|
||||
is : '=='
|
||||
@@ -516,6 +523,9 @@ COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
||||
no : 'false'
|
||||
on : 'true'
|
||||
off : 'false'
|
||||
|
||||
COFFEE_ALIASES = (key for key of COFFEE_ALIAS_MAP)
|
||||
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES
|
||||
|
||||
# The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
# used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
@@ -534,7 +544,7 @@ exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
|
||||
|
||||
# Token matching regexes.
|
||||
IDENTIFIER = /// ^
|
||||
( [$A-Za-z_][$\w]* )
|
||||
( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
|
||||
( [^\n\S]* : (?!:) )? # Is this a property name?
|
||||
///
|
||||
|
||||
@@ -569,7 +579,7 @@ JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/
|
||||
|
||||
# Regex-matching-regexes.
|
||||
REGEX = /// ^
|
||||
/ (?! \s ) # disallow leading whitespace
|
||||
/ (?! [\s=] ) # disallow leading whitespace or equals signs
|
||||
[^ [ / \n \\ ]* # every other thing
|
||||
(?:
|
||||
(?: \\[\s\S] # anything escaped
|
||||
@@ -591,9 +601,11 @@ MULTILINER = /\n/g
|
||||
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g
|
||||
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
||||
HEREDOC_ILLEGAL = /\*\//
|
||||
|
||||
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?!\.) | :: ) ///
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
||||
|
||||
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
|
||||
|
||||
TRAILING_SPACES = /\s+$/
|
||||
|
||||
|
||||
215
src/nodes.coffee
215
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
|
||||
@@ -145,12 +145,12 @@ exports.Base = class Base
|
||||
# Is this node used to assign a certain variable?
|
||||
assigns: NO
|
||||
|
||||
#### Expressions
|
||||
#### Block
|
||||
|
||||
# The expressions body is the list of expressions that forms the body of an
|
||||
# The block is the list of expressions that forms the body of an
|
||||
# indented block of code -- the implementation of a function, a clause in an
|
||||
# `if`, `switch`, or `try`, and so on...
|
||||
exports.Expressions = class Expressions extends Base
|
||||
exports.Block = class Block extends Base
|
||||
constructor: (nodes) ->
|
||||
@expressions = compact flatten nodes or []
|
||||
|
||||
@@ -170,7 +170,7 @@ exports.Expressions = class Expressions extends Base
|
||||
@expressions.unshift node
|
||||
this
|
||||
|
||||
# If this Expressions consists of just a single node, unwrap it by pulling
|
||||
# If this Block consists of just a single node, unwrap it by pulling
|
||||
# it back out.
|
||||
unwrap: ->
|
||||
if @expressions.length is 1 then @expressions[0] else this
|
||||
@@ -188,7 +188,7 @@ exports.Expressions = class Expressions extends Base
|
||||
for exp in @expressions
|
||||
return exp if exp.jumps o
|
||||
|
||||
# An Expressions node does not return its entire body, rather it
|
||||
# An Block node does not return its entire body, rather it
|
||||
# ensures that the final expression is returned.
|
||||
makeReturn: ->
|
||||
len = @expressions.length
|
||||
@@ -196,14 +196,15 @@ exports.Expressions = class Expressions extends Base
|
||||
expr = @expressions[len]
|
||||
if expr not instanceof Comment
|
||||
@expressions[len] = expr.makeReturn()
|
||||
@expressions.splice(len, 1) if expr instanceof Return and not expr.expression
|
||||
break
|
||||
this
|
||||
|
||||
# An **Expressions** is the only node that can serve as the root.
|
||||
# An **Block** is the only node that can serve as the root.
|
||||
compile: (o = {}, level) ->
|
||||
if o.scope then super o, level else @compileRoot o
|
||||
|
||||
# Compile all expressions within the **Expressions** body. If we need to
|
||||
# Compile all expressions within the **Block** body. If we need to
|
||||
# return the result, and it's an expression, simply return it. If it's a
|
||||
# statement, ask the statement to do so.
|
||||
compileNode: (o) ->
|
||||
@@ -223,7 +224,7 @@ exports.Expressions = class Expressions extends Base
|
||||
code = codes.join(', ') or 'void 0'
|
||||
if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code
|
||||
|
||||
# If we happen to be the top-level **Expressions**, wrap everything in
|
||||
# If we happen to be the top-level **Block**, wrap everything in
|
||||
# a safety closure, unless requested not to.
|
||||
# It would be better not to generate them in the first place, but for now,
|
||||
# clean up obvious double-parentheses.
|
||||
@@ -232,7 +233,6 @@ exports.Expressions = class Expressions extends Base
|
||||
o.scope = new Scope null, this, null
|
||||
o.level = LEVEL_TOP
|
||||
code = @compileWithDeclarations o
|
||||
code = code.replace TRAILING_WHITESPACE, ''
|
||||
if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
|
||||
|
||||
# Compile the expressions body for the contents of a function, with
|
||||
@@ -250,17 +250,17 @@ exports.Expressions = class Expressions extends Base
|
||||
post = @compileNode o
|
||||
{scope} = o
|
||||
if scope.expressions is this
|
||||
if not o.globals and o.scope.hasDeclarations()
|
||||
if o.scope.hasDeclarations()
|
||||
code += "#{@tab}var #{ scope.declaredVariables().join(', ') };\n"
|
||||
if scope.hasAssignments
|
||||
code += "#{@tab}var #{ multident scope.assignedVariables().join(', '), @tab };\n"
|
||||
code + post
|
||||
|
||||
# Wrap up the given nodes as an **Expressions**, unless it already happens
|
||||
# Wrap up the given nodes as an **Block**, unless it already happens
|
||||
# to be one.
|
||||
@wrap: (nodes) ->
|
||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
|
||||
new Expressions nodes
|
||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block
|
||||
new Block nodes
|
||||
|
||||
#### Literal
|
||||
|
||||
@@ -289,7 +289,12 @@ exports.Literal = class Literal extends Base
|
||||
if not (o and (o.loop or o.block and (@value isnt 'continue'))) then this else no
|
||||
|
||||
compileNode: (o) ->
|
||||
code = if @value.reserved then "\"#{@value}\"" else @value
|
||||
code = if @isUndefined
|
||||
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
|
||||
else if @value.reserved
|
||||
"\"#{@value}\""
|
||||
else
|
||||
@value
|
||||
if @isStatement() then "#{@tab}#{code};" else code
|
||||
|
||||
toString: ->
|
||||
@@ -300,7 +305,8 @@ exports.Literal = class Literal extends Base
|
||||
# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't
|
||||
# make sense.
|
||||
exports.Return = class Return extends Base
|
||||
constructor: (@expression) ->
|
||||
constructor: (expr) ->
|
||||
@expression = expr if expr and not expr.unwrap().isUndefined
|
||||
|
||||
children: ['expression']
|
||||
|
||||
@@ -398,19 +404,22 @@ exports.Value = class Value extends Base
|
||||
|
||||
# Unfold a soak into an `If`: `a?.b` -> `a.b if a?`
|
||||
unfoldSoak: (o) ->
|
||||
if ifn = @base.unfoldSoak o
|
||||
Array::push.apply ifn.body.properties, @properties
|
||||
return ifn
|
||||
for prop, i in @properties when prop.soak
|
||||
prop.soak = off
|
||||
fst = new Value @base, @properties.slice 0, i
|
||||
snd = new Value @base, @properties.slice i
|
||||
if fst.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, fst
|
||||
snd.base = ref
|
||||
return new If new Existence(fst), snd, soak: on
|
||||
null
|
||||
return @unfoldedSoak if @unfoldedSoak?
|
||||
result = do =>
|
||||
if ifn = @base.unfoldSoak o
|
||||
Array::push.apply ifn.body.properties, @properties
|
||||
return ifn
|
||||
for prop, i in @properties when prop.soak
|
||||
prop.soak = off
|
||||
fst = new Value @base, @properties.slice 0, i
|
||||
snd = new Value @base, @properties.slice i
|
||||
if fst.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, fst
|
||||
snd.base = ref
|
||||
return new If new Existence(fst), snd, soak: on
|
||||
null
|
||||
@unfoldedSoak = result or no
|
||||
|
||||
#### Comment
|
||||
|
||||
@@ -492,12 +501,31 @@ exports.Call = class Call extends Base
|
||||
ifn = unfoldSoak o, call, 'variable'
|
||||
ifn
|
||||
|
||||
# Walk through the objects in the arguments, moving over simple values.
|
||||
# This allows syntax like `call a: b, c` into `call({a: b}, c);`
|
||||
filterImplicitObjects: (list) ->
|
||||
nodes = []
|
||||
for node in list
|
||||
unless node.isObject?() and node.base.generated
|
||||
nodes.push node
|
||||
continue
|
||||
obj = null
|
||||
for prop in node.base.properties
|
||||
if prop instanceof Assign
|
||||
nodes.push obj = new Obj properties = [], true if not obj
|
||||
properties.push prop
|
||||
else
|
||||
nodes.push prop
|
||||
obj = null
|
||||
nodes
|
||||
|
||||
# Compile a vanilla function call.
|
||||
compileNode: (o) ->
|
||||
@variable?.front = @front
|
||||
if code = Splat.compileSplattedArray o, @args, true
|
||||
return @compileSplat o, code
|
||||
args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
|
||||
args = @filterImplicitObjects @args
|
||||
args = (arg.compile o, LEVEL_LIST for arg in args).join ', '
|
||||
if @isSuper
|
||||
@superReference(o) + ".call(this#{ args and ', ' + args })"
|
||||
else
|
||||
@@ -517,11 +545,11 @@ exports.Call = class Call extends Base
|
||||
if @isNew
|
||||
idt = @tab + TAB
|
||||
return """
|
||||
(function(func, args, ctor) {
|
||||
#{idt}ctor.prototype = func.prototype;
|
||||
#{idt}var child = new ctor, result = func.apply(child, args);
|
||||
#{idt}return typeof result === "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
(function(func, args, ctor) {
|
||||
#{idt}ctor.prototype = func.prototype;
|
||||
#{idt}var child = new ctor, result = func.apply(child, args);
|
||||
#{idt}return typeof result === "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
"""
|
||||
base = new Value @variable
|
||||
if (name = base.properties.pop()) and base.isComplex()
|
||||
@@ -529,6 +557,7 @@ exports.Call = class Call extends Base
|
||||
fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
|
||||
else
|
||||
fun = base.compile o, LEVEL_ACCESS
|
||||
fun = "(#{fun})" if SIMPLENUM.test fun
|
||||
if name
|
||||
ref = fun
|
||||
fun += name.compile o
|
||||
@@ -616,10 +645,9 @@ exports.Range = class Range extends Base
|
||||
idx = del o, 'index'
|
||||
step = del o, 'step'
|
||||
vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
intro = "(#{@fromVar} <= #{@toVar} ? #{idx}"
|
||||
compare = "#{intro} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar})"
|
||||
stepPart = if step then step.compile(o) else '1'
|
||||
incr = if step then "#{idx} += #{stepPart}" else "#{intro} += #{stepPart} : #{idx} -= #{stepPart})"
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
compare = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
|
||||
incr = if step then "#{idx} += #{step.compile(o)}" else "#{cond} ? #{idx}++ : #{idx}--"
|
||||
"#{vars}; #{compare}; #{incr}"
|
||||
|
||||
# Compile a simple range comprehension, with integers.
|
||||
@@ -645,13 +673,13 @@ exports.Range = class Range extends Base
|
||||
pre = "\n#{idt}#{result} = [];"
|
||||
if @fromNum and @toNum
|
||||
o.index = i
|
||||
body = @compileSimple o
|
||||
body = @compileSimple o
|
||||
else
|
||||
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
clause = "#{@fromVar} <= #{@toVar} ?"
|
||||
body = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
|
||||
vars = "#{i} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
|
||||
cond = "#{@fromVar} <= #{@toVar}"
|
||||
body = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--"
|
||||
post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}"
|
||||
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).call(this)"
|
||||
"(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this, arguments)"
|
||||
|
||||
#### Slice
|
||||
|
||||
@@ -693,6 +721,9 @@ exports.Obj = class Obj extends Base
|
||||
compileNode: (o) ->
|
||||
props = @properties
|
||||
return (if @front then '({})' else '{}') unless props.length
|
||||
if @generated
|
||||
for node in props when node instanceof Value
|
||||
throw new Error 'cannot have an implicit value in an implicit object'
|
||||
idt = o.indent += TAB
|
||||
lastNoncom = @lastNonComment @properties
|
||||
props = for prop, i in props
|
||||
@@ -727,11 +758,14 @@ exports.Arr = class Arr extends Base
|
||||
|
||||
children: ['objects']
|
||||
|
||||
filterImplicitObjects: Call::filterImplicitObjects
|
||||
|
||||
compileNode: (o) ->
|
||||
return '[]' unless @objects.length
|
||||
o.indent += TAB
|
||||
return code if code = Splat.compileSplattedArray o, @objects
|
||||
code = (obj.compile o, LEVEL_LIST for obj in @objects).join ', '
|
||||
objs = @filterImplicitObjects @objects
|
||||
return code if code = Splat.compileSplattedArray o, objs
|
||||
code = (obj.compile o, LEVEL_LIST for obj in objs).join ', '
|
||||
if code.indexOf('\n') >= 0
|
||||
"[\n#{o.indent}#{code}\n#{@tab}]"
|
||||
else
|
||||
@@ -747,7 +781,7 @@ exports.Arr = class Arr extends Base
|
||||
# Initialize a **Class** with its name, an optional superclass, and a
|
||||
# list of prototype property assignments.
|
||||
exports.Class = class Class extends Base
|
||||
constructor: (@variable, @parent, @body = new Expressions) ->
|
||||
constructor: (@variable, @parent, @body = new Block) ->
|
||||
@boundFuncs = []
|
||||
@body.classBody = yes
|
||||
|
||||
@@ -811,7 +845,7 @@ exports.Class = class Class extends Base
|
||||
walkBody: (name) ->
|
||||
@traverseChildren false, (child) =>
|
||||
return false if child instanceof Class
|
||||
if child instanceof Expressions
|
||||
if child instanceof Block
|
||||
for node, i in exps = child.expressions
|
||||
if node instanceof Value and node.isObject(true)
|
||||
exps[i] = @addProperties node, name
|
||||
@@ -838,8 +872,8 @@ exports.Class = class Class extends Base
|
||||
|
||||
@setContext name
|
||||
@walkBody name
|
||||
@body.expressions.unshift new Extends lname, @parent if @parent
|
||||
@ensureConstructor name
|
||||
@body.expressions.splice 1, 0, new Extends(lname, @parent) if @parent
|
||||
@body.expressions.push lname
|
||||
@addBoundFunctions o
|
||||
|
||||
@@ -856,7 +890,7 @@ exports.Assign = class Assign extends Base
|
||||
@param = options and options.param
|
||||
|
||||
# Matchers for detecting class/method names
|
||||
METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/
|
||||
METHOD_DEF: /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w\x7f-\uffff]*)$/
|
||||
|
||||
children: ['variable', 'value']
|
||||
|
||||
@@ -876,18 +910,18 @@ exports.Assign = class Assign extends Base
|
||||
return @compileSplice o if @variable.isSplice()
|
||||
return @compileConditional o if @context in ['||=', '&&=', '?=']
|
||||
name = @variable.compile o, LEVEL_LIST
|
||||
if @value instanceof Code and match = @METHOD_DEF.exec name
|
||||
@value.name = match[2]
|
||||
@value.klass = match[1] if match[1]
|
||||
val = @value.compile o, LEVEL_LIST
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
unless @variable.isAssignable()
|
||||
unless @context or @variable.isAssignable()
|
||||
throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned."
|
||||
unless @context or isValue and (@variable.namespaced or @variable.hasProperties())
|
||||
if @param
|
||||
o.scope.add name, 'var'
|
||||
else
|
||||
o.scope.find name
|
||||
if @value instanceof Code and match = @METHOD_DEF.exec name
|
||||
@value.name = match[2]
|
||||
@value.klass = match[1] if match[1]
|
||||
val = @value.compile o, LEVEL_LIST
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
val = name + " #{ @context or '=' } " + val
|
||||
if o.level <= LEVEL_LIST then val else "(#{val})"
|
||||
|
||||
@@ -899,7 +933,9 @@ exports.Assign = class Assign extends Base
|
||||
top = o.level is LEVEL_TOP
|
||||
{value} = this
|
||||
{objects} = @variable.base
|
||||
return value.compile o unless olen = objects.length
|
||||
unless olen = objects.length
|
||||
code = value.compile o
|
||||
return if o.level >= LEVEL_OP then "(#{code})" else code
|
||||
isObject = @variable.isObject()
|
||||
if top and olen is 1 and (obj = objects[0]) not instanceof Splat
|
||||
# Unroll simplest cases: `{v} = x` -> `v = x.v`
|
||||
@@ -995,7 +1031,7 @@ exports.Assign = class Assign extends Base
|
||||
exports.Code = class Code extends Base
|
||||
constructor: (params, body, tag) ->
|
||||
@params = params or []
|
||||
@body = body or new Expressions
|
||||
@body = body or new Block
|
||||
@bound = tag is 'boundfunc'
|
||||
@context = 'this' if @bound
|
||||
|
||||
@@ -1015,10 +1051,10 @@ exports.Code = class Code extends Base
|
||||
o.scope.shared = del o, 'sharedScope'
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
delete o.globals
|
||||
vars = []
|
||||
exprs = []
|
||||
for param in @params when param.splat
|
||||
o.scope.add param.name.value, 'var' if param.name.value
|
||||
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
|
||||
new Value new Literal 'arguments'
|
||||
break
|
||||
@@ -1163,7 +1199,7 @@ exports.While = class While extends Base
|
||||
rvar = o.scope.freeVariable 'results'
|
||||
set = "#{@tab}#{rvar} = [];\n"
|
||||
body = Push.wrap rvar, body if body
|
||||
body = Expressions.wrap [new If @guard, body] if @guard
|
||||
body = Block.wrap [new If @guard, body] if @guard
|
||||
body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}"
|
||||
code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}"
|
||||
if @returns
|
||||
@@ -1177,10 +1213,13 @@ exports.While = class While extends Base
|
||||
exports.Op = class Op extends Base
|
||||
constructor: (op, first, second, flip) ->
|
||||
return new In first, second if op is 'in'
|
||||
return new Call first, first.params or [] if op is 'do'
|
||||
if op is 'do'
|
||||
call = new Call first, first.params or []
|
||||
call.do = yes
|
||||
return call
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call
|
||||
first = new Parens first if first instanceof Code and first.bound
|
||||
return first.newInstance() if first instanceof Call and not first.do
|
||||
first = new Parens first if first instanceof Code and first.bound or first.do
|
||||
@operator = CONVERSIONS[op] or op
|
||||
@first = first
|
||||
@second = second
|
||||
@@ -1262,18 +1301,19 @@ exports.Op = class Op extends Base
|
||||
|
||||
compileExistence: (o) ->
|
||||
if @first.isComplex()
|
||||
ref = o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign new Literal(ref), @first
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, @first
|
||||
else
|
||||
fst = @first
|
||||
ref = fst.compile o
|
||||
new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL_LIST }"
|
||||
ref = fst
|
||||
new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o
|
||||
|
||||
# Compile a unary **Op**.
|
||||
compileUnary: (o) ->
|
||||
parts = [op = @operator]
|
||||
parts.push ' ' if op in ['new', 'typeof', 'delete'] or
|
||||
op in ['+', '-'] and @first instanceof Op and @first.operator is op
|
||||
@first = new Parens @first if op is 'new' and @first.isStatement o
|
||||
parts.push @first.compile o, LEVEL_OP
|
||||
parts.reverse() if @flip
|
||||
parts.join ''
|
||||
@@ -1300,6 +1340,7 @@ exports.In = class In extends Base
|
||||
[cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
|
||||
tests = for item, i in @array.base.objects
|
||||
(if i then ref else sub) + cmp + item.compile o, LEVEL_OP
|
||||
return 'false' if tests.length is 0
|
||||
tests = tests.join cnj
|
||||
if o.level < LEVEL_OP then tests else "(#{tests})"
|
||||
|
||||
@@ -1379,9 +1420,9 @@ exports.Existence = class Existence extends Base
|
||||
code = @expression.compile o, LEVEL_OP
|
||||
code = if IDENTIFIER.test(code) and not o.scope.check code
|
||||
if @negated
|
||||
"typeof #{code} == \"undefined\" || #{code} === null"
|
||||
"typeof #{code} === \"undefined\" || #{code} === null"
|
||||
else
|
||||
"typeof #{code} != \"undefined\" && #{code} !== null"
|
||||
"typeof #{code} !== \"undefined\" && #{code} !== null"
|
||||
else
|
||||
sym = if @negated then '==' else '!='
|
||||
"#{code} #{sym} null"
|
||||
@@ -1425,7 +1466,7 @@ exports.Parens = class Parens extends Base
|
||||
exports.For = class For extends Base
|
||||
constructor: (body, source) ->
|
||||
{@source, @guard, @step, @name, @index} = source
|
||||
@body = Expressions.wrap [body]
|
||||
@body = Block.wrap [body]
|
||||
@own = !!source.own
|
||||
@object = !!source.object
|
||||
[@name, @index] = [@index, @name] if @object
|
||||
@@ -1451,7 +1492,7 @@ exports.For = class For extends Base
|
||||
# comprehensions. Some of the generated code can be shared in common, and
|
||||
# some cannot.
|
||||
compileNode: (o) ->
|
||||
body = Expressions.wrap [@body]
|
||||
body = Block.wrap [@body]
|
||||
lastJumps = last(body.expressions)?.jumps()
|
||||
@returns = no if lastJumps and lastJumps instanceof Return
|
||||
source = if @range then @source.base else @source
|
||||
@@ -1485,7 +1526,7 @@ exports.For = class For extends Base
|
||||
returnResult = "\n#{@tab}return #{rvar};"
|
||||
body = Push.wrap rvar, body
|
||||
if @guard
|
||||
body = Expressions.wrap [new If @guard, body]
|
||||
body = Block.wrap [new If @guard, body]
|
||||
if @pattern
|
||||
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
|
||||
defPart += @pluckDirectCall o, body
|
||||
@@ -1551,9 +1592,8 @@ exports.Switch = class Switch extends Base
|
||||
code += body + '\n' if body = block.compile o, LEVEL_TOP
|
||||
break if i is @cases.length - 1 and not @otherwise
|
||||
expr = @lastNonComment block.expressions
|
||||
jumper = expr.jumps()
|
||||
if not expr or not jumper or (jumper instanceof Literal and jumper.value is 'debugger')
|
||||
code += idt2 + 'break;\n'
|
||||
continue if expr instanceof Return or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger')
|
||||
code += idt2 + 'break;\n'
|
||||
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
|
||||
code + @tab + '}'
|
||||
|
||||
@@ -1582,7 +1622,7 @@ exports.If = class If extends Base
|
||||
@elseBodyNode().addElse elseBody
|
||||
else
|
||||
@isChain = elseBody instanceof If
|
||||
@elseBody = @ensureExpressions elseBody
|
||||
@elseBody = @ensureBlock elseBody
|
||||
this
|
||||
|
||||
# The **If** only compiles into a statement if either of its bodies needs
|
||||
@@ -1597,12 +1637,12 @@ exports.If = class If extends Base
|
||||
if @isStatement o then @compileStatement o else @compileExpression o
|
||||
|
||||
makeReturn: ->
|
||||
@body and= new Expressions [@body.makeReturn()]
|
||||
@elseBody and= new Expressions [@elseBody.makeReturn()]
|
||||
@body and= new Block [@body.makeReturn()]
|
||||
@elseBody and= new Block [@elseBody.makeReturn()]
|
||||
this
|
||||
|
||||
ensureExpressions: (node) ->
|
||||
if node instanceof Expressions then node else new Expressions [node]
|
||||
ensureBlock: (node) ->
|
||||
if node instanceof Block then node else new Block [node]
|
||||
|
||||
# Compile the **If** as a regular *if-else* statement. Flattened chains
|
||||
# force inner *else* bodies into statement form.
|
||||
@@ -1610,7 +1650,7 @@ exports.If = class If extends Base
|
||||
child = del o, 'chainChild'
|
||||
cond = @condition.compile o, LEVEL_PAREN
|
||||
o.indent += TAB
|
||||
body = @ensureExpressions(@body).compile o
|
||||
body = @ensureBlock(@body).compile o
|
||||
body = "\n#{body}\n#{@tab}" if body
|
||||
ifPart = "if (#{cond}) {#{body}}"
|
||||
ifPart = @tab + ifPart unless child
|
||||
@@ -1657,17 +1697,16 @@ Closure =
|
||||
# then make sure that the closure wrapper preserves the original values.
|
||||
wrap: (expressions, statement, noReturn) ->
|
||||
return expressions if expressions.jumps()
|
||||
func = new Code [], Expressions.wrap [expressions]
|
||||
func = new Code [], Block.wrap [expressions]
|
||||
args = []
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or
|
||||
( expressions.contains @literalThis)
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
|
||||
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
||||
args = [new Literal 'this']
|
||||
args.push new Literal 'arguments' if mentionsArgs
|
||||
func = new Value func, [new Access meth]
|
||||
func.noReturn = noReturn
|
||||
call = new Call func, args
|
||||
if statement then Expressions.wrap [call] else call
|
||||
if statement then Block.wrap [call] else call
|
||||
|
||||
literalArgs: (node) ->
|
||||
node instanceof Literal and node.value is 'arguments' and not node.asKey
|
||||
@@ -1731,11 +1770,7 @@ LEVEL_ACCESS = 6 # ...[0]
|
||||
# Tabs are two spaces for pretty printing.
|
||||
TAB = ' '
|
||||
|
||||
# Trim out all trailing whitespace, so that the generated code plays nice
|
||||
# with Git.
|
||||
TRAILING_WHITESPACE = /[ \t]+$/gm
|
||||
|
||||
IDENTIFIER = /^[$A-Za-z_][$\w]*$/
|
||||
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/
|
||||
SIMPLENUM = /^[+-]?\d+$/
|
||||
|
||||
# Is a literal value a string?
|
||||
|
||||
@@ -47,7 +47,7 @@ exports.OptionParser = class OptionParser
|
||||
# Return the help text for this **OptionParser**, listing and describing all
|
||||
# of the valid options, for `--help` and such.
|
||||
help: ->
|
||||
lines = ['Available options:']
|
||||
lines = []
|
||||
lines.unshift "#{@banner}\n" if @banner
|
||||
for rule in @rules
|
||||
spaces = 15 - rule.longFlag.length
|
||||
|
||||
@@ -6,37 +6,102 @@
|
||||
|
||||
# Require the **coffee-script** module to get access to the compiler.
|
||||
CoffeeScript = require './coffee-script'
|
||||
helpers = require './helpers'
|
||||
readline = require 'readline'
|
||||
{inspect} = require 'util'
|
||||
{Script} = require 'vm'
|
||||
|
||||
# Start by opening up **stdio**.
|
||||
stdio = process.openStdin()
|
||||
# REPL Setup
|
||||
|
||||
# Config
|
||||
enableColours = no
|
||||
unless process.platform is 'win32'
|
||||
enableColours = not process.env.NODE_DISABLE_COLORS
|
||||
|
||||
# Start by opening up `stdin` and `stdout`.
|
||||
stdin = process.openStdin()
|
||||
stdout = process.stdout
|
||||
|
||||
# Log an error.
|
||||
error = (err) ->
|
||||
stdio.write (err.stack or err.toString()) + '\n\n'
|
||||
stdout.write (err.stack or err.toString()) + '\n\n'
|
||||
|
||||
# Quick alias for quitting the REPL.
|
||||
helpers.extend global, quit: -> process.exit(0)
|
||||
# The current backlog of multi-line code.
|
||||
backlog = ''
|
||||
|
||||
# The main REPL function. **run** is called every time a line of code is entered.
|
||||
# Attempt to evaluate the command. If there's an exception, print it out instead
|
||||
# of exiting.
|
||||
run = (buffer) ->
|
||||
try
|
||||
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
|
||||
console.log val if val isnt undefined
|
||||
catch err
|
||||
error err
|
||||
repl.prompt()
|
||||
run = do ->
|
||||
sandbox =
|
||||
require: require
|
||||
module : { exports: {} }
|
||||
sandbox[g] = global[g] for g of global
|
||||
sandbox.global = sandbox
|
||||
sandbox.global.global = sandbox.global.root = sandbox.global.GLOBAL = sandbox
|
||||
(buffer) ->
|
||||
code = backlog += '\n' + buffer.toString()
|
||||
if code[code.length - 1] is '\\'
|
||||
return backlog = backlog[0...backlog.length - 1]
|
||||
backlog = ''
|
||||
try
|
||||
val = CoffeeScript.eval code, {
|
||||
sandbox,
|
||||
bare: on,
|
||||
filename: 'repl'
|
||||
}
|
||||
unless val is undefined
|
||||
process.stdout.write inspect(val, no, 2, enableColours) + '\n'
|
||||
catch err
|
||||
error err
|
||||
repl.prompt()
|
||||
|
||||
## Autocompletion
|
||||
|
||||
# Regexes to match complete-able bits of text.
|
||||
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/
|
||||
SIMPLEVAR = /\s*(\w*)$/i
|
||||
|
||||
# Returns a list of completions, and the completed text.
|
||||
autocomplete = (text) ->
|
||||
completeAttribute(text) or completeVariable(text) or [[], text]
|
||||
|
||||
# Attempt to autocomplete a chained dotted attribute: `one.two.three`.
|
||||
completeAttribute = (text) ->
|
||||
if match = text.match ACCESSOR
|
||||
[all, obj, prefix] = match
|
||||
try
|
||||
val = Script.runInThisContext obj
|
||||
catch error
|
||||
return [[], text]
|
||||
completions = getCompletions prefix, getPropertyNames val
|
||||
[completions, prefix]
|
||||
|
||||
# Attempt to autocomplete an in-scope free variable: `one`.
|
||||
completeVariable = (text) ->
|
||||
if free = text.match(SIMPLEVAR)?[1]
|
||||
scope = Script.runInThisContext 'this'
|
||||
completions = getCompletions free, CoffeeScript.RESERVED.concat(getPropertyNames scope)
|
||||
[completions, free]
|
||||
|
||||
# Return elements of candidates for which `prefix` is a prefix.
|
||||
getCompletions = (prefix, candidates) ->
|
||||
(el for el in candidates when el.indexOf(prefix) is 0)
|
||||
|
||||
# Return all "own" properties of an object.
|
||||
getPropertyNames = (obj) ->
|
||||
(name for own name of obj)
|
||||
|
||||
# Make sure that uncaught exceptions don't kill the REPL.
|
||||
process.on 'uncaughtException', error
|
||||
|
||||
# Create the REPL by listening to **stdin**.
|
||||
repl = readline.createInterface stdio
|
||||
if readline.createInterface.length < 3
|
||||
repl = readline.createInterface stdin, autocomplete
|
||||
stdin.on 'data', (buffer) -> repl.write buffer
|
||||
else
|
||||
repl = readline.createInterface stdin, stdout, autocomplete
|
||||
|
||||
repl.setPrompt 'coffee> '
|
||||
stdio.on 'data', (buffer) -> repl.write buffer
|
||||
repl.on 'close', -> stdio.destroy()
|
||||
repl.on 'close', -> stdin.destroy()
|
||||
repl.on 'line', run
|
||||
repl.prompt()
|
||||
|
||||
@@ -104,7 +104,10 @@ class exports.Rewriter
|
||||
not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':')) or
|
||||
(tag is ',' and one and
|
||||
one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
|
||||
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
|
||||
action = (token, i) ->
|
||||
tok = ['}', '}', token[2]]
|
||||
tok.generated = yes
|
||||
@tokens.splice i, 0, tok
|
||||
@scanTokens (token, i, tokens) ->
|
||||
if (tag = token[0]) in EXPRESSION_START
|
||||
stack.push [(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag), i]
|
||||
@@ -143,6 +146,7 @@ class exports.Rewriter
|
||||
seenSingle = no
|
||||
noCall = no if tag in LINEBREAKS
|
||||
token.call = yes if prev and not prev.spaced and tag is '?'
|
||||
return 1 if token.fromThen
|
||||
return 1 unless callObject or
|
||||
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
|
||||
(tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)
|
||||
|
||||
@@ -14,10 +14,10 @@ exports.Scope = class Scope
|
||||
@root: null
|
||||
|
||||
# Initialize a scope with its parent, for lookups up the chain,
|
||||
# as well as a reference to the **Expressions** node is belongs to, which is
|
||||
# as well as a reference to the **Block** node is belongs to, which is
|
||||
# where it should declare its variables, and a reference to the function that
|
||||
# it wraps.
|
||||
constructor:(@parent, @expressions, @method) ->
|
||||
constructor: (@parent, @expressions, @method) ->
|
||||
@variables = [{name: 'arguments', type: 'arguments'}]
|
||||
@positions = {}
|
||||
Scope.root = this unless @parent
|
||||
@@ -66,7 +66,7 @@ exports.Scope = class Scope
|
||||
# compiler-generated variable. `_var`, `_var2`, and so on...
|
||||
freeVariable: (type) ->
|
||||
index = 0
|
||||
index++ while @check((temp = @temporary type, index), true)
|
||||
index++ while @check((temp = @temporary type, index))
|
||||
@add temp, 'var', yes
|
||||
temp
|
||||
|
||||
|
||||
77
test/arrays.coffee
Normal file
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,6 +1,12 @@
|
||||
# Assignment
|
||||
# ----------
|
||||
|
||||
# * Assignment
|
||||
# * Compound Assignment
|
||||
# * Destructuring Assignment
|
||||
# * Context Property (@) Assignment
|
||||
# * Existential Assignment (?=)
|
||||
|
||||
test "context property assignment (using @)", ->
|
||||
nonce = {}
|
||||
addMethod = ->
|
||||
@@ -19,44 +25,80 @@ test "compound assignments should not declare", ->
|
||||
eq Math, (-> Math or= 0)()
|
||||
|
||||
|
||||
#### Statements as Expressions
|
||||
# Compound Assignment
|
||||
|
||||
test "assign the result of a try/catch block", ->
|
||||
# multiline
|
||||
result = try
|
||||
nonexistent * missing
|
||||
catch error
|
||||
true
|
||||
eq true, result
|
||||
|
||||
# single line
|
||||
result = try nonexistent * missing catch error then true
|
||||
eq true, result
|
||||
|
||||
test "conditionals", ->
|
||||
# assign inside the condition of a conditional statement
|
||||
test "boolean operators", ->
|
||||
nonce = {}
|
||||
if a = nonce then 1
|
||||
|
||||
a = 0
|
||||
a or= nonce
|
||||
eq nonce, a
|
||||
1 if b = nonce
|
||||
eq nonce, b
|
||||
|
||||
# assign the result of a conditional statement
|
||||
c = if true then nonce
|
||||
eq nonce, c
|
||||
b = 1
|
||||
b or= nonce
|
||||
eq 1, b
|
||||
|
||||
test "assign inside the condition of a `while` loop", ->
|
||||
nonce = {}
|
||||
count = 1
|
||||
a = nonce while count--
|
||||
eq nonce, a
|
||||
count = 1
|
||||
while count--
|
||||
b = nonce
|
||||
eq nonce, b
|
||||
c = 0
|
||||
c and= nonce
|
||||
eq 0, c
|
||||
|
||||
d = 1
|
||||
d and= nonce
|
||||
eq nonce, d
|
||||
|
||||
#### Compound Assignment
|
||||
# ensure that RHS is treated as a group
|
||||
e = f = false
|
||||
e and= f or true
|
||||
eq false, e
|
||||
|
||||
test "compound assignment as a sub expression", ->
|
||||
[a, b, c] = [1, 2, 3]
|
||||
eq 6, (a + b += c)
|
||||
eq 1, a
|
||||
eq 5, b
|
||||
eq 3, c
|
||||
|
||||
# *note: this test could still use refactoring*
|
||||
test "compound assignment should be careful about caching variables", ->
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq 1, list[1]
|
||||
eq 1, count
|
||||
|
||||
list[++count] ?= 2
|
||||
eq 2, list[2]
|
||||
eq 2, count
|
||||
|
||||
list[count++] and= 6
|
||||
eq 6, list[2]
|
||||
eq 3, count
|
||||
|
||||
base = ->
|
||||
++count
|
||||
base
|
||||
|
||||
base().four or= 4
|
||||
eq 4, base.four
|
||||
eq 4, count
|
||||
|
||||
base().five ?= 5
|
||||
eq 5, base.five
|
||||
eq 5, count
|
||||
|
||||
test "compound assignment with implicit objects", ->
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
eq 1, obj.one
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
eq undefined, obj.one
|
||||
eq 2, obj.two
|
||||
|
||||
test "compound assignment (math operators)", ->
|
||||
num = 10
|
||||
@@ -92,7 +134,137 @@ test "more compound assignment", ->
|
||||
eq c, val
|
||||
|
||||
|
||||
#### Destructuring Assignment
|
||||
# Destructuring Assignment
|
||||
|
||||
# NO TESTS?!
|
||||
# TODO: make tests for destructuring assignment
|
||||
test "empty destructuring assignment", ->
|
||||
{} = [] = undefined
|
||||
|
||||
test "chained destructuring assignments", ->
|
||||
[a] = {0: b} = {'0': c} = [nonce={}]
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
eq nonce, c
|
||||
|
||||
test "variable swapping to verify caching of RHS values when appropriate", ->
|
||||
a = nonceA = {}
|
||||
b = nonceB = {}
|
||||
c = nonceC = {}
|
||||
[a, b, c] = [b, c, a]
|
||||
eq nonceB, a
|
||||
eq nonceC, b
|
||||
eq nonceA, c
|
||||
[a, b, c] = [b, c, a]
|
||||
eq nonceC, a
|
||||
eq nonceA, b
|
||||
eq nonceB, c
|
||||
fn = ->
|
||||
[a, b, c] = [b, c, a]
|
||||
arrayEq [nonceA,nonceB,nonceC], fn()
|
||||
eq nonceA, a
|
||||
eq nonceB, b
|
||||
eq nonceC, c
|
||||
|
||||
test "#713", ->
|
||||
nonces = [nonceA={},nonceB={}]
|
||||
eq nonces, [a, b] = [c, d] = nonces
|
||||
eq nonceA, a
|
||||
eq nonceA, c
|
||||
eq nonceB, b
|
||||
eq nonceB, d
|
||||
|
||||
test "destructuring assignment with splats", ->
|
||||
a = {}; b = {}; c = {}; d = {}; e = {}
|
||||
[x,y...,z] = [a,b,c,d,e]
|
||||
eq a, x
|
||||
arrayEq [b,c,d], y
|
||||
eq e, z
|
||||
|
||||
test "deep destructuring assignment with splats", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}; g={}; h={}; i={}
|
||||
[u, [v, w..., x], y..., z] = [a, [b, c, d, e], f, g, h, i]
|
||||
eq a, u
|
||||
eq b, v
|
||||
arrayEq [c,d], w
|
||||
eq e, x
|
||||
arrayEq [f,g,h], y
|
||||
eq i, z
|
||||
|
||||
test "destructuring assignment with objects", ->
|
||||
a={}; b={}; c={}
|
||||
obj = {a,b,c}
|
||||
{a:x, b:y, c:z} = obj
|
||||
eq a, x
|
||||
eq b, y
|
||||
eq c, z
|
||||
|
||||
test "deep destructuring assignment with objects", ->
|
||||
a={}; b={}; c={}; d={}
|
||||
obj = {
|
||||
a
|
||||
b: {
|
||||
'c': {
|
||||
d: [
|
||||
b
|
||||
{e: c, f: d}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
{a: w, 'b': {c: d: [x, {'f': z, e: y}]}} = obj
|
||||
eq a, w
|
||||
eq b, x
|
||||
eq c, y
|
||||
eq d, z
|
||||
|
||||
test "destructuring assignment with objects and splats", ->
|
||||
a={}; b={}; c={}; d={}
|
||||
obj = a: b: [a, b, c, d]
|
||||
{a: b: [y, z...]} = obj
|
||||
eq a, y
|
||||
arrayEq [b,c,d], z
|
||||
|
||||
test "destructuring assignment against an expression", ->
|
||||
a={}; b={}
|
||||
[y, z] = if true then [a, b] else [b, a]
|
||||
eq a, y
|
||||
eq b, z
|
||||
|
||||
test "bracket insertion when necessary", ->
|
||||
[a] = [0] ? [1]
|
||||
eq a, 0
|
||||
|
||||
# for implicit destructuring assignment in comprehensions, see the comprehension tests
|
||||
|
||||
test "destructuring assignment with context (@) properties", ->
|
||||
a={}; b={}; c={}; d={}; e={}
|
||||
obj =
|
||||
fn: () ->
|
||||
local = [a, {b, c}, d, e]
|
||||
[@a, {b: @b, c: @c}, @d, @e] = local
|
||||
eq undefined, obj[key] for key in ['a','b','c','d','e']
|
||||
obj.fn()
|
||||
eq a, obj.a
|
||||
eq b, obj.b
|
||||
eq c, obj.c
|
||||
eq d, obj.d
|
||||
eq e, obj.e
|
||||
|
||||
test "#1024", ->
|
||||
eq 2 * [] = 3 + 5, 16
|
||||
|
||||
|
||||
# Existential Assignment
|
||||
|
||||
test "existential assignment", ->
|
||||
nonce = {}
|
||||
a = false
|
||||
a ?= nonce
|
||||
eq false, a
|
||||
b = undefined
|
||||
b ?= nonce
|
||||
eq nonce, b
|
||||
c = null
|
||||
c ?= nonce
|
||||
eq nonce, c
|
||||
d ?= nonce
|
||||
eq nonce, d
|
||||
|
||||
21
test/booleans.coffee
Normal file
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,18 +0,0 @@
|
||||
# Break
|
||||
# -----
|
||||
|
||||
test "break at the top level", ->
|
||||
for i in [1,2,3]
|
||||
result = i
|
||||
if i == 2
|
||||
break
|
||||
eq 2, result
|
||||
|
||||
test "break *not* at the top level", ->
|
||||
someFunc = () ->
|
||||
i = 0
|
||||
while ++i < 3
|
||||
result = i
|
||||
break if i > 1
|
||||
result
|
||||
eq 2, someFunc()
|
||||
449
test/classes.coffee
Normal file
449
test/classes.coffee
Normal file
@@ -0,0 +1,449 @@
|
||||
# Classes
|
||||
# -------
|
||||
|
||||
# * Class Definition
|
||||
# * Class Instantiation
|
||||
# * Inheritance and Super
|
||||
|
||||
test "classes with a four-level inheritance chain", ->
|
||||
|
||||
class Base
|
||||
func: (string) ->
|
||||
"zero/#{string}"
|
||||
|
||||
@static: (string) ->
|
||||
"static/#{string}"
|
||||
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild = class extends FirstChild
|
||||
func: (string) ->
|
||||
super('two/') + string
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/').length + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is '9two/three/four'
|
||||
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
|
||||
|
||||
test "constructors with inheritance and super", ->
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
test "Overriding the static property new doesn't clobber Function::new", ->
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
test "basic classes, again, but in the manual prototype style", ->
|
||||
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-#{string}"
|
||||
|
||||
FirstChild = ->
|
||||
SecondChild = ->
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
|
||||
ThirdChild extends SecondChild extends FirstChild extends Base
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
|
||||
test "super with plain ol' functions as the original constructors", ->
|
||||
|
||||
TopClass = (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
this
|
||||
|
||||
SuperClass = (arg) ->
|
||||
super 'super-' + arg
|
||||
this
|
||||
|
||||
SubClass = ->
|
||||
super 'sub'
|
||||
this
|
||||
|
||||
SuperClass extends TopClass
|
||||
SubClass extends SuperClass
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
test "'@' referring to the current instance, and not being coerced into a call", ->
|
||||
|
||||
class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
|
||||
|
||||
test "super() calls in constructors of classes that are defined as object properties", ->
|
||||
|
||||
class Hive
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
|
||||
|
||||
test "classes with JS-keyword properties", ->
|
||||
|
||||
class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
|
||||
|
||||
test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
|
||||
|
||||
class Dog
|
||||
constructor: (name) ->
|
||||
@name = name
|
||||
|
||||
bark: =>
|
||||
"#{@name} woofs!"
|
||||
|
||||
@static = =>
|
||||
new this('Dog')
|
||||
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
|
||||
obj = func: Dog.static
|
||||
|
||||
ok obj.func().name is 'Dog'
|
||||
|
||||
|
||||
test "a bound function in a bound function", ->
|
||||
|
||||
class Mini
|
||||
num: 10
|
||||
generate: =>
|
||||
for i in [1..3]
|
||||
=>
|
||||
@num
|
||||
|
||||
m = new Mini
|
||||
eq (func() for func in m.generate()).join(' '), '10 10 10'
|
||||
|
||||
|
||||
test "contructor called with varargs", ->
|
||||
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
|
||||
out: ->
|
||||
"#{@one}-#{@two}-#{@three}"
|
||||
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
|
||||
|
||||
test "calling super and passing along all arguments", ->
|
||||
|
||||
class Parent
|
||||
method: (args...) -> @args = args
|
||||
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
|
||||
|
||||
test "classes wrapped in decorators", ->
|
||||
|
||||
func = (klass) ->
|
||||
klass::prop = 'value'
|
||||
klass
|
||||
|
||||
func class Test
|
||||
prop2: 'value2'
|
||||
|
||||
ok (new Test).prop is 'value'
|
||||
ok (new Test).prop2 is 'value2'
|
||||
|
||||
|
||||
test "anonymous classes", ->
|
||||
|
||||
obj =
|
||||
klass: class
|
||||
method: -> 'value'
|
||||
|
||||
instance = new obj.klass
|
||||
ok instance.method() is 'value'
|
||||
|
||||
|
||||
test "Implicit objects as static properties", ->
|
||||
|
||||
class Static
|
||||
@static =
|
||||
one: 1
|
||||
two: 2
|
||||
|
||||
ok Static.static.one is 1
|
||||
ok Static.static.two is 2
|
||||
|
||||
|
||||
test "nothing classes", ->
|
||||
|
||||
c = class
|
||||
ok c instanceof Function
|
||||
|
||||
|
||||
test "classes with value'd constructors", ->
|
||||
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
counter++
|
||||
inner = counter
|
||||
->
|
||||
@value = inner
|
||||
|
||||
class One
|
||||
constructor: classMaker()
|
||||
|
||||
class Two
|
||||
constructor: classMaker()
|
||||
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
|
||||
|
||||
test "exectuable class bodies", ->
|
||||
|
||||
class A
|
||||
if true
|
||||
b: 'b'
|
||||
else
|
||||
c: 'c'
|
||||
|
||||
a = new A
|
||||
|
||||
eq a.b, 'b'
|
||||
eq a.c, undefined
|
||||
|
||||
|
||||
test "mild metaprogramming", ->
|
||||
|
||||
class Base
|
||||
@attr: (name) ->
|
||||
@::[name] = (val) ->
|
||||
if arguments.length > 0
|
||||
@["_#{name}"] = val
|
||||
else
|
||||
@["_#{name}"]
|
||||
|
||||
class Robot extends Base
|
||||
@attr 'power'
|
||||
@attr 'speed'
|
||||
|
||||
robby = new Robot
|
||||
|
||||
ok robby.power() is undefined
|
||||
|
||||
robby.power 11
|
||||
robby.speed Infinity
|
||||
|
||||
eq robby.power(), 11
|
||||
eq robby.speed(), Infinity
|
||||
|
||||
|
||||
test "namespaced classes do not reserve their function name in outside scope", ->
|
||||
|
||||
one = {}
|
||||
two = {}
|
||||
|
||||
class one.Klass
|
||||
@label = "one"
|
||||
|
||||
class two.Klass
|
||||
@label = "two"
|
||||
|
||||
eq typeof Klass, 'undefined'
|
||||
eq one.Klass.label, 'one'
|
||||
eq two.Klass.label, 'two'
|
||||
|
||||
|
||||
test "nested classes", ->
|
||||
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'outer'
|
||||
|
||||
class @Inner
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
|
||||
|
||||
test "variables in constructor bodies are correctly scoped", ->
|
||||
|
||||
class A
|
||||
x = 1
|
||||
constructor: ->
|
||||
x = 10
|
||||
y = 20
|
||||
y = 2
|
||||
captured: ->
|
||||
{x, y}
|
||||
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
|
||||
|
||||
test "Issue #924: Static methods in nested classes", ->
|
||||
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
|
||||
eq A.B.c(), 5
|
||||
|
||||
|
||||
test "`class extends this`", ->
|
||||
|
||||
class A
|
||||
func: -> 'A'
|
||||
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
|
||||
makeClass.call A
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
|
||||
|
||||
test "ensure that constructors invoked with splats return a new object", ->
|
||||
|
||||
args = [1, 2, 3]
|
||||
Type = (@args) ->
|
||||
type = new Type args
|
||||
|
||||
ok type and type instanceof Type
|
||||
ok type.args and type.args instanceof Array
|
||||
ok v is args[i] for v, i in type.args
|
||||
|
||||
Type1 = (@a, @b, @c) ->
|
||||
type1 = new Type1 args...
|
||||
|
||||
ok type1 instanceof Type1
|
||||
eq type1.constructor, Type1
|
||||
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
|
||||
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
|
||||
test "`new` shouldn't add extra parens", ->
|
||||
|
||||
ok new Date().constructor is Date
|
||||
|
||||
|
||||
test "`new` works against bare function", ->
|
||||
|
||||
eq Date, new ->
|
||||
eq this, new => this
|
||||
Date
|
||||
|
||||
|
||||
test "a subclass should be able to set its constructor to an external function", ->
|
||||
|
||||
ctor = ->
|
||||
@val = 1
|
||||
class A
|
||||
class B extends A
|
||||
constructor: ctor
|
||||
|
||||
eq (new B).val, 1
|
||||
@@ -1,6 +1,9 @@
|
||||
# Comments
|
||||
# --------
|
||||
|
||||
# * Single-Line Comments
|
||||
# * Block Comments
|
||||
|
||||
# Note: awkward spacing seen in some tests is likely intentional.
|
||||
|
||||
test "comments in objects", ->
|
||||
@@ -107,7 +110,7 @@ test "spaced comments with conditional statements", ->
|
||||
eq nonce, result
|
||||
|
||||
|
||||
#### Block Comments
|
||||
# Block Comments
|
||||
|
||||
###
|
||||
This is a here-comment.
|
||||
|
||||
61
test/compilation.coffee
Normal file
61
test/compilation.coffee
Normal file
@@ -0,0 +1,61 @@
|
||||
# Compilation
|
||||
# -----------
|
||||
|
||||
# helper to assert that a string should fail compilation
|
||||
cantCompile = (code) ->
|
||||
throws -> CoffeeScript.compile code
|
||||
|
||||
|
||||
test "ensure that carriage returns don't break compilation on Windows", ->
|
||||
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
|
||||
|
||||
test "--bare", ->
|
||||
eq -1, CoffeeScript.compile('x = y', bare: on).indexOf 'function'
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
|
||||
|
||||
test "multiple generated references", ->
|
||||
a = {b: []}
|
||||
a.b[true] = -> this == a.b
|
||||
c = 0
|
||||
d = []
|
||||
ok a.b[0<++c<2] d...
|
||||
|
||||
test "splat on a line by itself is invalid", ->
|
||||
cantCompile "x 'a'\n...\n"
|
||||
|
||||
test "Issue 750", ->
|
||||
|
||||
cantCompile 'f(->'
|
||||
|
||||
cantCompile 'a = (break)'
|
||||
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
|
||||
test "Issue #986: Unicode identifiers", ->
|
||||
λ = 5
|
||||
eq λ, 5
|
||||
|
||||
test "don't accidentally stringify keywords", ->
|
||||
ok (-> this == 'this')() is false
|
||||
|
||||
test "#1026", ->
|
||||
cantCompile '''
|
||||
if a
|
||||
b
|
||||
else
|
||||
c
|
||||
else
|
||||
d
|
||||
'''
|
||||
|
||||
test "#1050", ->
|
||||
cantCompile "### */ ###"
|
||||
|
||||
test "#1106: __proto__ compilation", ->
|
||||
object = eq
|
||||
@["__proto__"] = true
|
||||
ok __proto__
|
||||
409
test/comprehensions.coffee
Normal file
409
test/comprehensions.coffee
Normal file
@@ -0,0 +1,409 @@
|
||||
# Comprehensions
|
||||
# --------------
|
||||
|
||||
# * Array Comprehensions
|
||||
# * Range Comprehensions
|
||||
# * Object Comprehensions
|
||||
# * Implicit Destructuring Assignment
|
||||
# * Comprehensions with Nonstandard Step
|
||||
|
||||
# TODO: refactor comprehension tests
|
||||
|
||||
test "Basic array comprehensions.", ->
|
||||
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
|
||||
|
||||
test "Basic object comprehensions.", ->
|
||||
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = (prop + '!' for prop of obj)
|
||||
odds = (prop + '!' for prop, value of obj when value & 1)
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
|
||||
|
||||
test "Basic range comprehensions.", ->
|
||||
|
||||
nums = (i * 3 for i in [1..3])
|
||||
|
||||
negs = (x for x in [-20..-5*2])
|
||||
negs = negs[0..2]
|
||||
|
||||
result = nums.concat(negs).join(', ')
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
|
||||
|
||||
test "With range comprehensions, you can loop in steps.", ->
|
||||
|
||||
results = (x for x in [0...15] by 5)
|
||||
ok results.join(' ') is '0 5 10'
|
||||
|
||||
results = (x for x in [0..100] by 10)
|
||||
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
|
||||
|
||||
|
||||
test "And can loop downwards, with a negative step.", ->
|
||||
|
||||
results = (x for x in [5..1])
|
||||
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
|
||||
results = (x for x in [10..1])
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
|
||||
results = (x for x in [10...0] by -2)
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
|
||||
|
||||
test "Range comprehension gymnastics.", ->
|
||||
|
||||
eq "#{i for i in [5..1]}", '5,4,3,2,1'
|
||||
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
|
||||
|
||||
a = 6
|
||||
b = 0
|
||||
c = -2
|
||||
|
||||
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
|
||||
eq "#{i for i in [a..b] by c}", '6,4,2,0'
|
||||
|
||||
|
||||
test "Multiline array comprehension with filter.", ->
|
||||
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
eq evens + '', '4,6,8'
|
||||
|
||||
|
||||
test "The in operator still works, standalone.", ->
|
||||
|
||||
ok 2 of evens
|
||||
|
||||
|
||||
test "all isn't reserved.", ->
|
||||
|
||||
all = 1
|
||||
|
||||
|
||||
test "Ensure that the closure wrapper preserves local variables.", ->
|
||||
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
|
||||
|
||||
test "Index values at the end of a loop.", ->
|
||||
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 4
|
||||
|
||||
|
||||
test "Ensure that local variables are closed over for range comprehensions.", ->
|
||||
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
-> -i
|
||||
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
|
||||
|
||||
test "Even when referenced in the filter.", ->
|
||||
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
test "Even a convoluted one.", ->
|
||||
|
||||
funcs = []
|
||||
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
||||
test "Naked ranges are expanded into arrays.", ->
|
||||
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
test "Nested shared scopes.", ->
|
||||
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
test "Scoped loop pattern matching.", ->
|
||||
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
|
||||
|
||||
test "Nested comprehensions.", ->
|
||||
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
|
||||
singleLiner =
|
||||
(([x, y] for y in [3..5]) for x in [3..5])
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
ok 5 is multiLiner[2][2][1]
|
||||
ok 5 is singleLiner[2][2][1]
|
||||
|
||||
|
||||
test "Comprehensions within parentheses.", ->
|
||||
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
|
||||
ok result.join(' ') is '6 4 2'
|
||||
|
||||
|
||||
test "Closure-wrapped comprehensions that refer to the 'arguments' object.", ->
|
||||
|
||||
expr = ->
|
||||
result = (item * item for item in arguments)
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
|
||||
|
||||
test "Fast object comprehensions over all properties, including prototypal ones.", ->
|
||||
|
||||
class Cat
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
|
||||
whiskers = new Cat
|
||||
own = (value for own key, value of whiskers)
|
||||
all = (value for key, value of whiskers)
|
||||
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
|
||||
|
||||
test "Optimized range comprehensions.", ->
|
||||
|
||||
exxes = ('x' for [0...10])
|
||||
ok exxes.join(' ') is 'x x x x x x x x x x'
|
||||
|
||||
|
||||
test "Comprehensions safely redeclare parameters if they're not present in closest scope.", ->
|
||||
|
||||
rule = (x) -> x
|
||||
|
||||
learn = ->
|
||||
rule for rule in [1, 2, 3]
|
||||
|
||||
ok learn().join(' ') is '1 2 3'
|
||||
|
||||
ok rule(101) is 101
|
||||
|
||||
f = -> [-> ok no, 'should cache source']
|
||||
ok yes for k of [f] = f()
|
||||
|
||||
|
||||
test "Lenient on pure statements not trying to reach out of the closure", ->
|
||||
|
||||
val = for i in [1]
|
||||
for j in [] then break
|
||||
i
|
||||
ok val[0] is i
|
||||
|
||||
|
||||
test "Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
to have pure expressions in them.", ->
|
||||
|
||||
func = -> for i in [1]
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
|
||||
ok func()[0][0] is 1
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
|
||||
|
||||
test "Issue #897: Ensure that plucked function variables aren't leaked.", ->
|
||||
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
||||
|
||||
test "Issue #905. Soaks as the for loop subject.", ->
|
||||
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
|
||||
eq e, 3
|
||||
|
||||
|
||||
test "Issue #948. Capturing loop variables.", ->
|
||||
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
|
||||
|
||||
test "Cancel the comprehension if there's a jump inside the loop.", ->
|
||||
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
|
||||
eq result, 10
|
||||
|
||||
|
||||
test "Comprehensions over break.", ->
|
||||
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
|
||||
test "Comprehensions over continue.", ->
|
||||
|
||||
arrayEq (continue for [1..10]), []
|
||||
|
||||
|
||||
test "Comprehensions over function literals.", ->
|
||||
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
|
||||
eq a, 1
|
||||
|
||||
|
||||
test "Comprehensions that mention arguments.", ->
|
||||
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
eq args[0], 10
|
||||
|
||||
|
||||
test "expression conversion under explicit returns", ->
|
||||
nonce = {}
|
||||
fn = ->
|
||||
return (nonce for x in [1,2,3])
|
||||
arrayEq [nonce,nonce,nonce], fn()
|
||||
fn = ->
|
||||
return [nonce for x in [1,2,3]][0]
|
||||
arrayEq [nonce,nonce,nonce], fn()
|
||||
fn = ->
|
||||
return [(nonce for x in [1..3])][0]
|
||||
arrayEq [nonce,nonce,nonce], fn()
|
||||
|
||||
|
||||
test "implicit destructuring assignment in object of objects", ->
|
||||
a={}; b={}; c={}
|
||||
obj = {
|
||||
a: { d: a },
|
||||
b: { d: b }
|
||||
c: { d: c }
|
||||
}
|
||||
result = ([y,z] for y, { d: z } of obj)
|
||||
arrayEq [['a',a],['b',b],['c',c]], result
|
||||
|
||||
|
||||
test "implicit destructuring assignment in array of objects", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}
|
||||
arr = [
|
||||
{ a: a, b: { c: b } },
|
||||
{ a: c, b: { c: d } },
|
||||
{ a: e, b: { c: f } }
|
||||
]
|
||||
result = ([y,z] for { a: y, b: { c: z } } in arr)
|
||||
arrayEq [[a,b],[c,d],[e,f]], result
|
||||
|
||||
|
||||
test "implicit destructuring assignment in array of arrays", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}
|
||||
arr = [[a, [b]], [c, [d]], [e, [f]]]
|
||||
result = ([y,z] for [y, [z]] in arr)
|
||||
arrayEq [[a,b],[c,d],[e,f]], result
|
||||
|
||||
test "issue #1124: don't assign a variable in two scopes", ->
|
||||
lista = [1, 2, 3, 4, 5]
|
||||
listb = (_i + 1 for _i in lista)
|
||||
arrayEq [2, 3, 4, 5, 6], listb
|
||||
@@ -1,181 +0,0 @@
|
||||
# Conditionals
|
||||
# ------------
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
#### Basic Conditionals
|
||||
|
||||
test "basic conditionals", ->
|
||||
if false
|
||||
ok false
|
||||
else if false
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
if true
|
||||
ok true
|
||||
else if true
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
unless true
|
||||
ok false
|
||||
else unless true
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
unless false
|
||||
ok true
|
||||
else unless false
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
test "single-line conditional", ->
|
||||
if false then ok false else ok true
|
||||
unless false then ok true else ok false
|
||||
|
||||
test "nested conditionals", ->
|
||||
nonce = {}
|
||||
eq nonce, (if true
|
||||
unless false
|
||||
if false then false else
|
||||
if true
|
||||
nonce)
|
||||
|
||||
test "nested single-line conditionals", ->
|
||||
nonce = {}
|
||||
|
||||
a = if false then undefined else b = if 0 then undefined else nonce
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
c = if false then undefined else (if 0 then undefined else nonce)
|
||||
eq nonce, c
|
||||
|
||||
d = if true then id(if false then undefined else nonce)
|
||||
eq nonce, d
|
||||
|
||||
test "empty conditional bodies", ->
|
||||
eq undefined, (if false
|
||||
else if false
|
||||
else)
|
||||
|
||||
test "conditional bodies containing only comments", ->
|
||||
eq undefined, (if true
|
||||
###
|
||||
block comment
|
||||
###
|
||||
else
|
||||
# comment
|
||||
)
|
||||
|
||||
eq undefined, (if false
|
||||
# comment
|
||||
else if true
|
||||
###
|
||||
block comment
|
||||
###
|
||||
else)
|
||||
|
||||
test "return value of if-else is from the proper body", ->
|
||||
nonce = {}
|
||||
eq nonce, if false then undefined else nonce
|
||||
|
||||
test "return value of unless-else is from the proper body", ->
|
||||
nonce = {}
|
||||
eq nonce, unless true then undefined else nonce
|
||||
|
||||
|
||||
#### Interactions With Functions
|
||||
|
||||
test "single-line function definition with single-line conditional", ->
|
||||
fn = -> if 1 < 0.5 then 1 else -1
|
||||
ok fn() is -1
|
||||
|
||||
test "function resturns conditional value with no `else`", ->
|
||||
fn = ->
|
||||
return if false then true
|
||||
eq undefined, fn()
|
||||
|
||||
test "function returns a conditional value", ->
|
||||
a = {}
|
||||
fnA = ->
|
||||
return if false then undefined else a
|
||||
eq a, fnA()
|
||||
|
||||
b = {}
|
||||
fnB = ->
|
||||
return unless false then b else undefined
|
||||
eq b, fnB()
|
||||
|
||||
test "passing a conditional value to a function", ->
|
||||
nonce = {}
|
||||
eq nonce, id if false then undefined else nonce
|
||||
|
||||
test "unmatched `then` should catch implicit calls", ->
|
||||
a = 0
|
||||
trueFn = -> true
|
||||
if trueFn undefined then a += 1
|
||||
eq 1, a
|
||||
|
||||
|
||||
#### if-to-ternary
|
||||
|
||||
test "if-to-ternary with instanceof requires parentheses", ->
|
||||
nonce = {}
|
||||
eq nonce, (if {} instanceof Object
|
||||
nonce
|
||||
else
|
||||
undefined)
|
||||
|
||||
test "if-to-ternary as part of a larger operation requires parentheses", ->
|
||||
ok 2, 1 + if false then 0 else 1
|
||||
|
||||
|
||||
#### Odd Formatting
|
||||
|
||||
test "if-else indented within an assignment", ->
|
||||
nonce = {}
|
||||
result =
|
||||
if false
|
||||
undefined
|
||||
else
|
||||
nonce
|
||||
eq nonce, result
|
||||
|
||||
test "suppressed indentation via assignment", ->
|
||||
nonce = {}
|
||||
result =
|
||||
if false then undefined
|
||||
else if no then undefined
|
||||
else if 0 then undefined
|
||||
else if 1 < 0 then undefined
|
||||
else id(
|
||||
if false then undefined
|
||||
else nonce
|
||||
)
|
||||
eq nonce, result
|
||||
|
||||
test "tight formatting with leading `then`", ->
|
||||
nonce = {}
|
||||
eq nonce,
|
||||
if true
|
||||
then nonce
|
||||
else undefined
|
||||
|
||||
test "#738", ->
|
||||
nonce = {}
|
||||
fn = if true then -> nonce
|
||||
eq nonce, fn()
|
||||
|
||||
test "#748: trailing reserved identifiers", ->
|
||||
nonce = {}
|
||||
obj = delete: true
|
||||
result = if obj.delete
|
||||
nonce
|
||||
eq nonce, result
|
||||
420
test/control_flow.coffee
Normal file
420
test/control_flow.coffee
Normal file
@@ -0,0 +1,420 @@
|
||||
# Control Flow
|
||||
# ------------
|
||||
|
||||
# * Conditionals
|
||||
# * Loops
|
||||
# * For
|
||||
# * While
|
||||
# * Until
|
||||
# * Loop
|
||||
# * Switch
|
||||
|
||||
# TODO: make sure postfix forms and expression coercion are properly tested
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
# Conditionals
|
||||
|
||||
test "basic conditionals", ->
|
||||
if false
|
||||
ok false
|
||||
else if false
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
if true
|
||||
ok true
|
||||
else if true
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
unless true
|
||||
ok false
|
||||
else unless true
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
unless false
|
||||
ok true
|
||||
else unless false
|
||||
ok false
|
||||
else
|
||||
ok true
|
||||
|
||||
test "single-line conditional", ->
|
||||
if false then ok false else ok true
|
||||
unless false then ok true else ok false
|
||||
|
||||
test "nested conditionals", ->
|
||||
nonce = {}
|
||||
eq nonce, (if true
|
||||
unless false
|
||||
if false then false else
|
||||
if true
|
||||
nonce)
|
||||
|
||||
test "nested single-line conditionals", ->
|
||||
nonce = {}
|
||||
|
||||
a = if false then undefined else b = if 0 then undefined else nonce
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
c = if false then undefined else (if 0 then undefined else nonce)
|
||||
eq nonce, c
|
||||
|
||||
d = if true then id(if false then undefined else nonce)
|
||||
eq nonce, d
|
||||
|
||||
test "empty conditional bodies", ->
|
||||
eq undefined, (if false
|
||||
else if false
|
||||
else)
|
||||
|
||||
test "conditional bodies containing only comments", ->
|
||||
eq undefined, (if true
|
||||
###
|
||||
block comment
|
||||
###
|
||||
else
|
||||
# comment
|
||||
)
|
||||
|
||||
eq undefined, (if false
|
||||
# comment
|
||||
else if true
|
||||
###
|
||||
block comment
|
||||
###
|
||||
else)
|
||||
|
||||
test "return value of if-else is from the proper body", ->
|
||||
nonce = {}
|
||||
eq nonce, if false then undefined else nonce
|
||||
|
||||
test "return value of unless-else is from the proper body", ->
|
||||
nonce = {}
|
||||
eq nonce, unless true then undefined else nonce
|
||||
|
||||
test "assign inside the condition of a conditional statement", ->
|
||||
nonce = {}
|
||||
if a = nonce then 1
|
||||
eq nonce, a
|
||||
1 if b = nonce
|
||||
eq nonce, b
|
||||
|
||||
|
||||
# Interactions With Functions
|
||||
|
||||
test "single-line function definition with single-line conditional", ->
|
||||
fn = -> if 1 < 0.5 then 1 else -1
|
||||
ok fn() is -1
|
||||
|
||||
test "function resturns conditional value with no `else`", ->
|
||||
fn = ->
|
||||
return if false then true
|
||||
eq undefined, fn()
|
||||
|
||||
test "function returns a conditional value", ->
|
||||
a = {}
|
||||
fnA = ->
|
||||
return if false then undefined else a
|
||||
eq a, fnA()
|
||||
|
||||
b = {}
|
||||
fnB = ->
|
||||
return unless false then b else undefined
|
||||
eq b, fnB()
|
||||
|
||||
test "passing a conditional value to a function", ->
|
||||
nonce = {}
|
||||
eq nonce, id if false then undefined else nonce
|
||||
|
||||
test "unmatched `then` should catch implicit calls", ->
|
||||
a = 0
|
||||
trueFn = -> true
|
||||
if trueFn undefined then a++
|
||||
eq 1, a
|
||||
|
||||
|
||||
# if-to-ternary
|
||||
|
||||
test "if-to-ternary with instanceof requires parentheses", ->
|
||||
nonce = {}
|
||||
eq nonce, (if {} instanceof Object
|
||||
nonce
|
||||
else
|
||||
undefined)
|
||||
|
||||
test "if-to-ternary as part of a larger operation requires parentheses", ->
|
||||
ok 2, 1 + if false then 0 else 1
|
||||
|
||||
|
||||
# Odd Formatting
|
||||
|
||||
test "if-else indented within an assignment", ->
|
||||
nonce = {}
|
||||
result =
|
||||
if false
|
||||
undefined
|
||||
else
|
||||
nonce
|
||||
eq nonce, result
|
||||
|
||||
test "suppressed indentation via assignment", ->
|
||||
nonce = {}
|
||||
result =
|
||||
if false then undefined
|
||||
else if no then undefined
|
||||
else if 0 then undefined
|
||||
else if 1 < 0 then undefined
|
||||
else id(
|
||||
if false then undefined
|
||||
else nonce
|
||||
)
|
||||
eq nonce, result
|
||||
|
||||
test "tight formatting with leading `then`", ->
|
||||
nonce = {}
|
||||
eq nonce,
|
||||
if true
|
||||
then nonce
|
||||
else undefined
|
||||
|
||||
test "#738", ->
|
||||
nonce = {}
|
||||
fn = if true then -> nonce
|
||||
eq nonce, fn()
|
||||
|
||||
test "#748: trailing reserved identifiers", ->
|
||||
nonce = {}
|
||||
obj = delete: true
|
||||
result = if obj.delete
|
||||
nonce
|
||||
eq nonce, result
|
||||
|
||||
|
||||
test "basic `while` loops", ->
|
||||
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
|
||||
|
||||
test "Issue 759: `if` within `while` condition", ->
|
||||
|
||||
2 while if 1 then 0
|
||||
|
||||
|
||||
test "assignment inside the condition of a `while` loop", ->
|
||||
|
||||
nonce = {}
|
||||
count = 1
|
||||
a = nonce while count--
|
||||
eq nonce, a
|
||||
count = 1
|
||||
while count--
|
||||
b = nonce
|
||||
eq nonce, b
|
||||
|
||||
|
||||
test "While over break.", ->
|
||||
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
break
|
||||
arrayEq result, []
|
||||
|
||||
|
||||
test "While over continue.", ->
|
||||
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
continue
|
||||
arrayEq result, []
|
||||
|
||||
|
||||
test "Basic `until`", ->
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i++
|
||||
ok i is 6
|
||||
|
||||
|
||||
test "Basic `loop`", ->
|
||||
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
|
||||
|
||||
test "break at the top level", ->
|
||||
for i in [1,2,3]
|
||||
result = i
|
||||
if i == 2
|
||||
break
|
||||
eq 2, result
|
||||
|
||||
test "break *not* at the top level", ->
|
||||
someFunc = ->
|
||||
i = 0
|
||||
while ++i < 3
|
||||
result = i
|
||||
break if i > 1
|
||||
result
|
||||
eq 2, someFunc()
|
||||
|
||||
|
||||
test "basic `switch`", ->
|
||||
|
||||
num = 10
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
false
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
true
|
||||
when 1, 3, 5
|
||||
false
|
||||
|
||||
ok func(2)
|
||||
ok func(6)
|
||||
ok !func(3)
|
||||
eq func(8), undefined
|
||||
|
||||
|
||||
test "Ensure that trailing switch elses don't get rewritten.", ->
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
test "Should be able to handle switches sans-condition.", ->
|
||||
|
||||
result = switch
|
||||
when null then 0
|
||||
when !1 then 1
|
||||
when '' not of {''} then 2
|
||||
when [] not instanceof Array then 3
|
||||
when true is false then 4
|
||||
when 'x' < 'y' > 'z' then 5
|
||||
when 'a' in ['b', 'c'] then 6
|
||||
when 'd' in (['e', 'f']) then 7
|
||||
else ok
|
||||
|
||||
eq result, ok
|
||||
|
||||
|
||||
test "Should be able to use `@properties` within the switch clause.", ->
|
||||
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
when 101 then '101!'
|
||||
else 'other'
|
||||
}
|
||||
|
||||
ok obj.func() is '101!'
|
||||
|
||||
|
||||
test "Should be able to use `@properties` within the switch cases.", ->
|
||||
|
||||
obj = {
|
||||
num: 101
|
||||
func: (yesOrNo) ->
|
||||
result = switch yesOrNo
|
||||
when yes then @num
|
||||
else 'other'
|
||||
result
|
||||
}
|
||||
|
||||
ok obj.func(yes) is 101
|
||||
|
||||
|
||||
test "Switch with break as the return value of a loop.", ->
|
||||
|
||||
i = 10
|
||||
results = while i > 0
|
||||
i--
|
||||
switch i % 2
|
||||
when 1 then i
|
||||
when 0 then break
|
||||
|
||||
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
|
||||
|
||||
|
||||
test "Issue #997. Switch doesn't fallthrough.", ->
|
||||
|
||||
val = 1
|
||||
switch true
|
||||
when true
|
||||
if false
|
||||
return 5
|
||||
else
|
||||
val = 2
|
||||
|
||||
eq val, 1
|
||||
@@ -1,17 +1,17 @@
|
||||
# Exceptions
|
||||
# ----------
|
||||
# Exception Handling
|
||||
# ------------------
|
||||
|
||||
# shared nonce
|
||||
nonce = {}
|
||||
|
||||
|
||||
#### Throw
|
||||
# Throw
|
||||
|
||||
test "basic exception throwing", ->
|
||||
throws (-> throw 'error'), 'error'
|
||||
|
||||
|
||||
#### Empty Try/Catch/Finally
|
||||
# Empty Try/Catch/Finally
|
||||
|
||||
test "try can exist alone", ->
|
||||
try
|
||||
@@ -43,7 +43,7 @@ test "single-line try/catch/finally with empty try, empty catch, empty finally",
|
||||
try catch err then finally
|
||||
|
||||
|
||||
#### Try/Catch/Finally as an Expression
|
||||
# Try/Catch/Finally as an Expression
|
||||
|
||||
test "return the result of try when no exception is thrown", ->
|
||||
result = try
|
||||
@@ -81,7 +81,7 @@ test "optional catch", ->
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
#### Try/Catch/Finally Interaction With Other Constructs
|
||||
# Try/Catch/Finally Interaction With Other Constructs
|
||||
|
||||
test "try/catch with empty catch as last statement in a function body", ->
|
||||
fn = ->
|
||||
|
||||
118
test/formatting.coffee
Normal file
118
test/formatting.coffee
Normal file
@@ -0,0 +1,118 @@
|
||||
# Formatting
|
||||
# ----------
|
||||
|
||||
# TODO: maybe this file should be split up into their respective sections:
|
||||
# operators -> operators
|
||||
# array literals -> array literals
|
||||
# string literals -> string literals
|
||||
# function invocations -> function invocations
|
||||
|
||||
# * Line Continuation
|
||||
# * Property Accesss
|
||||
# * Operators
|
||||
# * Array Literals
|
||||
# * Function Invocations
|
||||
# * String Literals
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile "a = then b"
|
||||
|
||||
test "multiple semicolon-separated statements in parentheticals", ->
|
||||
nonce = {}
|
||||
eq nonce, (1; 2; nonce)
|
||||
eq nonce, (-> return (1; 2; nonce))()
|
||||
|
||||
# Line Continuation
|
||||
|
||||
# Property Access
|
||||
|
||||
test "chained accesses split on period/newline, backwards and forwards", ->
|
||||
str = 'abc'
|
||||
result = str.
|
||||
split('').
|
||||
reverse().
|
||||
reverse().
|
||||
reverse()
|
||||
arrayEq ['c','b','a'], result
|
||||
arrayEq ['c','b','a'], str.
|
||||
split('').
|
||||
reverse().
|
||||
reverse().
|
||||
reverse()
|
||||
result = str
|
||||
.split('')
|
||||
.reverse()
|
||||
.reverse()
|
||||
.reverse()
|
||||
arrayEq ['c','b','a'], result
|
||||
arrayEq ['c','b','a'], str
|
||||
.split('')
|
||||
.reverse()
|
||||
.reverse()
|
||||
.reverse()
|
||||
arrayEq ['c','b','a'], str.
|
||||
split('')
|
||||
.reverse().
|
||||
reverse()
|
||||
.reverse()
|
||||
|
||||
# Operators
|
||||
|
||||
test "newline suppression for operators", ->
|
||||
six =
|
||||
1 +
|
||||
2 +
|
||||
3
|
||||
eq 6, six
|
||||
|
||||
test "`?.` and `::` should continue lines", ->
|
||||
ok not Date
|
||||
::
|
||||
?.foo
|
||||
#eq Object::toString, Date?.
|
||||
#prototype
|
||||
#::
|
||||
#?.foo
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile """
|
||||
oh. yes
|
||||
oh?. true
|
||||
oh:: return
|
||||
"""
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile """
|
||||
a?[b..]
|
||||
a?[...b]
|
||||
a?[b..c]
|
||||
"""
|
||||
|
||||
# Array Literals
|
||||
|
||||
test "indented array literals don't trigger whitespace rewriting", ->
|
||||
getArgs = -> arguments
|
||||
result = getArgs(
|
||||
[[[[[],
|
||||
[]],
|
||||
[[]]]],
|
||||
[]])
|
||||
eq 1, result.length
|
||||
|
||||
# Function Invocations
|
||||
|
||||
doesNotThrow -> CoffeeScript.compile """
|
||||
obj = then fn 1,
|
||||
1: 1
|
||||
a:
|
||||
b: ->
|
||||
fn c,
|
||||
d: e
|
||||
f: 1
|
||||
"""
|
||||
|
||||
# String Literals
|
||||
|
||||
test "indented heredoc", ->
|
||||
result = ((_) -> _)(
|
||||
"""
|
||||
abc
|
||||
""")
|
||||
eq "abc", result
|
||||
445
test/function_invocation.coffee
Normal file
445
test/function_invocation.coffee
Normal file
@@ -0,0 +1,445 @@
|
||||
# Function Invocation
|
||||
# -------------------
|
||||
|
||||
# * Function Invocation
|
||||
# * Splats in Function Invocations
|
||||
# * Implicit Returns
|
||||
# * Explicit Returns
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else [arguments...]
|
||||
|
||||
|
||||
test "basic argument passing", ->
|
||||
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
eq 1, (id 1)
|
||||
eq 2, (id 1, 2)[1]
|
||||
eq a, (id a)
|
||||
eq c, (id a, b, c)[2]
|
||||
|
||||
|
||||
test "passing arguments on separate lines", ->
|
||||
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
ok(id(
|
||||
a
|
||||
b
|
||||
c
|
||||
)[1] is b)
|
||||
eq(0, id(
|
||||
0
|
||||
10
|
||||
)[0])
|
||||
eq(a,id(
|
||||
a
|
||||
))
|
||||
eq b,
|
||||
(id b)
|
||||
|
||||
|
||||
test "optional parens can be used in a nested fashion", ->
|
||||
|
||||
call = (func) -> func()
|
||||
add = (a,b) -> a + b
|
||||
result = call ->
|
||||
inner = call ->
|
||||
add 5, 5
|
||||
ok result is 10
|
||||
|
||||
|
||||
test "hanging commas and semicolons in argument list", ->
|
||||
|
||||
fn = () -> arguments.length
|
||||
eq 2, fn(0,1,)
|
||||
eq 3, fn 0, 1,
|
||||
2
|
||||
eq 2, fn(0, 1;)
|
||||
# TODO: this test fails (the string compiles), but should it?
|
||||
#throws -> CoffeeScript.compile "fn(0,1,;)"
|
||||
throws -> CoffeeScript.compile "fn(0,1,;;)"
|
||||
throws -> CoffeeScript.compile "fn(0, 1;,)"
|
||||
throws -> CoffeeScript.compile "fn(,0)"
|
||||
throws -> CoffeeScript.compile "fn(;0)"
|
||||
|
||||
|
||||
test "function invocation", ->
|
||||
|
||||
func = ->
|
||||
return if true
|
||||
eq undefined, func()
|
||||
|
||||
result = ("hello".slice) 3
|
||||
ok result is 'lo'
|
||||
|
||||
|
||||
test "And even with strange things like this:", ->
|
||||
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
ok result is 25
|
||||
|
||||
|
||||
test "More fun with optional parens.", ->
|
||||
|
||||
fn = (arg) -> arg
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
|
||||
test "chained function calls", ->
|
||||
nonce = {}
|
||||
identityWrap = (x) ->
|
||||
-> x
|
||||
eq nonce, identityWrap(identityWrap(nonce))()()
|
||||
eq nonce, (identityWrap identityWrap nonce)()()
|
||||
|
||||
|
||||
test "Multi-blocks with optional parens.", ->
|
||||
|
||||
fn = (arg) -> arg
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
|
||||
test "method calls", ->
|
||||
|
||||
fnId = (fn) -> -> fn.apply this, arguments
|
||||
math = {
|
||||
add: (a, b) -> a + b
|
||||
anonymousAdd: (a, b) -> a + b
|
||||
fastAdd: fnId (a, b) -> a + b
|
||||
}
|
||||
ok math.add(5, 5) is 10
|
||||
ok math.anonymousAdd(10, 10) is 20
|
||||
ok math.fastAdd(20, 20) is 40
|
||||
|
||||
|
||||
test "Ensure that functions can have a trailing comma in their argument list", ->
|
||||
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
ok mult(10, (i for i in [1..6])...) is 7200
|
||||
|
||||
|
||||
test "`@` and `this` should both be able to invoke a method", ->
|
||||
nonce = {}
|
||||
fn = (arg) -> eq nonce, arg
|
||||
fn.withAt = -> @ nonce
|
||||
fn.withThis = -> this nonce
|
||||
fn.withAt()
|
||||
fn.withThis()
|
||||
|
||||
|
||||
test "Trying an implicit object call with a trailing function.", ->
|
||||
|
||||
a = null
|
||||
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
|
||||
meth 'apple', b: 1, a: 13, ->
|
||||
'orange'
|
||||
ok a is '13 apple orange'
|
||||
|
||||
|
||||
test "Ensure that empty functions don't return mistaken values.", ->
|
||||
|
||||
obj =
|
||||
func: (@param, @rest...) ->
|
||||
ok obj.func(101, 102, 103, 104) is undefined
|
||||
ok obj.param is 101
|
||||
ok obj.rest.join(' ') is '102 103 104'
|
||||
|
||||
|
||||
test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->
|
||||
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
ok result is 20
|
||||
|
||||
|
||||
test "Implicit call with a trailing if statement as a param.", ->
|
||||
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
|
||||
test "Test more function passing:", ->
|
||||
|
||||
sum = (one, two) -> one() + two()
|
||||
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
ok result is 6
|
||||
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
ok result is 3
|
||||
|
||||
|
||||
test "Chained blocks, with proper indentation levels:", ->
|
||||
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
arrayEq [3,2,1], counter.results
|
||||
|
||||
|
||||
test "This is a crazy one.", ->
|
||||
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
ok result.one is 1
|
||||
|
||||
|
||||
test "More paren compilation tests:", ->
|
||||
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
|
||||
|
||||
test "Test for inline functions with parentheses and implicit calls.", ->
|
||||
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
ok result is 9
|
||||
|
||||
|
||||
test "Test for calls/parens/multiline-chains.", ->
|
||||
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
ok result is 1
|
||||
|
||||
|
||||
test "Test implicit calls in functions in parens:", ->
|
||||
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
ok result is 10
|
||||
|
||||
|
||||
test "Ensure that chained calls with indented implicit object literals below are alright.", ->
|
||||
|
||||
result = null
|
||||
obj =
|
||||
method: (val) -> this
|
||||
second: (hash) -> result = hash.three
|
||||
obj
|
||||
.method(
|
||||
101
|
||||
).second(
|
||||
one:
|
||||
two: 2
|
||||
three: 3
|
||||
)
|
||||
eq result, 3
|
||||
|
||||
|
||||
test "Test newline-supressed call chains with nested functions.", ->
|
||||
|
||||
obj =
|
||||
call: -> this
|
||||
func = ->
|
||||
obj
|
||||
.call ->
|
||||
one two
|
||||
.call ->
|
||||
three four
|
||||
101
|
||||
eq func(), 101
|
||||
|
||||
|
||||
test "Implicit objects with number arguments.", ->
|
||||
|
||||
func = (x, y) -> y
|
||||
obj =
|
||||
prop: func "a", 1
|
||||
ok obj.prop is 1
|
||||
|
||||
|
||||
test "Non-spaced unary and binary operators should cause a function call.", ->
|
||||
|
||||
func = (val) -> val + 1
|
||||
ok (func +5) is 6
|
||||
ok (func -5) is -4
|
||||
|
||||
|
||||
test "Prefix unary assignment operators are allowed in parenless calls.", ->
|
||||
|
||||
func = (val) -> val + 1
|
||||
val = 5
|
||||
ok (func --val) is 5
|
||||
|
||||
test "#855: execution context for `func arr...` should be `null`", ->
|
||||
contextTest = -> eq @, if window? then window else global
|
||||
array = []
|
||||
contextTest array
|
||||
contextTest.apply null, array
|
||||
contextTest array...
|
||||
|
||||
test "#904: Destructuring function arguments with same-named variables in scope", ->
|
||||
a = b = nonce = {}
|
||||
fn = ([a,b]) -> {a:a,b:b}
|
||||
result = fn([c={},d={}])
|
||||
eq c, result.a
|
||||
eq d, result.b
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
|
||||
test "caching base value", ->
|
||||
|
||||
obj =
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
ok obj[obj.index++].method([]...)
|
||||
|
||||
|
||||
test "passing splats to functions", ->
|
||||
arrayEq [0..4], id id [0..4]...
|
||||
fn = (a, b, c..., d) -> [a, b, c, d]
|
||||
range = [0..3]
|
||||
[first, second, others, last] = fn range..., 4, [5...8]...
|
||||
eq 0, first
|
||||
eq 1, second
|
||||
arrayEq [2..6], others
|
||||
eq 7, last
|
||||
|
||||
test "splat variables are local to the function", ->
|
||||
outer = "x"
|
||||
clobber = (avar, outer...) -> outer
|
||||
clobber "foo", "bar"
|
||||
eq "x", outer
|
||||
|
||||
|
||||
test "Issue 894: Splatting against constructor-chained functions.", ->
|
||||
|
||||
x = null
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
new Foo().bar([101]...)
|
||||
eq x, 101
|
||||
|
||||
|
||||
test "Functions with splats being called with too few arguments.", ->
|
||||
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
|
||||
|
||||
test "splats with super() within classes.", ->
|
||||
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
|
||||
test "#1011: passing a splat to a method of a number", ->
|
||||
eq '1011', 11.toString [2]...
|
||||
eq '1011', (31).toString [3]...
|
||||
eq '1011', 69.0.toString [4]...
|
||||
eq '1011', (131.0).toString [5]...
|
||||
|
||||
|
||||
test "implicit return", ->
|
||||
|
||||
eq ok, new ->
|
||||
ok
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
|
||||
test "implicit returns with multiple branches", ->
|
||||
nonce = {}
|
||||
fn = ->
|
||||
if false
|
||||
for a in b
|
||||
return c if d
|
||||
else
|
||||
nonce
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
test "implicit returns with switches", ->
|
||||
nonce = {}
|
||||
fn = ->
|
||||
switch nonce
|
||||
when nonce then nonce
|
||||
else return undefined
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
test "preserve context when generating closure wrappers for expression conversions", ->
|
||||
nonce = {}
|
||||
obj =
|
||||
property: nonce
|
||||
method: ->
|
||||
this.result = if false
|
||||
10
|
||||
else
|
||||
"a"
|
||||
"b"
|
||||
this.property
|
||||
eq nonce, obj.method()
|
||||
eq nonce, obj.property
|
||||
|
||||
|
||||
test "don't wrap 'pure' statements in a closure", ->
|
||||
nonce = {}
|
||||
items = [0, 1, 2, 3, nonce, 4, 5]
|
||||
fn = (items) ->
|
||||
for item in items
|
||||
return item if item is nonce
|
||||
eq nonce, fn items
|
||||
|
||||
#### Unusual `new` Usage
|
||||
|
||||
test "usage of `new` is careful about where the invocation parens end up", ->
|
||||
eq 'object', typeof new try Array
|
||||
eq 'object', typeof new do -> ->
|
||||
@@ -1,48 +1,78 @@
|
||||
# Arguments
|
||||
# ---------
|
||||
# Function Literals
|
||||
# -----------------
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
# TODO: add indexing and method invocation tests: (->)[0], (->).call()
|
||||
|
||||
test "basic argument passing tests", ->
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
eq 1, (id 1)
|
||||
eq 2, (id 1, 2)[1]
|
||||
eq a, (id a)
|
||||
eq c, (id a, b, c)[2]
|
||||
# * Function Definition
|
||||
# * Bound Function Definition
|
||||
# * Parameter List Features
|
||||
# * Splat Parameters
|
||||
# * Context (@) Parameters
|
||||
# * Parameter Destructuring
|
||||
# * Default Parameters
|
||||
|
||||
test "passing arguments on separate lines", ->
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
ok(id(
|
||||
a
|
||||
b
|
||||
c
|
||||
)[1] is b)
|
||||
eq(0, id(
|
||||
0
|
||||
10
|
||||
)[0])
|
||||
eq(a,id(
|
||||
a
|
||||
))
|
||||
eq b,
|
||||
(id b)
|
||||
# Function Definition
|
||||
|
||||
test "reference `arguments` inside of functions", ->
|
||||
sumOfArgs = ->
|
||||
sum = (a,b) -> a + b
|
||||
sum = 0
|
||||
sum += num for num in arguments
|
||||
sum
|
||||
x = 1
|
||||
y = {}
|
||||
y.x = -> 3
|
||||
ok x is 1
|
||||
ok typeof(y.x) is 'function'
|
||||
ok y.x instanceof Function
|
||||
ok y.x() is 3
|
||||
|
||||
eq 10, sumOfArgs(0, 1, 2, 3, 4)
|
||||
# The empty function should not cause a syntax error.
|
||||
->
|
||||
() ->
|
||||
|
||||
# Multiple nested function declarations mixed with implicit calls should not
|
||||
# cause a syntax error.
|
||||
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
|
||||
|
||||
# with multiple single-line functions on the same line.
|
||||
func = (x) -> (x) -> (x) -> x
|
||||
ok func(1)(2)(3) is 3
|
||||
|
||||
# Make incorrect indentation safe.
|
||||
func = ->
|
||||
obj = {
|
||||
key: 10
|
||||
}
|
||||
obj.key - 5
|
||||
eq func(), 5
|
||||
|
||||
# Ensure that functions with the same name don't clash with helper functions.
|
||||
del = -> 5
|
||||
ok del() is 5
|
||||
|
||||
|
||||
#### Parameter List Features
|
||||
# Bound Function Definition
|
||||
|
||||
obj =
|
||||
bound: ->
|
||||
(=> this)()
|
||||
unbound: ->
|
||||
(-> this)()
|
||||
nested: ->
|
||||
(=>
|
||||
(=>
|
||||
(=> this)()
|
||||
)()
|
||||
)()
|
||||
eq obj, obj.bound()
|
||||
ok obj isnt obj.unbound()
|
||||
eq obj, obj.nested()
|
||||
|
||||
|
||||
test "self-referencing functions", ->
|
||||
changeMe = ->
|
||||
changeMe = 2
|
||||
|
||||
changeMe()
|
||||
eq changeMe, 2
|
||||
|
||||
|
||||
# Parameter List Features
|
||||
|
||||
test "splats", ->
|
||||
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
|
||||
@@ -125,3 +155,11 @@ test "default values with splatted arguments", ->
|
||||
eq 5, withSplats(1,1)
|
||||
eq 1, withSplats(1,1,1)
|
||||
eq 2, withSplats(1,1,1,1)
|
||||
|
||||
test "default values with function calls", ->
|
||||
doesNotThrow -> CoffeeScript.compile "(x = f()) ->"
|
||||
|
||||
test "arguments vs parameters", ->
|
||||
doesNotThrow -> CoffeeScript.compile "f(x) ->"
|
||||
f = (g) -> g()
|
||||
eq 5, f (x) -> 5
|
||||
@@ -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]
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
eq '(((dollars)))', '\(\(\(dollars\)\)\)'
|
||||
eq 'one two three', "one
|
||||
two
|
||||
three"
|
||||
eq "four five", 'four
|
||||
# Interpolation
|
||||
# -------------
|
||||
|
||||
five'
|
||||
# * String Interpolation
|
||||
# * Regular Expression Interpolation
|
||||
|
||||
#647
|
||||
eq "''Hello, World\\''", '''
|
||||
'\'Hello, World\\\''
|
||||
'''
|
||||
eq '""Hello, World\\""', """
|
||||
"\"Hello, World\\\""
|
||||
"""
|
||||
eq 'Hello, World\n', '''
|
||||
Hello, World\
|
||||
# String Interpolation
|
||||
|
||||
'''
|
||||
# TODO: refactor string interpolation tests
|
||||
|
||||
eq 'multiline nested "interpolations" work', """multiline #{
|
||||
"nested #{
|
||||
ok true
|
||||
"\"interpolations\""
|
||||
}"
|
||||
} work"""
|
||||
|
||||
# Issue #923: Tricky interpolation.
|
||||
eq "#{ "{" }", "{"
|
||||
eq "#{ '#{}}' } }", '#{}} }'
|
||||
eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'"
|
||||
|
||||
hello = 'Hello'
|
||||
world = 'World'
|
||||
@@ -28,37 +29,30 @@ ok "#{hello}##{world}" is 'Hello#World'
|
||||
ok "Hello #{ 1 + 2 } World" is 'Hello 3 World'
|
||||
ok "#{hello} #{ 1 + 2 } #{world}" is "Hello 3 World"
|
||||
|
||||
|
||||
[s, t, r, i, n, g] = ['s', 't', 'r', 'i', 'n', 'g']
|
||||
ok "#{s}#{t}#{r}#{i}#{n}#{g}" is 'string'
|
||||
ok "\#{s}\#{t}\#{r}\#{i}\#{n}\#{g}" is '#{s}#{t}#{r}#{i}#{n}#{g}'
|
||||
ok "\#{string}" is '#{string}'
|
||||
|
||||
|
||||
ok "\#{Escaping} first" is '#{Escaping} first'
|
||||
ok "Escaping \#{in} middle" is 'Escaping #{in} middle'
|
||||
ok "Escaping \#{last}" is 'Escaping #{last}'
|
||||
|
||||
|
||||
ok "##" is '##'
|
||||
ok "#{}" is ''
|
||||
ok "#{}A#{} #{} #{}B#{}" is 'A B'
|
||||
ok "\\\#{}" is '\\#{}'
|
||||
|
||||
|
||||
ok "I won ##{20} last night." is 'I won #20 last night.'
|
||||
ok "I won ##{'#20'} last night." is 'I won ##20 last night.'
|
||||
|
||||
|
||||
ok "#{hello + world}" is 'HelloWorld'
|
||||
ok "#{hello + ' ' + world + '!'}" is 'Hello World!'
|
||||
|
||||
|
||||
list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
ok "values: #{list.join(', ')}, length: #{list.length}." is 'values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, length: 10.'
|
||||
ok "values: #{list.join ' '}" is 'values: 0 1 2 3 4 5 6 7 8 9'
|
||||
|
||||
|
||||
obj = {
|
||||
name: 'Joe'
|
||||
hi: -> "Hello #{@name}."
|
||||
@@ -67,7 +61,6 @@ obj = {
|
||||
ok obj.hi() is "Hello Joe."
|
||||
ok obj.cya() is "Goodbye Joe."
|
||||
|
||||
|
||||
ok "With #{"quotes"}" is 'With quotes'
|
||||
ok 'With #{"quotes"}' is 'With #{"quotes"}'
|
||||
|
||||
@@ -78,41 +71,54 @@ ok "Hello #{world ? "#{hello}"}" is 'Hello World'
|
||||
|
||||
ok "Hello #{"#{"#{obj["name"]}" + '!'}"}" is 'Hello Joe!'
|
||||
|
||||
|
||||
a = """
|
||||
Hello #{ "Joe" }
|
||||
"""
|
||||
ok a is "Hello Joe"
|
||||
|
||||
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
ok "#{a}#{b}#{c}" is '123'
|
||||
|
||||
|
||||
result = null
|
||||
stash = (str) -> result = str
|
||||
stash "a #{ ('aa').replace /a/g, 'b' } c"
|
||||
ok result is 'a bb c'
|
||||
|
||||
|
||||
foo = "hello"
|
||||
ok "#{foo.replace("\"", "")}" is 'hello'
|
||||
|
||||
val = 10
|
||||
a = """
|
||||
basic heredoc #{val}
|
||||
on two lines
|
||||
"""
|
||||
b = '''
|
||||
basic heredoc #{val}
|
||||
on two lines
|
||||
'''
|
||||
ok a is "basic heredoc 10\non two lines"
|
||||
ok b is "basic heredoc \#{val}\non two lines"
|
||||
|
||||
eq 'multiline nested "interpolations" work', """multiline #{
|
||||
"nested #{
|
||||
ok true
|
||||
"nested #{(->
|
||||
ok yes
|
||||
"\"interpolations\""
|
||||
}"
|
||||
)()}"
|
||||
} work"""
|
||||
|
||||
|
||||
# Issue #923: Tricky interpolation.
|
||||
eq "#{ "{" }", "{"
|
||||
# Regular Expression Interpolation
|
||||
|
||||
eq "#{ '#{}}' } }", '#{}} }'
|
||||
|
||||
eq "#{"'#{ ({a: "b#{1}"}['a']) }'"}", "'b1'"
|
||||
# TODO: improve heregex interpolation tests
|
||||
|
||||
test "heregex interpolation", ->
|
||||
eq /\\#{}\\\"/ + '', ///
|
||||
#{
|
||||
"#{ '\\' }" # normal comment
|
||||
}
|
||||
# regex comment
|
||||
\#{}
|
||||
\\ \"
|
||||
/// + ''
|
||||
10
test/javascript_literals.coffee
Normal file
10
test/javascript_literals.coffee
Normal file
@@ -0,0 +1,10 @@
|
||||
# Javascript Literals
|
||||
# -------------------
|
||||
|
||||
# TODO: refactor javascript literal tests
|
||||
# TODO: add indexing and method invocation tests: `[1]`[0] is 1, `function(){}`.call()
|
||||
|
||||
eq '\\`', `
|
||||
// Inline JS
|
||||
"\\\`"
|
||||
`
|
||||
44
test/numbers.coffee
Normal file
44
test/numbers.coffee
Normal file
@@ -0,0 +1,44 @@
|
||||
# Number Literals
|
||||
# ---------------
|
||||
|
||||
# * Decimal Integer Literals
|
||||
# * Octal Integer Literals
|
||||
# * Hexadecimal Integer Literals
|
||||
# * Scientific Notation Integer Literals
|
||||
# * Scientific Notation Non-Integer Literals
|
||||
# * Non-Integer Literals
|
||||
|
||||
|
||||
# Decimal Integer Literals
|
||||
|
||||
test "call methods directly on numbers", ->
|
||||
eq 4, 4.valueOf()
|
||||
eq '11', 4.toString 3
|
||||
|
||||
eq -1, 3 -4
|
||||
|
||||
#764: Numbers should be indexable
|
||||
eq Number::toString, 42['toString']
|
||||
|
||||
eq Number::toString, 42.toString
|
||||
|
||||
|
||||
# Non-Integer Literals
|
||||
|
||||
# Decimal number literals.
|
||||
value = .25 + .75
|
||||
ok value is 1
|
||||
value = 0.0 + -.25 - -.75 + 0.0
|
||||
ok value is 0.5
|
||||
|
||||
#764: Numbers should be indexable
|
||||
eq Number::toString, 4.2['toString']
|
||||
eq Number::toString, .42['toString']
|
||||
|
||||
eq Number::toString, 4.2.toString
|
||||
eq Number::toString, .42.toString
|
||||
|
||||
test '#1168: leading floating point suppresses newline', ->
|
||||
eq 1, do ->
|
||||
1
|
||||
.5 + 0.5
|
||||
@@ -1,47 +1,14 @@
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
# Object Literals
|
||||
# ---------------
|
||||
|
||||
ok a.length is 2
|
||||
|
||||
|
||||
neg = (3 -4)
|
||||
|
||||
ok neg is -1
|
||||
|
||||
|
||||
# Decimal number literals.
|
||||
value = .25 + .75
|
||||
ok value is 1
|
||||
value = 0.0 + -.25 - -.75 + 0.0
|
||||
ok value is 0.5
|
||||
|
||||
|
||||
# Can call methods directly on numbers.
|
||||
4.valueOf() is 4
|
||||
|
||||
|
||||
func = ->
|
||||
return if true
|
||||
|
||||
ok func() is undefined
|
||||
|
||||
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
# TODO: refactor object literal tests
|
||||
# TODO: add indexing and method invocation tests: {a}['a'] is a, {a}.a()
|
||||
|
||||
trailingComma = {k1: "v1", k2: 4, k3: (-> true),}
|
||||
ok trailingComma.k3() and (trailingComma.k2 is 4) and (trailingComma.k1 is "v1")
|
||||
|
||||
|
||||
ok {a: (num) -> num is 10 }.a 10
|
||||
|
||||
|
||||
moe = {
|
||||
name: 'Moe'
|
||||
greet: (salutation) ->
|
||||
@@ -50,138 +17,70 @@ moe = {
|
||||
@['greet'] "Hello"
|
||||
10: 'number'
|
||||
}
|
||||
|
||||
ok moe.hello() is "Hello Moe"
|
||||
ok moe[10] is 'number'
|
||||
|
||||
moe.hello = ->
|
||||
this['greet'] "Hello"
|
||||
|
||||
ok moe.hello() is 'Hello Moe'
|
||||
|
||||
|
||||
obj = {
|
||||
is: -> yes,
|
||||
'not': -> no,
|
||||
}
|
||||
|
||||
ok obj.is()
|
||||
ok not obj.not()
|
||||
|
||||
|
||||
### Top-level object literal... ###
|
||||
obj: 1
|
||||
### ...doesn't break things. ###
|
||||
|
||||
# Funky indentation within non-comma-seperated arrays.
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
|
||||
|
||||
# Object literals should be able to include keywords.
|
||||
obj = {class: 'höt'}
|
||||
obj.function = 'dog'
|
||||
|
||||
ok obj.class + obj.function is 'hötdog'
|
||||
|
||||
|
||||
# But keyword assignment should be smart enough not to stringify variables.
|
||||
func = ->
|
||||
this == 'this'
|
||||
|
||||
ok func() is false
|
||||
# Implicit objects as part of chained calls.
|
||||
pluck = (x) -> x.a
|
||||
eq 100, pluck pluck pluck a: a: a: 100
|
||||
|
||||
|
||||
# New fancy implicit objects:
|
||||
config =
|
||||
development:
|
||||
server: 'localhost'
|
||||
timeout: 10
|
||||
test "YAML-style object literals", ->
|
||||
obj =
|
||||
a: 1
|
||||
b: 2
|
||||
eq 1, obj.a
|
||||
eq 2, obj.b
|
||||
|
||||
production:
|
||||
server: 'dreamboat'
|
||||
timeout: 1000
|
||||
config =
|
||||
development:
|
||||
server: 'localhost'
|
||||
timeout: 10
|
||||
|
||||
ok config.development.server is 'localhost'
|
||||
ok config.production.server is 'dreamboat'
|
||||
ok config.development.timeout is 10
|
||||
ok config.production.timeout is 1000
|
||||
production:
|
||||
server: 'dreamboat'
|
||||
timeout: 1000
|
||||
|
||||
obj =
|
||||
a: 1
|
||||
b: 2
|
||||
|
||||
ok obj.a is 1
|
||||
ok obj.b is 2
|
||||
ok config.development.server is 'localhost'
|
||||
ok config.production.server is 'dreamboat'
|
||||
ok config.development.timeout is 10
|
||||
ok config.production.timeout is 1000
|
||||
|
||||
obj =
|
||||
a: 1,
|
||||
b: 2,
|
||||
|
||||
ok obj.a is 1
|
||||
ok obj.b is 2
|
||||
|
||||
|
||||
# Implicit objects nesting.
|
||||
obj =
|
||||
options:
|
||||
value: yes
|
||||
|
||||
fn: ->
|
||||
{}
|
||||
null
|
||||
|
||||
ok obj.options.value is yes
|
||||
ok obj.fn() is null
|
||||
|
||||
|
||||
# Implicit arguments to function calls:
|
||||
func = (obj) -> obj.a
|
||||
func2 = -> arguments
|
||||
|
||||
result = func
|
||||
a: 10
|
||||
|
||||
ok result is 10
|
||||
|
||||
result = func
|
||||
"a": 20
|
||||
|
||||
ok result is 20
|
||||
|
||||
third = (a, b, c) -> c
|
||||
obj =
|
||||
one: 'one'
|
||||
two: third 'one', 'two', 'three'
|
||||
|
||||
ok obj.one is 'one'
|
||||
ok obj.two is 'three'
|
||||
|
||||
a = b = undefined
|
||||
|
||||
result = func
|
||||
b:1
|
||||
a
|
||||
|
||||
ok result is undefined
|
||||
|
||||
result = func
|
||||
a:
|
||||
b:2
|
||||
b:1
|
||||
ok result.b is 2
|
||||
|
||||
result = func2
|
||||
a:1
|
||||
b
|
||||
c:1
|
||||
|
||||
ok result.length is 3
|
||||
ok result[2].c is 1
|
||||
|
||||
# Implicit objects with wacky indentation:
|
||||
obj =
|
||||
'reverse': (obj) ->
|
||||
@@ -202,7 +101,6 @@ obj =
|
||||
[],
|
||||
[],
|
||||
[]]
|
||||
|
||||
ok obj.abc().join(' ') is 'a b c'
|
||||
ok obj.one.length is 5
|
||||
ok obj.one[4] is 4
|
||||
@@ -212,29 +110,14 @@ ok obj.red.orange.yellow.green is 'blue'
|
||||
ok obj.red.indigo is 'violet'
|
||||
ok obj.misdent.toString() is ',,,'
|
||||
|
||||
second = (x, y) -> y
|
||||
obj = then second 'the',
|
||||
1: 1
|
||||
two:
|
||||
three: ->
|
||||
four five,
|
||||
six: seven
|
||||
three: 3
|
||||
|
||||
ok obj[1] is 1
|
||||
ok obj.three is 3
|
||||
|
||||
|
||||
# Implicit objects as part of chained calls.
|
||||
pluck = (x) -> x.a
|
||||
eq 100, pluck pluck pluck a: a: a: 100
|
||||
|
||||
|
||||
eq '\\`', `
|
||||
// Inline JS
|
||||
"\\\`"
|
||||
`
|
||||
#542: Objects leading expression statement should be parenthesized.
|
||||
{f: -> ok yes }.f() + 1
|
||||
|
||||
# String-keyed objects shouldn't suppress newlines.
|
||||
one =
|
||||
'>!': 3
|
||||
six: -> 10
|
||||
ok not one.six
|
||||
|
||||
# Shorthand objects with property references.
|
||||
obj =
|
||||
@@ -244,27 +127,91 @@ obj =
|
||||
two: 2
|
||||
object: -> {@one, @two}
|
||||
list: -> [@one, @two]
|
||||
|
||||
|
||||
result = obj.object()
|
||||
eq result.one, 1
|
||||
eq result.two, 2
|
||||
eq result.two, obj.list()[1]
|
||||
|
||||
third = (a, b, c) -> c
|
||||
obj =
|
||||
one: 'one'
|
||||
two: third 'one', 'two', 'three'
|
||||
ok obj.one is 'one'
|
||||
ok obj.two is 'three'
|
||||
|
||||
#542: Objects leading expression statement should be parenthesized.
|
||||
{f: -> ok yes }.f() + 1
|
||||
test "invoking functions with implicit object literals", ->
|
||||
generateGetter = (prop) -> (obj) -> obj[prop]
|
||||
getA = generateGetter 'a'
|
||||
getArgs = -> arguments
|
||||
a = b = 30
|
||||
|
||||
result = getA
|
||||
a: 10
|
||||
eq 10, result
|
||||
|
||||
#764: Boolean/Number should be indexable.
|
||||
ok 42['toString']
|
||||
ok on['toString']
|
||||
result = getA
|
||||
"a": 20
|
||||
eq 20, result
|
||||
|
||||
result = getA a,
|
||||
b:1
|
||||
eq undefined, result
|
||||
|
||||
# String-keyed objects shouldn't suppress newlines.
|
||||
one =
|
||||
'>!': 3
|
||||
six: -> 10
|
||||
result = getA b:1
|
||||
a:43
|
||||
eq 43, result
|
||||
|
||||
ok not one.six
|
||||
result = getA b:1,
|
||||
a:62
|
||||
eq undefined, result
|
||||
|
||||
result = getA
|
||||
b:1
|
||||
a
|
||||
eq undefined, result
|
||||
|
||||
result = getA
|
||||
a:
|
||||
b:2
|
||||
b:1
|
||||
eq 2, result.b
|
||||
|
||||
result = getArgs
|
||||
a:1
|
||||
b
|
||||
c:1
|
||||
ok result.length is 3
|
||||
ok result[2].c is 1
|
||||
|
||||
result = getA b: 13, a: 42, 2
|
||||
eq 42, result
|
||||
|
||||
result = getArgs a:1, (1 + 1)
|
||||
ok result[1] is 2
|
||||
|
||||
result = getArgs a:1, b
|
||||
ok result.length is 2
|
||||
ok result[1] is 30
|
||||
|
||||
result = getArgs a:1, b, b:1, a
|
||||
ok result.length is 4
|
||||
ok result[2].b is 1
|
||||
|
||||
throws -> CoffeeScript.compile "a = b:1, c"
|
||||
|
||||
test "some weird indentation in YAML-style object literals", ->
|
||||
two = (a, b) -> b
|
||||
obj = then two 1,
|
||||
1: 1
|
||||
a:
|
||||
b: ->
|
||||
fn c,
|
||||
d: e
|
||||
f: 1
|
||||
eq 1, obj[1]
|
||||
|
||||
test "#1274: `{} = a()` compiles to `false` instead of `a()`", ->
|
||||
a = false
|
||||
fn = -> a = true
|
||||
{} = fn()
|
||||
ok a
|
||||
@@ -1,6 +1,13 @@
|
||||
# Operators
|
||||
# ---------
|
||||
|
||||
# * Operators
|
||||
# * Existential Operator (Binary)
|
||||
# * Existential Operator (Unary)
|
||||
# * Aliased Operators
|
||||
# * [not] in/of
|
||||
# * Chained Comparison
|
||||
|
||||
test "binary (2-ary) math operators do not require spaces", ->
|
||||
a = 1
|
||||
b = -1
|
||||
@@ -42,84 +49,72 @@ test "`instanceof`", ->
|
||||
ok new Number not instanceof String
|
||||
ok new Array not instanceof Boolean
|
||||
|
||||
test "use `::` operator on keywords `this` and `@`", ->
|
||||
nonce = {}
|
||||
obj =
|
||||
withAt: -> @::prop
|
||||
withThis: -> this::prop
|
||||
obj.prototype = prop: nonce
|
||||
eq nonce, obj.withAt()
|
||||
eq nonce, obj.withThis()
|
||||
|
||||
#### Compound Assignment Operators
|
||||
|
||||
test "boolean operators", ->
|
||||
# Existential Operator (Binary)
|
||||
|
||||
test "binary existential operator", ->
|
||||
nonce = {}
|
||||
|
||||
a = 0
|
||||
a or= nonce
|
||||
eq nonce, a
|
||||
b = a ? nonce
|
||||
eq nonce, b
|
||||
|
||||
b = 1
|
||||
b or= nonce
|
||||
eq 1, b
|
||||
a = null
|
||||
b = undefined
|
||||
b = a ? nonce
|
||||
eq nonce, b
|
||||
|
||||
c = 0
|
||||
c and= nonce
|
||||
eq 0, c
|
||||
a = false
|
||||
b = a ? nonce
|
||||
eq false, b
|
||||
|
||||
d = 1
|
||||
d and= nonce
|
||||
eq nonce, d
|
||||
a = 0
|
||||
b = a ? nonce
|
||||
eq 0, b
|
||||
|
||||
# ensure that RHS is treated as a group
|
||||
e = f = false
|
||||
e and= f or true
|
||||
eq false, e
|
||||
test "binary existential operator conditionally evaluates second operand", ->
|
||||
i = 1
|
||||
func = -> i -= 1
|
||||
result = func() ? func()
|
||||
eq result, 0
|
||||
|
||||
test "compound assignment as a sub expression", ->
|
||||
[a, b, c] = [1, 2, 3]
|
||||
eq 6, (a + b += c)
|
||||
eq 1, a
|
||||
eq 5, b
|
||||
eq 3, c
|
||||
|
||||
# *note: this test could still use refactoring*
|
||||
test "compound assignment should be careful about caching variables", ->
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq 1, list[1]
|
||||
eq 1, count
|
||||
|
||||
list[++count] ?= 2
|
||||
eq 2, list[2]
|
||||
eq 2, count
|
||||
|
||||
list[count++] and= 6
|
||||
eq 6, list[2]
|
||||
eq 3, count
|
||||
|
||||
base = ->
|
||||
++count
|
||||
base
|
||||
|
||||
base().four or= 4
|
||||
eq 4, base.four
|
||||
eq 4, count
|
||||
|
||||
base().five ?= 5
|
||||
eq 5, base.five
|
||||
eq 5, count
|
||||
|
||||
test "compound assignment with implicit objects", ->
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
eq 1, obj.one
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
eq undefined, obj.one
|
||||
eq 2, obj.two
|
||||
test "binary existential operator with negative number", ->
|
||||
a = null ? - 1
|
||||
eq -1, a
|
||||
|
||||
|
||||
#### `is`,`isnt`,`==`,`!=`
|
||||
# Existential Operator (Unary)
|
||||
|
||||
test "postfix existential operator", ->
|
||||
ok (if nonexistent? then false else true)
|
||||
defined = true
|
||||
ok defined?
|
||||
defined = false
|
||||
ok defined?
|
||||
|
||||
test "postfix existential operator only evaluates its operand once", ->
|
||||
semaphore = 0
|
||||
fn = ->
|
||||
ok false if semaphore
|
||||
++semaphore
|
||||
ok(if fn()? then true else false)
|
||||
|
||||
test "negated postfix existential operator", ->
|
||||
ok !nothing?.value
|
||||
|
||||
test "postfix existential operator on expressions", ->
|
||||
eq true, (1 or 0)?, true
|
||||
|
||||
|
||||
# `is`,`isnt`,`==`,`!=`
|
||||
|
||||
test "`==` and `is` should be interchangeable", ->
|
||||
a = b = 1
|
||||
@@ -135,7 +130,7 @@ test "`!=` and `isnt` should be interchangeable", ->
|
||||
ok a isnt b
|
||||
|
||||
|
||||
#### `in`, `of`
|
||||
# [not] in/of
|
||||
|
||||
# - `in` should check if an array contains a value using `indexOf`
|
||||
# - `of` should check if a property is defined on an object using `in`
|
||||
@@ -189,8 +184,12 @@ test "#768: `in` should preserve evaluation order", ->
|
||||
ok a() not in [b(),c()]
|
||||
eq 3, share
|
||||
|
||||
test "#1099: empty array after `in` should compile to `false`", ->
|
||||
eq 1, [5 in []].length
|
||||
eq false, do -> return 0 in []
|
||||
|
||||
#### Chainable Operators
|
||||
|
||||
# Chained Comparison
|
||||
|
||||
test "chainable operators", ->
|
||||
ok 100 > 10 > 1 > 0 > -1
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# Option Parser
|
||||
# -------------
|
||||
|
||||
# TODO: refactor option parser tests
|
||||
|
||||
# Ensure that the OptionParser handles arguments correctly.
|
||||
return unless require?
|
||||
{OptionParser} = require './../lib/optparse'
|
||||
85
test/ranges.coffee
Normal file
85
test/ranges.coffee
Normal file
@@ -0,0 +1,85 @@
|
||||
# Range Literals
|
||||
# --------------
|
||||
|
||||
# TODO: add indexing and method invocation tests: [1..4][0] is 1, [0...3].toString()
|
||||
|
||||
# shared array
|
||||
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
test "basic inclusive ranges", ->
|
||||
arrayEq [1, 2, 3] , [1..3]
|
||||
arrayEq [0, 1, 2] , [0..2]
|
||||
arrayEq [0, 1] , [0..1]
|
||||
arrayEq [0] , [0..0]
|
||||
arrayEq [-1] , [-1..-1]
|
||||
arrayEq [-1, 0] , [-1..0]
|
||||
arrayEq [-1, 0, 1], [-1..1]
|
||||
|
||||
test "basic exclusive ranges", ->
|
||||
arrayEq [1, 2, 3] , [1...4]
|
||||
arrayEq [0, 1, 2] , [0...3]
|
||||
arrayEq [0, 1] , [0...2]
|
||||
arrayEq [0] , [0...1]
|
||||
arrayEq [-1] , [-1...0]
|
||||
arrayEq [-1, 0] , [-1...1]
|
||||
arrayEq [-1, 0, 1], [-1...2]
|
||||
|
||||
arrayEq [], [1...1]
|
||||
arrayEq [], [0...0]
|
||||
arrayEq [], [-1...-1]
|
||||
|
||||
test "downward ranges", ->
|
||||
arrayEq shared, [9..0].reverse()
|
||||
arrayEq [5, 4, 3, 2] , [5..2]
|
||||
arrayEq [2, 1, 0, -1], [2..-1]
|
||||
|
||||
arrayEq [3, 2, 1] , [3..1]
|
||||
arrayEq [2, 1, 0] , [2..0]
|
||||
arrayEq [1, 0] , [1..0]
|
||||
arrayEq [0] , [0..0]
|
||||
arrayEq [-1] , [-1..-1]
|
||||
arrayEq [0, -1] , [0..-1]
|
||||
arrayEq [1, 0, -1] , [1..-1]
|
||||
arrayEq [0, -1, -2], [0..-2]
|
||||
|
||||
arrayEq [4, 3, 2], [4...1]
|
||||
arrayEq [3, 2, 1], [3...0]
|
||||
arrayEq [2, 1] , [2...0]
|
||||
arrayEq [1] , [1...0]
|
||||
arrayEq [] , [0...0]
|
||||
arrayEq [] , [-1...-1]
|
||||
arrayEq [0] , [0...-1]
|
||||
arrayEq [0, -1] , [0...-2]
|
||||
arrayEq [1, 0] , [1...-1]
|
||||
arrayEq [2, 1, 0], [2...-1]
|
||||
|
||||
test "ranges with variables as enpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [1, 2, 3], [a..b]
|
||||
arrayEq [1, 2] , [a...b]
|
||||
b = -2
|
||||
arrayEq [1, 0, -1, -2], [a..b]
|
||||
arrayEq [1, 0, -1] , [a...b]
|
||||
|
||||
test "ranges with expressions as endpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
|
||||
arrayEq [2, 3, 4, 5] , [(a+1)...2*b]
|
||||
|
||||
test "large ranges are generated with looping constructs", ->
|
||||
down = [99..0]
|
||||
eq 100, (len = down.length)
|
||||
eq 0, down[len - 1]
|
||||
|
||||
up = [0...100]
|
||||
eq 100, (len = up.length)
|
||||
eq 99, up[len - 1]
|
||||
|
||||
test "#1012 slices with arguments object", ->
|
||||
expected = [0..9]
|
||||
argsAtStart = (-> [arguments[0]..9]) 0
|
||||
arrayEq expected, argsAtStart
|
||||
argsAtEnd = (-> [0..arguments[0]]) 9
|
||||
arrayEq expected, argsAtEnd
|
||||
argsAtBoth = (-> [arguments[0]..arguments[1]]) 0, 9
|
||||
arrayEq expected, argsAtBoth
|
||||
@@ -1,6 +1,10 @@
|
||||
# Regular Expressions
|
||||
# -------------------
|
||||
#TODO: add some rigorous regex interpolation tests
|
||||
# Regular Expression Literals
|
||||
# ---------------------------
|
||||
|
||||
# TODO: add method invocation tests: /regex/.toString()
|
||||
|
||||
# * Regexen
|
||||
# * Heregexen
|
||||
|
||||
test "basic regular expression literals", ->
|
||||
ok 'a'.match(/a/)
|
||||
@@ -16,6 +20,10 @@ test "division is not confused for a regular expression", ->
|
||||
g = 1
|
||||
eq 2, a / b/g
|
||||
|
||||
a = 10
|
||||
b = a /= 4 / 2
|
||||
eq a, 5
|
||||
|
||||
obj = method: -> 2
|
||||
two = 2
|
||||
eq 2, (obj.method()/two + obj.method()/two)
|
||||
@@ -24,9 +32,6 @@ test "division is not confused for a regular expression", ->
|
||||
eq 2, (4)/2/i
|
||||
eq 1, i/i/i
|
||||
|
||||
test "backslash escapes", ->
|
||||
eq "\\/\\\\", /\/\\/.source
|
||||
|
||||
test "#764: regular expressions should be indexable", ->
|
||||
eq /0/['source'], ///#{0}///['source']
|
||||
|
||||
@@ -34,7 +39,7 @@ test "#584: slashes are allowed unescaped in character classes", ->
|
||||
ok /^a\/[/]b$/.test 'a//b'
|
||||
|
||||
|
||||
#### Heregexe(n|s)
|
||||
# Heregexe(n|s)
|
||||
|
||||
test "a heregex will ignore whitespace and comments", ->
|
||||
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
|
||||
@@ -42,15 +47,5 @@ test "a heregex will ignore whitespace and comments", ->
|
||||
Heregex? / // # or not
|
||||
///gim + ''
|
||||
|
||||
test "heregex interpolation", ->
|
||||
eq /\\#{}\\\"/ + '', ///
|
||||
#{
|
||||
"#{ '\\' }" # normal comment
|
||||
}
|
||||
# regex comment
|
||||
\#{}
|
||||
\\ \"
|
||||
/// + ''
|
||||
|
||||
test "an empty heregex will compile to an empty, non-capturing group", ->
|
||||
eq /(?:)/ + '', /// /// + ''
|
||||
4
test/repl.coffee
Normal file
4
test/repl.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
# REPL
|
||||
# ----
|
||||
|
||||
# TODO: add tests
|
||||
22
test/scope.coffee
Normal file
22
test/scope.coffee
Normal file
@@ -0,0 +1,22 @@
|
||||
# Scope
|
||||
# -----
|
||||
|
||||
# * Variable Safety
|
||||
# * Variable Shadowing
|
||||
# * Auto-closure (`do`)
|
||||
# * Global Scope Leaks
|
||||
|
||||
test "reference `arguments` inside of functions", ->
|
||||
sumOfArgs = ->
|
||||
sum = (a,b) -> a + b
|
||||
sum = 0
|
||||
sum += num for num in arguments
|
||||
sum
|
||||
eq 10, sumOfArgs(0, 1, 2, 3, 4)
|
||||
|
||||
test "assignment to an Object.prototype-named variable should not leak to outer scope", ->
|
||||
# FIXME: fails on IE
|
||||
(->
|
||||
constructor = 'word'
|
||||
)()
|
||||
ok constructor isnt 'word'
|
||||
@@ -1,83 +1,13 @@
|
||||
# Ranges, Slices, and Splices
|
||||
# ---------------------------
|
||||
# Slicing and Splicing
|
||||
# --------------------
|
||||
|
||||
# * Slicing
|
||||
# * Splicing
|
||||
|
||||
# shared array
|
||||
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
|
||||
#### Ranges
|
||||
|
||||
test "basic inclusive ranges", ->
|
||||
arrayEq [1, 2, 3] , [1..3]
|
||||
arrayEq [0, 1, 2] , [0..2]
|
||||
arrayEq [0, 1] , [0..1]
|
||||
arrayEq [0] , [0..0]
|
||||
arrayEq [-1] , [-1..-1]
|
||||
arrayEq [-1, 0] , [-1..0]
|
||||
arrayEq [-1, 0, 1], [-1..1]
|
||||
|
||||
test "basic exclusive ranges", ->
|
||||
arrayEq [1, 2, 3] , [1...4]
|
||||
arrayEq [0, 1, 2] , [0...3]
|
||||
arrayEq [0, 1] , [0...2]
|
||||
arrayEq [0] , [0...1]
|
||||
arrayEq [-1] , [-1...0]
|
||||
arrayEq [-1, 0] , [-1...1]
|
||||
arrayEq [-1, 0, 1], [-1...2]
|
||||
|
||||
arrayEq [], [1...1]
|
||||
arrayEq [], [0...0]
|
||||
arrayEq [], [-1...-1]
|
||||
|
||||
test "downward ranges", ->
|
||||
arrayEq shared, [9..0].reverse()
|
||||
arrayEq [5, 4, 3, 2] , [5..2]
|
||||
arrayEq [2, 1, 0, -1], [2..-1]
|
||||
|
||||
arrayEq [3, 2, 1] , [3..1]
|
||||
arrayEq [2, 1, 0] , [2..0]
|
||||
arrayEq [1, 0] , [1..0]
|
||||
arrayEq [0] , [0..0]
|
||||
arrayEq [-1] , [-1..-1]
|
||||
arrayEq [0, -1] , [0..-1]
|
||||
arrayEq [1, 0, -1] , [1..-1]
|
||||
arrayEq [0, -1, -2], [0..-2]
|
||||
|
||||
arrayEq [4, 3, 2], [4...1]
|
||||
arrayEq [3, 2, 1], [3...0]
|
||||
arrayEq [2, 1] , [2...0]
|
||||
arrayEq [1] , [1...0]
|
||||
arrayEq [] , [0...0]
|
||||
arrayEq [] , [-1...-1]
|
||||
arrayEq [0] , [0...-1]
|
||||
arrayEq [0, -1] , [0...-2]
|
||||
arrayEq [1, 0] , [1...-1]
|
||||
arrayEq [2, 1, 0], [2...-1]
|
||||
|
||||
test "ranges with variables as enpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [1, 2, 3], [a..b]
|
||||
arrayEq [1, 2] , [a...b]
|
||||
b = -2
|
||||
arrayEq [1, 0, -1, -2], [a..b]
|
||||
arrayEq [1, 0, -1] , [a...b]
|
||||
|
||||
test "ranges with expressions as endpoints", ->
|
||||
[a, b] = [1, 3]
|
||||
arrayEq [2, 3, 4, 5, 6], [(a+1)..2*b]
|
||||
arrayEq [2, 3, 4, 5] , [(a+1)...2*b]
|
||||
|
||||
test "large ranges are generated with looping constructs", ->
|
||||
down = [99..0]
|
||||
eq 100, (len = down.length)
|
||||
eq 0, down[len - 1]
|
||||
|
||||
up = [0...100]
|
||||
eq 100, (len = up.length)
|
||||
eq 99, up[len - 1]
|
||||
|
||||
|
||||
#### Slices
|
||||
# Slicing
|
||||
|
||||
test "basic slicing", ->
|
||||
arrayEq [7, 8, 9] , shared[7..9]
|
||||
@@ -123,7 +53,7 @@ test "string slicing", ->
|
||||
ok str[-5..] is "vwxyz"
|
||||
|
||||
|
||||
#### Splices
|
||||
# Splicing
|
||||
|
||||
test "basic splicing", ->
|
||||
ary = [0..9]
|
||||
134
test/soaks.coffee
Normal file
134
test/soaks.coffee
Normal file
@@ -0,0 +1,134 @@
|
||||
# Soaks
|
||||
# -----
|
||||
|
||||
# * Soaked Property Access
|
||||
# * Soaked Method Invocation
|
||||
# * Soaked Function Invocation
|
||||
|
||||
|
||||
# Soaked Property Access
|
||||
|
||||
test "soaked property access", ->
|
||||
nonce = {}
|
||||
obj = a: b: nonce
|
||||
eq nonce , obj?.a.b
|
||||
eq nonce , obj?['a'].b
|
||||
eq nonce , obj.a?.b
|
||||
eq nonce , obj?.a?['b']
|
||||
eq undefined, obj?.a?.non?.existent?.property
|
||||
|
||||
test "soaked property access caches method calls", ->
|
||||
nonce ={}
|
||||
obj = fn: -> a: nonce
|
||||
eq nonce , obj.fn()?.a
|
||||
eq undefined, obj.fn()?.b
|
||||
|
||||
test "soaked property access chaching", ->
|
||||
nonce = {}
|
||||
counter = 0
|
||||
fn = ->
|
||||
counter++
|
||||
'self'
|
||||
obj =
|
||||
self: -> @
|
||||
prop: nonce
|
||||
eq nonce, obj[fn()]()[fn()]()[fn()]()?.prop
|
||||
eq 3, counter
|
||||
|
||||
test "method calls on soaked methods", ->
|
||||
nonce = {}
|
||||
obj = null
|
||||
eq undefined, obj?.a().b()
|
||||
obj = a: -> b: -> nonce
|
||||
eq nonce , obj?.a().b()
|
||||
|
||||
test "postfix existential operator mixes well with soaked property accesses", ->
|
||||
eq false, nonexistent?.property?
|
||||
|
||||
test "function invocation with soaked property access", ->
|
||||
id = (_) -> _
|
||||
eq undefined, id nonexistent?.method()
|
||||
|
||||
test "if-to-ternary should safely parenthesize soaked property accesses", ->
|
||||
ok (if nonexistent?.property then false else true)
|
||||
|
||||
test "#726", ->
|
||||
# TODO: check this test, looks like it's not really testing anything
|
||||
eq undefined, nonexistent?[Date()]
|
||||
|
||||
test "#756", ->
|
||||
# TODO: improve this test
|
||||
a = null
|
||||
ok isNaN a?.b.c + 1
|
||||
eq undefined, a?.b.c += 1
|
||||
eq undefined, ++a?.b.c
|
||||
eq undefined, delete a?.b.c
|
||||
|
||||
test "operations on soaked properties", ->
|
||||
# TODO: improve this test
|
||||
a = b: {c: 0}
|
||||
eq 1, a?.b.c + 1
|
||||
eq 1, a?.b.c += 1
|
||||
eq 2, ++a?.b.c
|
||||
eq yes, delete a?.b.c
|
||||
|
||||
|
||||
# Soaked Method Invocation
|
||||
|
||||
test "soaked method invocation", ->
|
||||
nonce = {}
|
||||
counter = 0
|
||||
obj =
|
||||
self: -> @
|
||||
increment: -> counter++; @
|
||||
eq obj , obj.self?()
|
||||
eq undefined, obj.method?()
|
||||
eq nonce , obj.self?().property = nonce
|
||||
eq undefined, obj.method?().property = nonce
|
||||
eq obj , obj.increment().increment().self?()
|
||||
eq 2 , counter
|
||||
|
||||
test "#733", ->
|
||||
a = b: {c: null}
|
||||
eq a.b?.c?(), undefined
|
||||
a.b?.c or= (it) -> it
|
||||
eq a.b?.c?(1), 1
|
||||
eq a.b?.c?([2, 3]...), 2
|
||||
|
||||
|
||||
# Soaked Function Invocation
|
||||
|
||||
test "soaked function invocation", ->
|
||||
nonce = {}
|
||||
id = (_) -> _
|
||||
eq nonce , id?(nonce)
|
||||
eq nonce , (id? nonce)
|
||||
eq undefined, nonexistent?(nonce)
|
||||
eq undefined, (nonexistent? nonce)
|
||||
|
||||
test "soaked function invocation with generated functions", ->
|
||||
nonce = {}
|
||||
id = (_) -> _
|
||||
maybe = (fn, arg) -> if typeof fn is 'function' then () -> fn(arg)
|
||||
eq maybe(id, nonce)?(), nonce
|
||||
eq (maybe id, nonce)?(), nonce
|
||||
eq (maybe false, nonce)?(), undefined
|
||||
|
||||
test "soaked constructor invocation", ->
|
||||
eq 42 , +new Number? 42
|
||||
eq undefined, new Other? 42
|
||||
|
||||
test "soaked constructor invocations with caching and property access", ->
|
||||
semaphore = 0
|
||||
nonce = {}
|
||||
class C
|
||||
constructor: ->
|
||||
ok false if semaphore
|
||||
semaphore++
|
||||
prop: nonce
|
||||
eq nonce, (new C())?.prop
|
||||
eq 1, semaphore
|
||||
|
||||
test "soaked function invocation safe on non-functions", ->
|
||||
eq undefined, 0?(1)
|
||||
eq undefined, 0? 1, 2
|
||||
@@ -1,86 +1,85 @@
|
||||
# String Literals
|
||||
# ---------------
|
||||
|
||||
# TODO: refactor string literal tests
|
||||
# TODO: add indexing and method invocation tests: "string"["toString"] is String::toString, "string".toString() is "string"
|
||||
|
||||
# * Strings
|
||||
# * Heredocs
|
||||
|
||||
test "backslash escapes", ->
|
||||
eq "\\/\\\\", /\/\\/.source
|
||||
|
||||
eq '(((dollars)))', '\(\(\(dollars\)\)\)'
|
||||
eq 'one two three', "one
|
||||
two
|
||||
three"
|
||||
eq "four five", 'four
|
||||
|
||||
five'
|
||||
|
||||
#647
|
||||
eq "''Hello, World\\''", '''
|
||||
'\'Hello, World\\\''
|
||||
'''
|
||||
eq '""Hello, World\\""', """
|
||||
"\"Hello, World\\\""
|
||||
"""
|
||||
eq 'Hello, World\n', '''
|
||||
Hello, World\
|
||||
|
||||
'''
|
||||
|
||||
a = """
|
||||
basic heredoc
|
||||
on two lines
|
||||
"""
|
||||
|
||||
ok a is "basic heredoc\non two lines"
|
||||
|
||||
|
||||
a = '''
|
||||
a
|
||||
"b
|
||||
c
|
||||
'''
|
||||
|
||||
ok a is "a\n \"b\nc"
|
||||
|
||||
|
||||
a = """
|
||||
a
|
||||
b
|
||||
c
|
||||
"""
|
||||
|
||||
ok a is "a\n b\n c"
|
||||
|
||||
|
||||
a = '''one-liner'''
|
||||
|
||||
ok a is 'one-liner'
|
||||
|
||||
|
||||
a = """
|
||||
out
|
||||
here
|
||||
"""
|
||||
|
||||
ok a is "out\nhere"
|
||||
|
||||
|
||||
a = '''
|
||||
a
|
||||
b
|
||||
c
|
||||
'''
|
||||
|
||||
ok a is " a\n b\nc"
|
||||
|
||||
|
||||
a = '''
|
||||
a
|
||||
|
||||
|
||||
b c
|
||||
'''
|
||||
|
||||
ok a is "a\n\n\nb c"
|
||||
|
||||
|
||||
a = '''more"than"one"quote'''
|
||||
|
||||
ok a is 'more"than"one"quote'
|
||||
|
||||
|
||||
val = 10
|
||||
|
||||
a = """
|
||||
basic heredoc #{val}
|
||||
on two lines
|
||||
"""
|
||||
|
||||
b = '''
|
||||
basic heredoc #{val}
|
||||
on two lines
|
||||
'''
|
||||
|
||||
ok a is "basic heredoc 10\non two lines"
|
||||
ok b is "basic heredoc \#{val}\non two lines"
|
||||
|
||||
|
||||
a = '''here's an apostrophe'''
|
||||
ok a is "here's an apostrophe"
|
||||
|
||||
|
||||
# The indentation detector ignores blank lines without trailing whitespace
|
||||
a = """
|
||||
one
|
||||
@@ -103,9 +102,6 @@ eq """ "\\\" """, ' "\\" '
|
||||
|
||||
eq ''' <- keep these spaces -> ''', ' <- keep these spaces -> '
|
||||
|
||||
eq 'multiline nested "interpolations" work', """multiline #{
|
||||
"nested #{(->
|
||||
ok yes
|
||||
"\"interpolations\""
|
||||
)()}"
|
||||
} work"""
|
||||
|
||||
test "#1046, empty string interpolations", ->
|
||||
eq "#{ }", ''
|
||||
@@ -27,10 +27,9 @@
|
||||
start = new Date
|
||||
success = total = done = failed = 0
|
||||
|
||||
say = (msg, yay) ->
|
||||
say = (msg) ->
|
||||
div = document.createElement 'div'
|
||||
div.appendChild document.createTextNode msg
|
||||
div.style.color = if yay then 'green' else 'red'
|
||||
stdout.appendChild div
|
||||
msg
|
||||
|
||||
@@ -72,16 +71,9 @@
|
||||
return
|
||||
ok no
|
||||
|
||||
|
||||
CoffeeScript.run = (code, cb) ->
|
||||
try Function(CoffeeScript.compile code, wrap: no)()
|
||||
catch e then cb(); throw e
|
||||
cb yes
|
||||
|
||||
run = (name) ->
|
||||
CoffeeScript.load "#{name}.coffee", (yay) ->
|
||||
say "#{ if yay then '\u2714' else '\u3000' } #{name}", yay
|
||||
++failed unless yay
|
||||
CoffeeScript.load "#{name}.coffee", ->
|
||||
say '\u2714 ' + name
|
||||
fin() if ++done is names.length
|
||||
|
||||
fin = ->
|
||||
@@ -92,30 +84,33 @@
|
||||
say msg, yay
|
||||
|
||||
run name for name in names = [
|
||||
'arguments'
|
||||
'arrays'
|
||||
'assignment'
|
||||
'break'
|
||||
'booleans'
|
||||
'classes'
|
||||
'comments'
|
||||
'compilation'
|
||||
'comprehensions'
|
||||
'control_flow'
|
||||
'exception_handling'
|
||||
'formatting'
|
||||
'function_invocation'
|
||||
'functions'
|
||||
'helpers'
|
||||
'importing'
|
||||
'interpolation'
|
||||
'javascript_literals'
|
||||
'numbers'
|
||||
'objects'
|
||||
'operators'
|
||||
'regular_expressions'
|
||||
'test_chaining'
|
||||
'test_classes'
|
||||
'test_compilation'
|
||||
'test_comprehensions'
|
||||
'test_existence'
|
||||
'test_functions'
|
||||
'test_heredocs'
|
||||
'conditionals'
|
||||
'test_literals'
|
||||
'test_pattern_matching'
|
||||
'ranges_slices_and_splices'
|
||||
'test_returns'
|
||||
'test_splats'
|
||||
'test_strings'
|
||||
'test_switch'
|
||||
'test_while'
|
||||
'option_parser'
|
||||
'ranges'
|
||||
'regexps'
|
||||
'repl'
|
||||
'scope'
|
||||
'slicing_and_splicing'
|
||||
'soaks'
|
||||
'strings'
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# Chaining
|
||||
# --------
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
|
||||
|
||||
# Basic chained function calls.
|
||||
identityWrap = (x) ->
|
||||
-> x
|
||||
|
||||
result = identityWrap(identityWrap(true))()()
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to look at prototypes on keywords.
|
||||
obj =
|
||||
withAt: -> @::prop
|
||||
withThis: -> this::prop
|
||||
proto:
|
||||
prop: 100
|
||||
obj.prototype = obj.proto
|
||||
eq obj.withAt() , 100
|
||||
eq obj.withThis(), 100
|
||||
|
||||
|
||||
# Chained accesses split on period/newline, backwards and forwards.
|
||||
str = 'god'
|
||||
|
||||
result = str.
|
||||
split('').
|
||||
reverse().
|
||||
reverse().
|
||||
reverse()
|
||||
|
||||
ok result.join('') is 'dog'
|
||||
|
||||
result = str
|
||||
.split('')
|
||||
.reverse()
|
||||
.reverse()
|
||||
.reverse()
|
||||
|
||||
ok result.join('') is 'dog'
|
||||
|
||||
|
||||
# Newline suppression for operators.
|
||||
six =
|
||||
1 +
|
||||
2 +
|
||||
3
|
||||
|
||||
ok six is 6
|
||||
|
||||
|
||||
# Ensure that indented array literals don't trigger whitespace rewriting.
|
||||
func = () ->
|
||||
ok arguments.length is 1
|
||||
|
||||
func(
|
||||
[[[[[],
|
||||
[]],
|
||||
[[]]]],
|
||||
[]])
|
||||
|
||||
greeting = id(
|
||||
"""
|
||||
Hello
|
||||
""")
|
||||
|
||||
ok greeting is "Hello"
|
||||
|
||||
ok not Date
|
||||
::
|
||||
?.foo, '`?.` and `::` should also continue lines'
|
||||
@@ -1,372 +0,0 @@
|
||||
# Test classes with a four-level inheritance chain.
|
||||
class Base
|
||||
func: (string) ->
|
||||
"zero/#{string}"
|
||||
|
||||
@static: (string) ->
|
||||
"static/#{string}"
|
||||
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild = class extends FirstChild
|
||||
func: (string) ->
|
||||
super('two/') + string
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/').length + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is '9two/three/four'
|
||||
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
# And now the same tests, but written in the manual style:
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-#{string}"
|
||||
|
||||
FirstChild = ->
|
||||
SecondChild = ->
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
|
||||
ThirdChild extends SecondChild extends FirstChild extends Base
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
|
||||
TopClass = (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
this
|
||||
|
||||
SuperClass = (arg) ->
|
||||
super 'super-' + arg
|
||||
this
|
||||
|
||||
SubClass = ->
|
||||
super 'sub'
|
||||
this
|
||||
|
||||
SuperClass extends TopClass
|
||||
SubClass extends SuperClass
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
# '@' referring to the current instance, and not being coerced into a call.
|
||||
class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
|
||||
|
||||
# super() calls in constructors of classes that are defined as object properties.
|
||||
class Hive
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
|
||||
|
||||
# Class with JS-keyword properties.
|
||||
class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
|
||||
|
||||
# Classes with methods that are pre-bound to the instance.
|
||||
# ... or statically, to the class.
|
||||
class Dog
|
||||
|
||||
constructor: (name) ->
|
||||
@name = name
|
||||
|
||||
bark: =>
|
||||
"#{@name} woofs!"
|
||||
|
||||
@static = =>
|
||||
new this('Dog')
|
||||
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
|
||||
obj = func: Dog.static
|
||||
|
||||
ok obj.func().name is 'Dog'
|
||||
|
||||
|
||||
# Testing a bound function in a bound function.
|
||||
class Mini
|
||||
num: 10
|
||||
generate: =>
|
||||
for i in [1..3]
|
||||
=>
|
||||
@num
|
||||
|
||||
m = new Mini
|
||||
eq (func() for func in m.generate()).join(' '), '10 10 10'
|
||||
|
||||
|
||||
# Testing a contructor called with varargs.
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
|
||||
out: ->
|
||||
"#{@one}-#{@two}-#{@three}"
|
||||
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
|
||||
|
||||
# Test calling super and passing along all arguments.
|
||||
class Parent
|
||||
method: (args...) -> @args = args
|
||||
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
|
||||
|
||||
# Test classes wrapped in decorators.
|
||||
func = (klass) ->
|
||||
klass::prop = 'value'
|
||||
klass
|
||||
|
||||
func class Test
|
||||
prop2: 'value2'
|
||||
|
||||
ok (new Test).prop is 'value'
|
||||
ok (new Test).prop2 is 'value2'
|
||||
|
||||
|
||||
# Test anonymous classes.
|
||||
obj =
|
||||
klass: class
|
||||
method: -> 'value'
|
||||
|
||||
instance = new obj.klass
|
||||
ok instance.method() is 'value'
|
||||
|
||||
|
||||
# Implicit objects as static properties.
|
||||
class Static
|
||||
@static =
|
||||
one: 1
|
||||
two: 2
|
||||
|
||||
ok Static.static.one is 1
|
||||
ok Static.static.two is 2
|
||||
|
||||
|
||||
# Nothing classes.
|
||||
c = class
|
||||
ok c instanceof Function
|
||||
|
||||
|
||||
# Classes with value'd constructors.
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
counter += 1
|
||||
inner = counter
|
||||
->
|
||||
@value = inner
|
||||
|
||||
class One
|
||||
constructor: classMaker()
|
||||
|
||||
class Two
|
||||
constructor: classMaker()
|
||||
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
|
||||
|
||||
# Exectuable class bodies.
|
||||
class A
|
||||
if true
|
||||
b: 'b'
|
||||
else
|
||||
c: 'c'
|
||||
|
||||
a = new A
|
||||
|
||||
eq a.b, 'b'
|
||||
eq a.c, undefined
|
||||
|
||||
|
||||
# Light metaprogramming.
|
||||
class Base
|
||||
@attr: (name) ->
|
||||
@::[name] = (val) ->
|
||||
if arguments.length > 0
|
||||
@["_#{name}"] = val
|
||||
else
|
||||
@["_#{name}"]
|
||||
|
||||
class Robot extends Base
|
||||
@attr 'power'
|
||||
@attr 'speed'
|
||||
|
||||
robby = new Robot
|
||||
|
||||
ok robby.power() is undefined
|
||||
|
||||
robby.power 11
|
||||
robby.speed Infinity
|
||||
|
||||
eq robby.power(), 11
|
||||
eq robby.speed(), Infinity
|
||||
|
||||
|
||||
# Namespaced classes do not reserve their function name in outside scope.
|
||||
one = {}
|
||||
two = {}
|
||||
|
||||
class one.Klass
|
||||
@label = "one"
|
||||
|
||||
class two.Klass
|
||||
@label = "two"
|
||||
|
||||
eq typeof Klass, 'undefined'
|
||||
eq one.Klass.label, 'one'
|
||||
eq two.Klass.label, 'two'
|
||||
|
||||
|
||||
# Nested classes.
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'outer'
|
||||
|
||||
class @Inner
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
|
||||
|
||||
# Variables in constructor bodies are correctly scoped.
|
||||
class A
|
||||
x = 1
|
||||
constructor: ->
|
||||
x = 10
|
||||
y = 20
|
||||
y = 2
|
||||
captured: ->
|
||||
{x, y}
|
||||
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
|
||||
|
||||
# Issue #924: Static methods in nested classes.
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
|
||||
eq A.B.c(), 5
|
||||
|
||||
|
||||
# `class extends this` ...
|
||||
class A
|
||||
func: -> 'A'
|
||||
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
|
||||
makeClass.call A
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
@@ -1,26 +0,0 @@
|
||||
# Ensure that carriage returns don't break compilation on Windows.
|
||||
eq CoffeeScript.compile('one\r\ntwo', bare: on), 'one;\ntwo;'
|
||||
|
||||
# `globals: on` removes `var`s
|
||||
eq CoffeeScript.compile('x = y', bare: on, globals: on), 'x = y;'
|
||||
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, fileName: 'test'
|
||||
|
||||
#750
|
||||
try ok not CoffeeScript.nodes 'f(->'
|
||||
catch e then eq e.message, 'unclosed CALL_START on line 1'
|
||||
|
||||
eq CoffeeScript.compile('for k of o then', bare: on, globals: on),
|
||||
'for (k in o) {}'
|
||||
|
||||
# Compilations that should fail.
|
||||
cantCompile = (code) ->
|
||||
throws -> CoffeeScript.compile code
|
||||
|
||||
cantCompile 'a = (break)'
|
||||
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
@@ -1,318 +0,0 @@
|
||||
# Basic array comprehensions.
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
|
||||
|
||||
# Basic object comprehensions.
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = (prop + '!' for prop of obj)
|
||||
odds = (prop + '!' for prop, value of obj when value & 1)
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
|
||||
|
||||
# Basic range comprehensions.
|
||||
nums = (i * 3 for i in [1..3])
|
||||
|
||||
negs = (x for x in [-20..-5*2])
|
||||
negs = negs[0..2]
|
||||
|
||||
result = nums.concat(negs).join(', ')
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
|
||||
|
||||
# With range comprehensions, you can loop in steps.
|
||||
results = (x for x in [0...15] by 5)
|
||||
ok results.join(' ') is '0 5 10'
|
||||
|
||||
results = (x for x in [0..100] by 10)
|
||||
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
|
||||
|
||||
|
||||
# And can loop downwards, with a negative step.
|
||||
results = (x for x in [5..1])
|
||||
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
|
||||
results = (x for x in [10..1])
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
|
||||
results = (x for x in [10...0] by -2)
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
|
||||
|
||||
# Range comprehension gymnastics.
|
||||
eq "#{i for i in [5..1]}", '5,4,3,2,1'
|
||||
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
|
||||
|
||||
a = 6
|
||||
b = 0
|
||||
c = -2
|
||||
|
||||
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
|
||||
eq "#{i for i in [a..b] by c}", '6,4,2,0'
|
||||
|
||||
|
||||
# Multiline array comprehension with filter.
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
eq evens + '', '4,6,8'
|
||||
|
||||
|
||||
# The in operator still works, standalone.
|
||||
ok 2 of evens
|
||||
|
||||
# all isn't reserved.
|
||||
all = 1
|
||||
|
||||
|
||||
# Ensure that the closure wrapper preserves local variables.
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
|
||||
|
||||
# Index values at the end of a loop.
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 4
|
||||
|
||||
|
||||
# Ensure that local variables are closed over for range comprehensions.
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
-> -i
|
||||
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
|
||||
|
||||
# Even when referenced in the filter.
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
# Even a convoluted one.
|
||||
funcs = []
|
||||
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
||||
# Naked ranges are expanded into arrays.
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Nested shared scopes.
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Scoped loop pattern matching.
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
|
||||
|
||||
# Nested comprehensions.
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
|
||||
singleLiner =
|
||||
(([x, y] for y in [3..5]) for x in [3..5])
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
ok 5 is multiLiner[2][2][1]
|
||||
ok 5 is singleLiner[2][2][1]
|
||||
|
||||
|
||||
# Comprehensions within parentheses.
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
|
||||
ok result.join(' ') is '6 4 2'
|
||||
|
||||
|
||||
# Closure-wrapped comprehensions that refer to the "arguments" object.
|
||||
expr = ->
|
||||
result = (item * item for item in arguments)
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
|
||||
|
||||
# Fast object comprehensions over all properties, including prototypal ones.
|
||||
class Cat
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
|
||||
whiskers = new Cat
|
||||
own = (value for own key, value of whiskers)
|
||||
all = (value for key, value of whiskers)
|
||||
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
|
||||
|
||||
# Optimized range comprehensions.
|
||||
exxes = ('x' for [0...10])
|
||||
ok exxes.join(' ') is 'x x x x x x x x x x'
|
||||
|
||||
|
||||
# Comprehensions safely redeclare parameters if they're not present in closest
|
||||
# scope.
|
||||
rule = (x) -> x
|
||||
|
||||
learn = ->
|
||||
rule for rule in [1, 2, 3]
|
||||
|
||||
ok learn().join(' ') is '1 2 3'
|
||||
|
||||
ok rule(101) is 101
|
||||
|
||||
f = -> [-> ok no, 'should cache source']
|
||||
ok yes for k of [f] = f()
|
||||
|
||||
|
||||
# Lenient on pure statements not trying to reach out of the closure
|
||||
val = for i in [1]
|
||||
for j in [] then break
|
||||
i
|
||||
ok val[0] is i
|
||||
|
||||
|
||||
# Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
# to have pure expressions in them.
|
||||
func = -> for i in [1]
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
|
||||
ok func()[0][0] is 1
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
|
||||
|
||||
# Issue #897: Ensure that plucked function variables aren't leaked.
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
||||
|
||||
# Issue #905. Soaks as the for loop subject.
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
|
||||
eq e, 3
|
||||
|
||||
|
||||
# Issue #948. Capturing loop variables.
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
|
||||
|
||||
# Cancel the comprehension if there's a jump inside the loop.
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
|
||||
eq result, 10
|
||||
|
||||
|
||||
# Comprehensions over break.
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
# Comprehensions over continue.
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
|
||||
# Comprehensions over function literals.
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
|
||||
eq a, 1
|
||||
|
||||
|
||||
# Comprehensions that mention arguments.
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
|
||||
eq args[0], 10
|
||||
@@ -1,165 +0,0 @@
|
||||
ok(if mySpecialVariable? then false else true)
|
||||
|
||||
mySpecialVariable = false
|
||||
|
||||
ok(if mySpecialVariable? then true else false)
|
||||
|
||||
|
||||
# Existential assignment.
|
||||
a = 5
|
||||
a = null
|
||||
a ?= 10
|
||||
b ?= 10
|
||||
|
||||
ok a is 10 and b is 10
|
||||
|
||||
|
||||
# The existential operator.
|
||||
z = null
|
||||
x = z ? "EX"
|
||||
ok z is null and x is "EX"
|
||||
|
||||
i = 9
|
||||
func = -> i += 1
|
||||
result = func() ? 101
|
||||
ok result is 10
|
||||
|
||||
# Only evaluate once.
|
||||
counter = 0
|
||||
getNextNode = ->
|
||||
throw "up" if counter
|
||||
counter++
|
||||
|
||||
ok(if getNextNode()? then true else false)
|
||||
|
||||
|
||||
# Existence chains, soaking up undefined properties:
|
||||
obj =
|
||||
prop: "hello"
|
||||
|
||||
eq obj?.prop, "hello"
|
||||
eq obj?['prop'], "hello"
|
||||
eq obj.prop?.length, 5
|
||||
eq obj?.prop?['length'], 5
|
||||
eq obj?.prop?.non?.existent?.property, undefined
|
||||
|
||||
|
||||
# Soaks and caches method calls as well.
|
||||
arr = ["--", "----"]
|
||||
|
||||
eq arr.pop()?.length, 4
|
||||
eq arr.pop()?.length, 2
|
||||
eq arr.pop()?.length, undefined
|
||||
eq arr.pop()?.length?.non?.existent()?.property, undefined
|
||||
|
||||
|
||||
# Soaks method calls safely.
|
||||
value = null
|
||||
eq value?.toString().toLowerCase(), undefined
|
||||
|
||||
value = 10
|
||||
eq value?.toString().toLowerCase(), '10'
|
||||
|
||||
eq 0.nothing?.property() or 101, 101
|
||||
|
||||
counter = 0
|
||||
func = ->
|
||||
counter += 1
|
||||
'prop'
|
||||
obj =
|
||||
prop: -> this
|
||||
value: 25
|
||||
|
||||
ok obj[func()]()[func()]()[func()]()?.value is 25
|
||||
ok counter is 3
|
||||
|
||||
|
||||
ident = (obj) -> obj
|
||||
eq ident(non?.existent().method()), undefined, 'soaks inner values'
|
||||
|
||||
|
||||
# Soaks constructor invocations.
|
||||
a = 0
|
||||
class Foo
|
||||
constructor: -> a += 1
|
||||
bar: "bat"
|
||||
|
||||
ok (new Foo())?.bar is 'bat'
|
||||
ok a is 1
|
||||
|
||||
|
||||
ok not value?.property?, 'safely checks existence on soaks'
|
||||
|
||||
|
||||
eq nothing?.value, undefined, 'safely calls values off of non-existent variables'
|
||||
eq !nothing?.value and 1, 1, 'corresponding operators work as expected'
|
||||
|
||||
|
||||
# Assign to the result of an exsitential operation with a minus.
|
||||
x = null ? - 1
|
||||
ok x is - 1
|
||||
|
||||
|
||||
# Things that compile to ternaries should force parentheses, like operators do.
|
||||
duration = if options?.animated then 150 else 0
|
||||
ok duration is 0
|
||||
|
||||
|
||||
# Function soaks.
|
||||
plus1 = (x) -> x + 1
|
||||
count = 0
|
||||
obj = {
|
||||
counter: -> count += 1; this
|
||||
returnThis: -> this
|
||||
}
|
||||
|
||||
eq plus1?(41), 42
|
||||
eq (plus1? 41), 42
|
||||
eq plus2?(41), undefined
|
||||
eq (plus2? 41), undefined
|
||||
eq obj.returnThis?(), obj
|
||||
eq obj.returnSelf?(), undefined
|
||||
eq obj.returnThis?().flag = on, on
|
||||
eq obj.returnSelf?().flag = on, undefined
|
||||
eq obj.counter().counter().returnThis?(), obj
|
||||
eq count, 2
|
||||
|
||||
maybe_close = (f, arg) -> if typeof f is 'function' then () -> f(arg) else -1
|
||||
|
||||
eq maybe_close(plus1, 41)?(), 42
|
||||
eq (maybe_close plus1, 41)?(), 42
|
||||
eq (maybe_close 'string', 41)?(), undefined
|
||||
|
||||
eq 2?(3), undefined
|
||||
eq new Number?(42) | 0, 42
|
||||
eq new Bumper?(42) | 0, 0
|
||||
|
||||
|
||||
#726
|
||||
eq calendar?[Date()], undefined
|
||||
|
||||
|
||||
#733
|
||||
a = b: {c: null}
|
||||
eq a.b?.c?(), undefined
|
||||
|
||||
a.b?.c or= (it) -> it
|
||||
eq a.b?.c?(1), 1
|
||||
eq a.b?.c?([2, 3]...), 2
|
||||
|
||||
|
||||
#756
|
||||
a = null
|
||||
ok isNaN a?.b.c + 1
|
||||
eq undefined, a?.b.c += 1
|
||||
eq undefined, ++a?.b.c
|
||||
eq undefined, delete a?.b.c
|
||||
|
||||
a = b: {c: 0}
|
||||
eq 1, a?.b.c + 1
|
||||
eq 1, a?.b.c += 1
|
||||
eq 2, ++a?.b.c
|
||||
eq yes, delete a?.b.c
|
||||
|
||||
|
||||
eq (1 or 0)?, true, 'postfix `?` should unwrap correctly'
|
||||
@@ -1,379 +0,0 @@
|
||||
x = 1
|
||||
y = {}
|
||||
y.x = -> 3
|
||||
|
||||
ok x is 1
|
||||
ok typeof(y.x) is 'function'
|
||||
ok y.x instanceof Function
|
||||
ok y.x() is 3
|
||||
|
||||
|
||||
# The empty function should not cause a syntax error.
|
||||
->
|
||||
() ->
|
||||
|
||||
|
||||
# Multiple nested function declarations mixed with implicit calls should not
|
||||
# cause a syntax error.
|
||||
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
|
||||
|
||||
|
||||
obj = {
|
||||
name: 'Fred'
|
||||
|
||||
bound: ->
|
||||
do (=> eq this, obj)
|
||||
|
||||
unbound: ->
|
||||
do (-> ok this isnt obj)
|
||||
|
||||
nested: ->
|
||||
(=>
|
||||
do (=>
|
||||
(=>
|
||||
eq this, obj
|
||||
)()
|
||||
)
|
||||
)()
|
||||
}
|
||||
|
||||
obj.unbound()
|
||||
obj.bound()
|
||||
obj.nested()
|
||||
|
||||
|
||||
# Python decorator style wrapper that memoizes any function
|
||||
memoize = (fn) ->
|
||||
cache = {}
|
||||
self = this
|
||||
(args...) ->
|
||||
key = args.toString()
|
||||
return cache[key] if cache[key]
|
||||
cache[key] = fn.apply(self, args)
|
||||
|
||||
Math = {
|
||||
Add: (a, b) -> a + b
|
||||
AnonymousAdd: (a, b) -> a + b
|
||||
FastAdd: memoize (a, b) -> a + b
|
||||
}
|
||||
|
||||
ok Math.Add(5, 5) is 10
|
||||
ok Math.AnonymousAdd(10, 10) is 20
|
||||
ok Math.FastAdd(20, 20) is 40
|
||||
|
||||
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
# Optional parens can be used in a nested fashion.
|
||||
call = (func) -> func()
|
||||
|
||||
result = call ->
|
||||
inner = call ->
|
||||
Math.Add(5, 5)
|
||||
|
||||
ok result is 10
|
||||
|
||||
|
||||
# More fun with optional parens.
|
||||
fn = (arg) -> arg
|
||||
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
|
||||
|
||||
# Multi-blocks with optional parens.
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
|
||||
# And even with strange things like this:
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
|
||||
ok result is 25
|
||||
|
||||
result = ("hello".slice) 3
|
||||
|
||||
ok result is 'lo'
|
||||
|
||||
|
||||
# And with multiple single-line functions on the same line.
|
||||
func = (x) -> (x) -> (x) -> x
|
||||
ok func(1)(2)(3) is 3
|
||||
|
||||
|
||||
# Ensure that functions with the same name don't clash with helper functions.
|
||||
del = -> 5
|
||||
ok del() is 5
|
||||
|
||||
# Ensure that functions can have a trailing comma in their argument list
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
ok mult(10, (i for i in [1..6])...) is 7200
|
||||
|
||||
|
||||
# Test for inline functions with parentheses and implicit calls.
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
|
||||
ok result is 9
|
||||
|
||||
|
||||
# Test for calls/parens/multiline-chains.
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
|
||||
ok result is 1
|
||||
|
||||
|
||||
# Test implicit calls in functions in parens:
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
|
||||
ok result is 10
|
||||
|
||||
|
||||
# More paren compilation tests:
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
|
||||
# Passing multiple functions without paren-wrapping is legal, and should compile.
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
|
||||
ok result is 20
|
||||
|
||||
|
||||
# Implicit call with a trailing if statement as a param.
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
|
||||
# Test more function passing:
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
ok result is 6
|
||||
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
|
||||
ok result is 3
|
||||
|
||||
|
||||
# This is a crazy one.
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
|
||||
ok result.one is 1
|
||||
|
||||
|
||||
# Assignment to a Object.prototype-named variable should not leak to outer scope.
|
||||
# FIXME: fails on IE
|
||||
(->
|
||||
constructor = 'word'
|
||||
)()
|
||||
|
||||
ok constructor isnt 'word'
|
||||
|
||||
|
||||
# Trying an implicit object call with a trailing function.
|
||||
a = null
|
||||
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
|
||||
|
||||
meth 'apple', b: 1, a: 13, ->
|
||||
'orange'
|
||||
|
||||
ok a is '13 apple orange'
|
||||
|
||||
|
||||
# Ensure that empty functions don't return mistaken values.
|
||||
obj =
|
||||
func: (@param, @rest...) ->
|
||||
|
||||
ok obj.func(101, 102, 103, 104) is undefined
|
||||
ok obj.param is 101
|
||||
ok obj.rest.join(' ') is '102 103 104'
|
||||
|
||||
|
||||
# `@` and `this` should both be able to invoke a method.
|
||||
func = (arg) -> ok arg is true
|
||||
func.withAt = -> @ true
|
||||
func.withThis = -> this true
|
||||
|
||||
func.withAt()
|
||||
func.withThis()
|
||||
|
||||
|
||||
# Ensure that constructors invoked with splats return a new object.
|
||||
args = [1, 2, 3]
|
||||
Type = (@args) ->
|
||||
type = new Type args
|
||||
|
||||
ok type and type instanceof Type
|
||||
ok type.args and type.args instanceof Array
|
||||
ok v is args[i] for v, i in type.args
|
||||
|
||||
Type1 = (@a, @b, @c) ->
|
||||
type1 = new Type1 args...
|
||||
|
||||
ok type1 instanceof Type1
|
||||
eq type1.constructor, Type1
|
||||
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
|
||||
|
||||
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
|
||||
|
||||
# Chained blocks, with proper indentation levels:
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
|
||||
eq counter.results.join(' '), '3 2 1'
|
||||
|
||||
|
||||
# Make incorrect indentation safe.
|
||||
func = ->
|
||||
obj = {
|
||||
key: 10
|
||||
}
|
||||
obj.key - 5
|
||||
|
||||
eq func(), 5
|
||||
|
||||
|
||||
# Ensure that chained calls with indented implicit object literals below are
|
||||
# alright.
|
||||
result = null
|
||||
obj =
|
||||
method: (val) -> this
|
||||
second: (hash) -> result = hash.three
|
||||
|
||||
|
||||
obj
|
||||
.method(
|
||||
101
|
||||
).second(
|
||||
one:
|
||||
two: 2
|
||||
three: 3
|
||||
)
|
||||
|
||||
eq result, 3
|
||||
|
||||
|
||||
# Test newline-supressed call chains with nested functions.
|
||||
obj =
|
||||
call: -> this
|
||||
func = ->
|
||||
obj
|
||||
.call ->
|
||||
one two
|
||||
.call ->
|
||||
three four
|
||||
101
|
||||
|
||||
eq func(), 101
|
||||
|
||||
|
||||
# `new` shouldn't add extra parens
|
||||
ok new Date().constructor is Date
|
||||
|
||||
|
||||
# `new` works against bare function
|
||||
eq Date, new ->
|
||||
eq this, new => this
|
||||
Date
|
||||
|
||||
|
||||
# Implicit objects with number arguments.
|
||||
func = (x, y) -> y
|
||||
obj =
|
||||
prop: func "a", 1
|
||||
|
||||
ok obj.prop is 1
|
||||
|
||||
|
||||
# Non-spaced unary and binary operators should cause a function call.
|
||||
func = (val) -> val + 1
|
||||
ok (func +5) is 6
|
||||
ok (func -5) is -4
|
||||
|
||||
|
||||
# Prefix unary assignment operators are allowed in parenless calls.
|
||||
val = 5
|
||||
ok (func --val) is 5
|
||||
|
||||
|
||||
eq ok, new ->
|
||||
ok
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
|
||||
#855: execution context for `func arr...` should be `null`
|
||||
(->
|
||||
global = @
|
||||
contextTest = -> ok global is @
|
||||
array = []
|
||||
contextTest array
|
||||
contextTest.apply null, array
|
||||
contextTest array...
|
||||
)()
|
||||
|
||||
|
||||
# #894: Splatting against constructor-chained functions.
|
||||
x = null
|
||||
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
|
||||
new Foo().bar([101]...)
|
||||
|
||||
eq x, 101
|
||||
|
||||
|
||||
test "#904: Destructuring function arguments with same-named variables in scope", ->
|
||||
a = b = nonce = {}
|
||||
fn = ([a,b]) -> {a:a,b:b}
|
||||
result = fn([c={},d={}])
|
||||
eq c, result.a
|
||||
eq d, result.b
|
||||
eq nonce, a
|
||||
eq nonce, b
|
||||
@@ -1,162 +0,0 @@
|
||||
# Simple variable swapping.
|
||||
a = -1
|
||||
b = -2
|
||||
|
||||
[a, b] = [b, a]
|
||||
|
||||
eq a, -2
|
||||
eq b, -1
|
||||
|
||||
func = ->
|
||||
[a, b] = [b, a]
|
||||
|
||||
eq func().join(' '), '-1 -2'
|
||||
eq a, -1
|
||||
eq b, -2
|
||||
|
||||
#713
|
||||
eq (onetwo = [1, 2]), [a, b] = [c, d] = onetwo
|
||||
ok a is c is 1 and b is d is 2
|
||||
|
||||
|
||||
# Array destructuring, including splats.
|
||||
[x,y...,z] = [1,2,3,4,5]
|
||||
|
||||
ok x is 1
|
||||
ok y.length is 3
|
||||
ok z is 5
|
||||
|
||||
[x, [y, mids..., last], z..., end] = [1, [10, 20, 30, 40], 2,3,4, 5]
|
||||
|
||||
ok x is 1
|
||||
ok y is 10
|
||||
ok mids.length is 2 and mids[1] is 30
|
||||
ok last is 40
|
||||
ok z.length is 3 and z[2] is 4
|
||||
ok end is 5
|
||||
|
||||
|
||||
# Object destructuring.
|
||||
obj = {x: 10, y: 20, z: 30}
|
||||
|
||||
{x: a, y: b, z: c} = obj
|
||||
|
||||
ok a is 10
|
||||
ok b is 20
|
||||
ok c is 30
|
||||
|
||||
person = {
|
||||
name: "Moe"
|
||||
family: {
|
||||
'elder-brother': {
|
||||
addresses: [
|
||||
"first"
|
||||
{
|
||||
street: "101 Deercreek Ln."
|
||||
city: "Moquasset NY, 10021"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{name: a, family: {'elder-brother': {addresses: [one, {city: b}]}}} = person
|
||||
|
||||
ok a is "Moe"
|
||||
ok b is "Moquasset NY, 10021"
|
||||
|
||||
test = {
|
||||
person: {
|
||||
address: [
|
||||
"------"
|
||||
"Street 101"
|
||||
"Apt 101"
|
||||
"City 101"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
{person: {address: [ignore, addr...]}} = test
|
||||
|
||||
ok addr.join(', ') is "Street 101, Apt 101, City 101"
|
||||
|
||||
|
||||
# Pattern matching against an expression.
|
||||
[a, b] = if true then [2, 1] else [1, 2]
|
||||
|
||||
ok a is 2
|
||||
ok b is 1
|
||||
|
||||
|
||||
# Pattern matching with object shorthand.
|
||||
|
||||
person = {
|
||||
name: "Bob"
|
||||
age: 26
|
||||
dogs: ["Prince", "Bowie"]
|
||||
}
|
||||
|
||||
{name, age, dogs: [first, second]} = person
|
||||
|
||||
ok name is "Bob"
|
||||
ok age is 26
|
||||
ok first is "Prince"
|
||||
ok second is "Bowie"
|
||||
|
||||
# Pattern matching within for..loops.
|
||||
|
||||
persons = {
|
||||
George: { name: "Bob" },
|
||||
Bob: { name: "Alice" }
|
||||
Christopher: { name: "Stan" }
|
||||
}
|
||||
|
||||
join1 = ("#{key}: #{name}" for key, { name } of persons)
|
||||
|
||||
eq join1.join(' / '), "George: Bob / Bob: Alice / Christopher: Stan"
|
||||
|
||||
persons = [
|
||||
{ name: "Bob", parent: { name: "George" } },
|
||||
{ name: "Alice", parent: { name: "Bob" } },
|
||||
{ name: "Stan", parent: { name: "Christopher" } }
|
||||
]
|
||||
|
||||
join2 = ("#{parent}: #{name}" for { name, parent: { name: parent } } in persons)
|
||||
|
||||
eq join1.join(' '), join2.join(' ')
|
||||
|
||||
persons = [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]]
|
||||
join3 = ("#{parent}: #{name}" for [name, [parent]] in persons)
|
||||
|
||||
eq join2.join(' '), join3.join(' ')
|
||||
|
||||
|
||||
# Pattern matching doesn't clash with implicit block objects.
|
||||
obj = a: 101
|
||||
func = -> true
|
||||
|
||||
if func func
|
||||
{a} = obj
|
||||
|
||||
ok a is 101
|
||||
|
||||
[x] = {0: y} = {'0': z} = [Math.random()]
|
||||
ok x is y is z, 'destructuring in multiple'
|
||||
|
||||
|
||||
# Destructuring into an object.
|
||||
obj =
|
||||
func: (list, object) ->
|
||||
[@one, @two] = list
|
||||
{@a, @b} = object
|
||||
{@a} = object
|
||||
null
|
||||
|
||||
{} = [] = ok yes, 'empty assignment is allowed'
|
||||
|
||||
obj.func [1, 2], a: 'a', b: 'b'
|
||||
|
||||
eq obj.one, 1
|
||||
eq obj.two, 2
|
||||
eq obj.a, 'a'
|
||||
eq obj.b, 'b'
|
||||
@@ -1,63 +0,0 @@
|
||||
# Expression conversion under explicit returns.
|
||||
first = ->
|
||||
return ('do' for x in [1,2,3])
|
||||
|
||||
second = ->
|
||||
return ['re' for x in [1,2,3]]
|
||||
|
||||
third = ->
|
||||
return ('mi' for x in [1,2,3])
|
||||
|
||||
ok first().join(' ') is 'do do do'
|
||||
ok second()[0].join(' ') is 're re re'
|
||||
ok third().join(' ') is 'mi mi mi'
|
||||
|
||||
|
||||
# Testing returns with multiple branches.
|
||||
func = ->
|
||||
if false
|
||||
for a in b
|
||||
return c if d
|
||||
else
|
||||
"word"
|
||||
|
||||
ok func() is 'word'
|
||||
|
||||
|
||||
# And with switches.
|
||||
func = ->
|
||||
switch 'a'
|
||||
when 'a' then 42
|
||||
else return 23
|
||||
|
||||
eq func(), 42
|
||||
|
||||
# Ensure that we don't wrap Nodes that are "pureStatement" in a closure.
|
||||
items = [1, 2, 3, "bacon", 4, 5]
|
||||
|
||||
findit = (items) ->
|
||||
for item in items
|
||||
return item if item is "bacon"
|
||||
|
||||
ok findit(items) is "bacon"
|
||||
|
||||
|
||||
# When a closure wrapper is generated for expression conversion, make sure
|
||||
# that references to "this" within the wrapper are safely converted as well.
|
||||
obj =
|
||||
num: 5
|
||||
func: ->
|
||||
this.result = if false
|
||||
10
|
||||
else
|
||||
"a"
|
||||
"b"
|
||||
this.num
|
||||
|
||||
eq obj.num, obj.func()
|
||||
eq obj.num, obj.result
|
||||
|
||||
|
||||
# Multiple semicolon-separated statements in parentheticals.
|
||||
eq 3, (1; 2; 3)
|
||||
eq 3, (-> return (1; 2; 3))()
|
||||
@@ -1,102 +0,0 @@
|
||||
# Splats
|
||||
# ------
|
||||
# note: splats in parameter lists of function definitions are tested in `arguments.coffee`
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
test "passing splats to functions", ->
|
||||
arrayEq [0..4], id id [0..4]...
|
||||
|
||||
fn = (a, b, c..., d) -> [a, b, c, d]
|
||||
[first, second, others, last] = fn [0..3]..., 4, [5...8]...
|
||||
eq 0, first
|
||||
eq 1, second
|
||||
arrayEq [2..6], others
|
||||
eq 7, last
|
||||
|
||||
|
||||
obj =
|
||||
name: 'moe'
|
||||
accessor: (args...) ->
|
||||
[@name].concat(args).join(' ')
|
||||
getNames: ->
|
||||
args = ['jane', 'ted']
|
||||
@accessor(args...)
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
|
||||
ok obj.getNames() is 'moe jane ted'
|
||||
ok obj[obj.index++].method([]...), 'should cache base value'
|
||||
|
||||
#crowd = [
|
||||
# contenders...
|
||||
# "Mighty Mouse"
|
||||
#]
|
||||
#
|
||||
#bests = [
|
||||
# "Mighty Mouse"
|
||||
# contenders.slice(0, 4)...
|
||||
#]
|
||||
#
|
||||
#ok crowd[0] is contenders[0]
|
||||
#ok crowd[10] is "Mighty Mouse"
|
||||
#
|
||||
#ok bests[1] is contenders[0]
|
||||
#ok bests[4] is contenders[3]
|
||||
|
||||
|
||||
# Finally, splats with super() within classes.
|
||||
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
|
||||
# Functions with splats being called with too few arguments.
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
|
||||
|
||||
# Array splat expansions with assigns.
|
||||
nums = [1, 2, 3]
|
||||
list = [a = 0, nums..., b = 4]
|
||||
ok a is 0
|
||||
ok b is 4
|
||||
ok list.join(' ') is '0 1 2 3 4'
|
||||
|
||||
|
||||
# Splat on a line by itself is invalid.
|
||||
failed = true
|
||||
try
|
||||
CoffeeScript.compile "x 'a'\n...\n"
|
||||
failed = false
|
||||
catch err
|
||||
ok failed
|
||||
|
||||
|
||||
# multiple generated references
|
||||
(->
|
||||
a = {b: []}
|
||||
a.b[true] = -> this == a.b
|
||||
c = 0
|
||||
d = []
|
||||
ok a.b[0<++c<2] d...
|
||||
)()
|
||||
@@ -1,103 +0,0 @@
|
||||
num = 10
|
||||
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
false
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
true
|
||||
when 1, 3, 5
|
||||
false
|
||||
|
||||
ok func(2)
|
||||
ok func(6)
|
||||
ok !func(3)
|
||||
eq func(8), undefined
|
||||
|
||||
|
||||
# Ensure that trailing switch elses don't get rewritten.
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to handle switches sans-condition.
|
||||
result = switch
|
||||
when null then 0
|
||||
when !1 then 1
|
||||
when '' not of {''} then 2
|
||||
when [] not instanceof Array then 3
|
||||
when true is false then 4
|
||||
when 'x' < 'y' > 'z' then 5
|
||||
when 'a' in ['b', 'c'] then 6
|
||||
when 'd' in (['e', 'f']) then 7
|
||||
else ok
|
||||
|
||||
eq result, ok
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch clause.
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
when 101 then '101!'
|
||||
else 'other'
|
||||
}
|
||||
|
||||
ok obj.func() is '101!'
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch cases.
|
||||
obj = {
|
||||
num: 101
|
||||
func: (yesOrNo) ->
|
||||
result = switch yesOrNo
|
||||
when yes then @num
|
||||
else 'other'
|
||||
result
|
||||
}
|
||||
|
||||
ok obj.func(yes) is 101
|
||||
|
||||
|
||||
# Switch with break as the return value of a loop.
|
||||
i = 10
|
||||
results = while i > 0
|
||||
i--
|
||||
switch i % 2
|
||||
when 1 then i
|
||||
when 0 then break
|
||||
|
||||
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
|
||||
@@ -1,71 +0,0 @@
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
|
||||
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
|
||||
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i += 1
|
||||
|
||||
ok i is 6
|
||||
|
||||
|
||||
# And, the loop form of while.
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
|
||||
|
||||
#759: `if` within `while` condition
|
||||
2 while if 1 then 0
|
||||
|
||||
|
||||
# While over break.
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
break
|
||||
|
||||
arrayEq result, []
|
||||
|
||||
|
||||
# While over continue.
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
continue
|
||||
|
||||
arrayEq result, []
|
||||
Reference in New Issue
Block a user