mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 01:07:55 -05:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c44d9ae923 | ||
|
|
a487259e8e | ||
|
|
37308e6760 | ||
|
|
4ce374be25 | ||
|
|
8b8e8a94ff | ||
|
|
578a46fbda | ||
|
|
6fb2088d5f | ||
|
|
49d9eb687d | ||
|
|
1f2f55bea3 | ||
|
|
f35ea486a7 | ||
|
|
a48cd7cb1d | ||
|
|
150a8a12a0 | ||
|
|
08cd112585 | ||
|
|
566087b518 | ||
|
|
f4a7cca075 | ||
|
|
d9d50fdf54 | ||
|
|
4c18ddf549 | ||
|
|
7c7b9a4be1 | ||
|
|
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 | ||
|
|
a330eda4b6 | ||
|
|
dcfdd144d8 | ||
|
|
0fd3ed593c | ||
|
|
83d424f2f4 | ||
|
|
c16c90c00a | ||
|
|
8087a5914c | ||
|
|
03eccd4958 | ||
|
|
6d3f272551 | ||
|
|
7ffb7c19fd | ||
|
|
f545f18c2d |
23
Cakefile
23
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
|
||||
)
|
||||
@@ -104,6 +104,7 @@ task 'build:browser', 'rebuild the merged script for inclusion in the browser',
|
||||
"""
|
||||
code = uglify.gen_code uglify.ast_squeeze uglify.ast_mangle ast, extra: yes
|
||||
fs.writeFileSync 'extras/coffee-script.js', header + '\n' + code
|
||||
console.log "built ... running browser tests:"
|
||||
invoke 'test:browser'
|
||||
|
||||
|
||||
@@ -150,6 +151,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 +169,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?
|
||||
@@ -208,11 +213,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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
###
|
||||
CoffeeScript Compiler v1.0.0
|
||||
CoffeeScript Compiler v1.0.1
|
||||
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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -12,12 +12,12 @@ execute all scripts present in <code>text/coffeescript</code> tags.</p>
|
||||
<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="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.0.1'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Words that cannot be used as identifiers in CoffeeScript code</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.RESERVED = </span><span class="nx">RESERVED</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Expose helpers for testing.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.helpers = </span><span class="nx">require</span> <span class="s1">'./helpers'</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
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,12 +28,12 @@ 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="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">filename</span> <span class="k">then</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">realpathSync</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="k">else</span> <span class="s1">'.'</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Clear the module cache.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root.moduleCache = </span><span class="p">{}</span> <span class="k">if</span> <span class="nx">root</span><span class="p">.</span><span class="nx">moduleCache</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Compile.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">root</span><span class="p">.</span><span class="nx">filename</span><span class="p">)</span> <span class="o">isnt</span> <span class="s1">'.coffee'</span> <span class="o">or</span> <span class="nx">require</span><span class="p">.</span><span class="nx">extensions</span>
|
||||
<span class="nx">root</span><span class="p">.</span><span class="nx">_compile</span> <span class="nx">compile</span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="nx">options</span><span class="p">),</span> <span class="nx">root</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<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">__filename = module.filename = </span><span class="nx">options</span><span class="p">.</span><span class="nx">filename</span>
|
||||
<span class="nv">__dirname = </span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">__filename</span>
|
||||
<span class="nb">eval</span> <span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">options</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>Instantiate a Lexer for our use here.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">lexer = </span><span class="k">new</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>The real Lexer produces a generic stream of tokens. This object provides a
|
||||
thin wrapper around it, compatible with the Jison API. We can then pass it
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -55,7 +55,7 @@ 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">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>
|
||||
@@ -74,8 +74,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 +101,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="s2">"concatenation"</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="s2">"concatenation"</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Load files that are to-be-required before compilation occurs.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">loadRequires = </span><span class="o">-></span>
|
||||
<span class="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 +123,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).toTimeString()} - 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 +136,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 +155,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>
|
||||
@@ -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>
|
||||
@@ -218,7 +220,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 +251,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 +315,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>
|
||||
@@ -354,10 +355,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>
|
||||
@@ -411,7 +413,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>
|
||||
|
||||
@@ -462,7 +464,7 @@ 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">ASSIGNED = </span><span class="sr">/^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/</span>
|
||||
|
||||
<span class="nv">LINE_CONTINUER = </span><span class="err">/// ^ \s* (?: , | \??\.(?!\.) | :: ) ///</span>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -170,10 +171,10 @@ declarations of all inner variables pushed up to the top.</p> </td>
|
||||
<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 +198,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>
|
||||
|
||||
@@ -332,7 +339,7 @@ method.</p> </td> <td class="code"> <div c
|
||||
<span class="nv">rite = </span><span class="k">new</span> <span class="nx">Value</span> <span class="nx">left</span>
|
||||
<span class="nv">rite = </span><span class="k">new</span> <span class="nx">Call</span> <span class="nx">rite</span><span class="p">,</span> <span class="nx">@args</span>
|
||||
<span class="nv">rite.isNew = </span><span class="nx">@isNew</span>
|
||||
<span class="nv">left = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="s2">"typeof #{ left.compile o } === \"function\""</span>
|
||||
<span class="nv">left = </span><span class="k">new</span> <span class="nx">Literal</span> <span class="s2">"typeof #{ left.compile o } == \"function\""</span>
|
||||
<span class="k">return</span> <span class="k">new</span> <span class="nx">If</span> <span class="nx">left</span><span class="p">,</span> <span class="k">new</span> <span class="nx">Value</span><span class="p">(</span><span class="nx">rite</span><span class="p">),</span> <span class="nx">soak</span><span class="o">:</span> <span class="kc">yes</span>
|
||||
<span class="nv">call = </span><span class="k">this</span>
|
||||
<span class="nv">list = </span><span class="p">[]</span>
|
||||
@@ -372,7 +379,7 @@ inner constructor in order to be able to pass the varargs.</p> </td>
|
||||
<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"> #{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>
|
||||
@@ -381,6 +388,7 @@ 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>
|
||||
@@ -468,7 +476,7 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
|
||||
<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">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-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
|
||||
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>
|
||||
|
||||
@@ -541,7 +549,7 @@ is the index of the beginning.</p> </td> <td class="code
|
||||
<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.
|
||||
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>
|
||||
|
||||
@@ -590,7 +598,7 @@ on the class.</p> </td> <td class="code">
|
||||
<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">@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>
|
||||
@@ -621,7 +629,7 @@ constructor, property assignments, and inheritance getting built out below.</p>
|
||||
<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
|
||||
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-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\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>
|
||||
|
||||
@@ -658,7 +666,10 @@ for details.</p> </td> <td class="code"> <
|
||||
<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="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">top</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="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>
|
||||
@@ -709,7 +720,7 @@ for details.</p> </td> <td class="code"> <
|
||||
<span class="nv">val = </span><span class="k">new</span> <span class="nx">Value</span> <span class="k">new</span> <span class="nx">Literal</span><span class="p">(</span><span class="nx">vvar</span><span class="p">),</span> <span class="p">[</span><span class="k">new</span> <span class="p">(</span><span class="k">if</span> <span class="nx">acc</span> <span class="k">then</span> <span class="nx">Access</span> <span class="k">else</span> <span class="nx">Index</span><span class="p">)</span> <span class="nx">idx</span><span class="p">]</span>
|
||||
<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="nv">code = </span><span class="p">(</span><span class="nx">compact</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
|
||||
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>
|
||||
@@ -735,7 +746,7 @@ 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>
|
||||
|
||||
@@ -876,7 +887,7 @@ 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>
|
||||
@@ -1085,7 +1096,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>
|
||||
@@ -1108,7 +1119,7 @@ you can map and filter in a single pass.</p> </td> <td c
|
||||
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 +1153,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>
|
||||
@@ -1203,9 +1214,8 @@ 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
|
||||
to the last line of each clause.</p>
|
||||
@@ -1226,7 +1236,7 @@ because ternaries are already proper expressions, and don't need conversion.</p>
|
||||
<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="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-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
|
||||
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>
|
||||
@@ -1238,17 +1248,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-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
|
||||
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>
|
||||
@@ -1277,7 +1287,7 @@ which is helpful for recording the result arrays from comprehensions.</p>
|
||||
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>
|
||||
@@ -1287,7 +1297,7 @@ then make sure that the closure wrapper preserves the original values.</p>
|
||||
<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>
|
||||
@@ -1326,7 +1336,7 @@ parens are necessary or superfluous.</p> </td> <td class
|
||||
<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">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>
|
||||
|
||||
@@ -5,19 +5,24 @@ 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></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">¶</a> </div> <p>Start by opening up <code>stdin</code> and <code>stdout</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">stdin = </span><span class="nx">process</span><span class="p">.</span><span class="nx">openStdin</span><span class="p">()</span>
|
||||
<span class="nv">stdout = </span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">¶</a> </div> <p>Log an error.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">error = </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="p">(</span><span class="nx">err</span><span class="p">.</span><span class="nx">stack</span> <span class="o">or</span> <span class="nx">err</span><span class="p">.</span><span class="nx">toString</span><span class="p">())</span> <span class="o">+</span> <span class="s1">'\n\n'</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Quick alias for quitting the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">helpers</span><span class="p">.</span><span class="nx">extend</span> <span class="nx">global</span><span class="p">,</span> <span class="nx">quit</span><span class="o">:</span> <span class="o">-></span> <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
|
||||
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="nv">val = </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nb">eval</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">bare</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">globals</span><span class="o">:</span> <span class="kc">on</span><span class="p">,</span> <span class="nx">filename</span><span class="o">:</span> <span class="s1">'repl'</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span> <span class="nx">val</span> <span class="o">+</span> <span class="s1">'\n'</span> <span class="k">if</span> <span class="nx">val</span> <span class="o">isnt</span> <span class="kc">undefined</span>
|
||||
<span class="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>
|
||||
<span class="nx">repl</span><span class="p">.</span><span class="nx">prompt</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>Make sure that uncaught exceptions don't kill the REPL.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">process</span><span class="p">.</span><span class="kc">on</span> <span class="s1">'uncaughtException'</span><span class="p">,</span> <span class="nx">error</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>Create the REPL by listening to <strong>stdin</strong>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="mi">3</span>
|
||||
<span class="nv">repl = </span><span class="nx">readline</span><span class="p">.</span><span class="nx">createInterface</span> <span class="nx">stdin</span>
|
||||
<span class="nx">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="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>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ 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>
|
||||
<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>
|
||||
|
||||
@@ -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 |
@@ -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.0.1">1.0.1</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -479,11 +479,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.
|
||||
@@ -1010,6 +1012,10 @@ Expressions
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>dhotson</b>'s <a href="https://github.com/dhotson/coffeescript-jedit">coffeescript-jedit</a>
|
||||
— which provides syntax highlighting support in jEdit.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
@@ -1035,11 +1041,6 @@ Expressions
|
||||
— 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
|
||||
@@ -1088,6 +1089,19 @@ Expressions
|
||||
<span id="change_log" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
<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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
CoffeeScript Compiler v1.0.0
|
||||
CoffeeScript Compiler v1.0.1
|
||||
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,2 +1,2 @@
|
||||
var zip, _ref;
|
||||
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
zip = typeof lottery.drawWinner == "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
|
||||
@@ -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
60
index.html
60
index.html
@@ -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.0.1">1.0.1</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -752,8 +752,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 +764,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,21 +913,21 @@ 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>
|
||||
@@ -1220,7 +1222,7 @@ footprints = typeof yeti != "undefined" && yeti !== null ? yeti : "bear";;alert(
|
||||
</p>
|
||||
<div class='code'><pre class="idle">zip <span class="Keyword">=</span> lottery.drawWinner<span class="Keyword">?</span>().address<span class="Keyword">?</span>.zipcode
|
||||
</pre><pre class="idle"><span class="Storage">var</span> zip, _ref;
|
||||
zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.drawWinner <span class="Keyword">===</span> <span class="String"><span class="String">"</span>function<span class="String">"</span></span> ? (_ref <span class="Keyword">=</span> lottery.drawWinner().address) <span class="Keyword">!</span><span class="Keyword">=</span> <span class="BuiltInConstant">null</span> ? _ref.zipcode : <span class="Storage">void</span> <span class="Number">0</span> : <span class="Storage">void</span> <span class="Number">0</span>;
|
||||
zip <span class="Keyword">=</span> <span class="Keyword">typeof</span> lottery.drawWinner <span class="Keyword">==</span> <span class="String"><span class="String">"</span>function<span class="String">"</span></span> ? (_ref <span class="Keyword">=</span> lottery.drawWinner().address) <span class="Keyword">!</span><span class="Keyword">=</span> <span class="BuiltInConstant">null</span> ? _ref.zipcode : <span class="Storage">void</span> <span class="Number">0</span> : <span class="Storage">void</span> <span class="Number">0</span>;
|
||||
</pre><script>window.example22 = "zip = lottery.drawWinner?().address?.zipcode\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example22);'>load</div><br class='clear' /></div>
|
||||
<p>
|
||||
Soaking up nulls is similar to Ruby's
|
||||
@@ -1710,16 +1712,16 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
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.0.1</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.0.1</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.0.1\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><br class='clear' /></div>
|
||||
|
||||
<p>
|
||||
<span id="regexes" class="bookmark"></span>
|
||||
@@ -1918,6 +1920,10 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>dhotson</b>'s <a href="https://github.com/dhotson/coffeescript-jedit">coffeescript-jedit</a>
|
||||
— which provides syntax highlighting support in jEdit.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
@@ -1943,11 +1949,6 @@ task(<span class="String"><span class="String">'</span>build:parser<span class="
|
||||
— 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
|
||||
@@ -1996,6 +1997,19 @@ 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.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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
return compile(content);
|
||||
});
|
||||
}
|
||||
exports.VERSION = '1.0.0';
|
||||
exports.VERSION = '1.0.1';
|
||||
exports.RESERVED = RESERVED;
|
||||
exports.helpers = require('./helpers');
|
||||
exports.compile = compile = function(code, options) {
|
||||
@@ -25,8 +25,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;
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
while (root.parent) {
|
||||
root = root.parent;
|
||||
}
|
||||
root.filename = fs.realpathSync(options.fileName || '.');
|
||||
root.filename = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
if (root.moduleCache) {
|
||||
root.moduleCache = {};
|
||||
}
|
||||
@@ -59,7 +59,7 @@
|
||||
};
|
||||
exports.eval = function(code, options) {
|
||||
var __dirname, __filename;
|
||||
__filename = options.fileName;
|
||||
__filename = module.filename = options.filename;
|
||||
__dirname = path.dirname(__filename);
|
||||
return eval(compile(code, options));
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
@@ -32,6 +31,9 @@
|
||||
if (opts.version) {
|
||||
return version();
|
||||
}
|
||||
if (opts.require) {
|
||||
loadRequires();
|
||||
}
|
||||
if (opts.interactive) {
|
||||
return require('./repl');
|
||||
}
|
||||
@@ -58,7 +60,7 @@
|
||||
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) {
|
||||
@@ -95,16 +97,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,
|
||||
@@ -159,6 +154,17 @@
|
||||
code = contents.join('\n');
|
||||
return compileScript("concatenation", code, "concatenation");
|
||||
};
|
||||
loadRequires = function() {
|
||||
var realFilename, req, _i, _len, _ref;
|
||||
realFilename = module.filename;
|
||||
module.filename = '.';
|
||||
_ref = opts.require;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
req = _ref[_i];
|
||||
require(req);
|
||||
}
|
||||
return module.filename = realFilename;
|
||||
};
|
||||
watch = function(source, base) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
@@ -190,7 +196,7 @@
|
||||
if (err) {
|
||||
return printLine(err.message);
|
||||
} else if (opts.compile && opts.watch) {
|
||||
return util.log("compiled " + source);
|
||||
return console.log("" + ((new Date).toTimeString()) + " - compiled " + source);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -237,9 +243,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 +261,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: [
|
||||
@@ -352,9 +357,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 +368,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 +486,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
|
||||
});
|
||||
|
||||
19
lib/lexer.js
19
lib/lexer.js
@@ -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;
|
||||
@@ -477,7 +480,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, _ref, _ref2, _ref3;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -506,11 +509,13 @@
|
||||
if (((_ref = nested[0]) != null ? _ref[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;
|
||||
@@ -598,7 +603,7 @@
|
||||
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})/;
|
||||
@@ -613,7 +618,7 @@
|
||||
HEREGEX_OMIT = /\s+(?:#.*)?/g;
|
||||
MULTILINER = /\n/g;
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/;
|
||||
LINE_CONTINUER = /^\s*(?:,|\??\.(?!\.)|::)/;
|
||||
TRAILING_SPACES = /\s+$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
|
||||
122
lib/nodes.js
122
lib/nodes.js
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var Access, Arr, Assign, Base, Call, Class, Closure, Code, Comment, Existence, Expressions, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, NEGATE, NO, Obj, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, starts, unfoldSoak, utility, _ref;
|
||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, NEGATE, NO, Obj, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, starts, unfoldSoak, utility, _ref;
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
|
||||
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
|
||||
function ctor() { this.constructor = child; }
|
||||
@@ -166,34 +166,34 @@
|
||||
Base.prototype.assigns = NO;
|
||||
return Base;
|
||||
})();
|
||||
exports.Expressions = Expressions = (function() {
|
||||
__extends(Expressions, Base);
|
||||
function Expressions(nodes) {
|
||||
exports.Block = Block = (function() {
|
||||
__extends(Block, Base);
|
||||
function Block(nodes) {
|
||||
this.expressions = compact(flatten(nodes || []));
|
||||
}
|
||||
Expressions.prototype.children = ['expressions'];
|
||||
Expressions.prototype.push = function(node) {
|
||||
Block.prototype.children = ['expressions'];
|
||||
Block.prototype.push = function(node) {
|
||||
this.expressions.push(node);
|
||||
return this;
|
||||
};
|
||||
Expressions.prototype.pop = function() {
|
||||
Block.prototype.pop = function() {
|
||||
return this.expressions.pop();
|
||||
};
|
||||
Expressions.prototype.unshift = function(node) {
|
||||
Block.prototype.unshift = function(node) {
|
||||
this.expressions.unshift(node);
|
||||
return this;
|
||||
};
|
||||
Expressions.prototype.unwrap = function() {
|
||||
Block.prototype.unwrap = function() {
|
||||
if (this.expressions.length === 1) {
|
||||
return this.expressions[0];
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
Expressions.prototype.isEmpty = function() {
|
||||
Block.prototype.isEmpty = function() {
|
||||
return !this.expressions.length;
|
||||
};
|
||||
Expressions.prototype.isStatement = function(o) {
|
||||
Block.prototype.isStatement = function(o) {
|
||||
var exp, _i, _len, _ref;
|
||||
_ref = this.expressions;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
@@ -204,7 +204,7 @@
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Expressions.prototype.jumps = function(o) {
|
||||
Block.prototype.jumps = function(o) {
|
||||
var exp, _i, _len, _ref;
|
||||
_ref = this.expressions;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
@@ -214,29 +214,32 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
Expressions.prototype.makeReturn = function() {
|
||||
Block.prototype.makeReturn = function() {
|
||||
var expr, len;
|
||||
len = this.expressions.length;
|
||||
while (len--) {
|
||||
expr = this.expressions[len];
|
||||
if (!(expr instanceof Comment)) {
|
||||
this.expressions[len] = expr.makeReturn();
|
||||
if (expr instanceof Return && !expr.expression) {
|
||||
this.expressions.splice(len, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
Expressions.prototype.compile = function(o, level) {
|
||||
Block.prototype.compile = function(o, level) {
|
||||
if (o == null) {
|
||||
o = {};
|
||||
}
|
||||
if (o.scope) {
|
||||
return Expressions.__super__.compile.call(this, o, level);
|
||||
return Block.__super__.compile.call(this, o, level);
|
||||
} else {
|
||||
return this.compileRoot(o);
|
||||
}
|
||||
};
|
||||
Expressions.prototype.compileNode = function(o) {
|
||||
Block.prototype.compileNode = function(o) {
|
||||
var code, codes, node, top, _i, _len, _ref;
|
||||
this.tab = o.indent;
|
||||
top = o.level === LEVEL_TOP;
|
||||
@@ -264,7 +267,7 @@
|
||||
return code;
|
||||
}
|
||||
};
|
||||
Expressions.prototype.compileRoot = function(o) {
|
||||
Block.prototype.compileRoot = function(o) {
|
||||
var code;
|
||||
o.indent = this.tab = o.bare ? '' : TAB;
|
||||
o.scope = new Scope(null, this, null);
|
||||
@@ -277,7 +280,7 @@
|
||||
return "(function() {\n" + code + "\n}).call(this);\n";
|
||||
}
|
||||
};
|
||||
Expressions.prototype.compileWithDeclarations = function(o) {
|
||||
Block.prototype.compileWithDeclarations = function(o) {
|
||||
var code, exp, i, post, rest, scope, _len, _ref;
|
||||
code = post = '';
|
||||
_ref = this.expressions;
|
||||
@@ -308,13 +311,13 @@
|
||||
}
|
||||
return code + post;
|
||||
};
|
||||
Expressions.wrap = function(nodes) {
|
||||
if (nodes.length === 1 && nodes[0] instanceof Expressions) {
|
||||
Block.wrap = function(nodes) {
|
||||
if (nodes.length === 1 && nodes[0] instanceof Block) {
|
||||
return nodes[0];
|
||||
}
|
||||
return new Expressions(nodes);
|
||||
return new Block(nodes);
|
||||
};
|
||||
return Expressions;
|
||||
return Block;
|
||||
})();
|
||||
exports.Literal = Literal = (function() {
|
||||
__extends(Literal, Base);
|
||||
@@ -351,7 +354,7 @@
|
||||
};
|
||||
Literal.prototype.compileNode = function(o) {
|
||||
var code;
|
||||
code = this.value.reserved ? "\"" + this.value + "\"" : this.value;
|
||||
code = this.isUndefined ? o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0' : this.value.reserved ? "\"" + this.value + "\"" : this.value;
|
||||
if (this.isStatement()) {
|
||||
return "" + this.tab + code + ";";
|
||||
} else {
|
||||
@@ -365,8 +368,10 @@
|
||||
})();
|
||||
exports.Return = Return = (function() {
|
||||
__extends(Return, Base);
|
||||
function Return(expression) {
|
||||
this.expression = expression;
|
||||
function Return(expr) {
|
||||
if (expr && !expr.unwrap().isUndefined) {
|
||||
this.expression = expr;
|
||||
}
|
||||
}
|
||||
Return.prototype.children = ['expression'];
|
||||
Return.prototype.isStatement = YES;
|
||||
@@ -591,7 +596,7 @@
|
||||
}
|
||||
rite = new Call(rite, this.args);
|
||||
rite.isNew = this.isNew;
|
||||
left = new Literal("typeof " + (left.compile(o)) + " === \"function\"");
|
||||
left = new Literal("typeof " + (left.compile(o)) + " == \"function\"");
|
||||
return new If(left, new Value(rite), {
|
||||
soak: true
|
||||
});
|
||||
@@ -660,7 +665,7 @@
|
||||
}
|
||||
if (this.isNew) {
|
||||
idt = this.tab + TAB;
|
||||
return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return typeof result === \"object\" ? result : child;\n" + this.tab + "})(" + (this.variable.compile(o, LEVEL_LIST)) + ", " + splatArgs + ", function() {})";
|
||||
return "(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return typeof result == \"object\" ? result : child;\n" + this.tab + "})(" + (this.variable.compile(o, LEVEL_LIST)) + ", " + splatArgs + ", function() {})";
|
||||
}
|
||||
base = new Value(this.variable);
|
||||
if ((name = base.properties.pop()) && base.isComplex()) {
|
||||
@@ -668,6 +673,9 @@
|
||||
fun = "(" + ref + " = " + (base.compile(o, LEVEL_LIST)) + ")" + (name.compile(o));
|
||||
} else {
|
||||
fun = base.compile(o, LEVEL_ACCESS);
|
||||
if (SIMPLENUM.test(fun)) {
|
||||
fun = "(" + fun + ")";
|
||||
}
|
||||
if (name) {
|
||||
ref = fun;
|
||||
fun += name.compile(o);
|
||||
@@ -785,7 +793,7 @@
|
||||
_results = [];
|
||||
for (var _i = _ref = +this.fromNum, _ref2 = +this.toNum; _ref <= _ref2 ? _i <= _ref2 : _i >= _ref2; _ref <= _ref2 ? _i += 1 : _i -= 1){ _results.push(_i); }
|
||||
return _results;
|
||||
}).call(this);
|
||||
}).apply(this, arguments);
|
||||
if (this.exclusive) {
|
||||
range.pop();
|
||||
}
|
||||
@@ -804,7 +812,7 @@
|
||||
body = "var " + vars + "; " + clause + " " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + clause + " " + i + " += 1 : " + i + " -= 1";
|
||||
}
|
||||
post = "{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + o.indent;
|
||||
return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).call(this)";
|
||||
return "(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).apply(this, arguments)";
|
||||
};
|
||||
return Range;
|
||||
})();
|
||||
@@ -936,7 +944,7 @@
|
||||
function Class(variable, parent, body) {
|
||||
this.variable = variable;
|
||||
this.parent = parent;
|
||||
this.body = body != null ? body : new Expressions;
|
||||
this.body = body != null ? body : new Block;
|
||||
this.boundFuncs = [];
|
||||
this.body.classBody = true;
|
||||
}
|
||||
@@ -1018,7 +1026,7 @@
|
||||
if (child instanceof Class) {
|
||||
return false;
|
||||
}
|
||||
if (child instanceof Expressions) {
|
||||
if (child instanceof Block) {
|
||||
_ref = exps = child.expressions;
|
||||
for (i = 0, _len = _ref.length; i < _len; i++) {
|
||||
node = _ref[i];
|
||||
@@ -1071,7 +1079,7 @@
|
||||
this.context = context;
|
||||
this.param = options && options.param;
|
||||
}
|
||||
Assign.prototype.METHOD_DEF = /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w]*)$/;
|
||||
Assign.prototype.METHOD_DEF = /^(?:(\S+)\.prototype\.|\S+?)?\b([$A-Za-z_][$\w\x7f-\uffff]*)$/;
|
||||
Assign.prototype.children = ['variable', 'value'];
|
||||
Assign.prototype.assigns = function(name) {
|
||||
return this[this.context === 'object' ? 'value' : 'variable'].assigns(name);
|
||||
@@ -1126,7 +1134,15 @@
|
||||
value = this.value;
|
||||
objects = this.variable.base.objects;
|
||||
if (!(olen = objects.length)) {
|
||||
return value.compile(o);
|
||||
if (top) {
|
||||
return false;
|
||||
}
|
||||
code = value.compile(o);
|
||||
if (o.level >= LEVEL_OP) {
|
||||
return "(" + code + ")";
|
||||
} else {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
isObject = this.variable.isObject();
|
||||
if (top && olen === 1 && !((obj = objects[0]) instanceof Splat)) {
|
||||
@@ -1195,7 +1211,7 @@
|
||||
if (!top) {
|
||||
assigns.push(vvar);
|
||||
}
|
||||
code = assigns.join(', ');
|
||||
code = (compact(assigns)).join(', ');
|
||||
if (o.level < LEVEL_LIST) {
|
||||
return code;
|
||||
} else {
|
||||
@@ -1241,7 +1257,7 @@
|
||||
__extends(Code, Base);
|
||||
function Code(params, body, tag) {
|
||||
this.params = params || [];
|
||||
this.body = body || new Expressions;
|
||||
this.body = body || new Block;
|
||||
this.bound = tag === 'boundfunc';
|
||||
if (this.bound) {
|
||||
this.context = 'this';
|
||||
@@ -1486,7 +1502,7 @@
|
||||
}
|
||||
}
|
||||
if (this.guard) {
|
||||
body = Expressions.wrap([new If(this.guard, body)]);
|
||||
body = Block.wrap([new If(this.guard, body)]);
|
||||
}
|
||||
body = "\n" + (body.compile(o, LEVEL_TOP)) + "\n" + this.tab;
|
||||
}
|
||||
@@ -1788,7 +1804,7 @@
|
||||
function For(body, source) {
|
||||
var _ref;
|
||||
this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index;
|
||||
this.body = Expressions.wrap([body]);
|
||||
this.body = Block.wrap([body]);
|
||||
this.own = !!source.own;
|
||||
this.object = !!source.object;
|
||||
if (this.object) {
|
||||
@@ -1816,7 +1832,7 @@
|
||||
};
|
||||
For.prototype.compileNode = function(o) {
|
||||
var body, defPart, forPart, guardPart, idt1, index, ivar, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, svar, varPart, _ref;
|
||||
body = Expressions.wrap([this.body]);
|
||||
body = Block.wrap([this.body]);
|
||||
lastJumps = (_ref = last(body.expressions)) != null ? _ref.jumps() : void 0;
|
||||
if (lastJumps && lastJumps instanceof Return) {
|
||||
this.returns = false;
|
||||
@@ -1872,7 +1888,7 @@
|
||||
body = Push.wrap(rvar, body);
|
||||
}
|
||||
if (this.guard) {
|
||||
body = Expressions.wrap([new If(this.guard, body)]);
|
||||
body = Block.wrap([new If(this.guard, body)]);
|
||||
}
|
||||
if (this.pattern) {
|
||||
body.expressions.unshift(new Assign(this.name, new Literal("" + svar + "[" + ivar + "]")));
|
||||
@@ -1961,7 +1977,7 @@
|
||||
return this;
|
||||
};
|
||||
Switch.prototype.compileNode = function(o) {
|
||||
var block, body, code, cond, conditions, expr, i, idt1, idt2, jumper, _i, _len, _len2, _ref, _ref2, _ref3, _ref4;
|
||||
var block, body, code, cond, conditions, expr, i, idt1, idt2, _i, _len, _len2, _ref, _ref2, _ref3, _ref4;
|
||||
idt1 = o.indent + TAB;
|
||||
idt2 = o.indent = idt1 + TAB;
|
||||
code = this.tab + ("switch (" + (((_ref = this.subject) != null ? _ref.compile(o, LEVEL_PAREN) : void 0) || false) + ") {\n");
|
||||
@@ -1983,10 +1999,10 @@
|
||||
break;
|
||||
}
|
||||
expr = this.lastNonComment(block.expressions);
|
||||
jumper = expr.jumps();
|
||||
if (!expr || !jumper || (jumper instanceof Literal && jumper.value === 'debugger')) {
|
||||
code += idt2 + 'break;\n';
|
||||
if (expr instanceof Return || (expr instanceof Literal && expr.jumps() && expr.value !== 'debugger')) {
|
||||
continue;
|
||||
}
|
||||
code += idt2 + 'break;\n';
|
||||
}
|
||||
if (this.otherwise && this.otherwise.expressions.length) {
|
||||
code += idt1 + ("default:\n" + (this.otherwise.compile(o, LEVEL_TOP)) + "\n");
|
||||
@@ -2021,7 +2037,7 @@
|
||||
this.elseBodyNode().addElse(elseBody);
|
||||
} else {
|
||||
this.isChain = elseBody instanceof If;
|
||||
this.elseBody = this.ensureExpressions(elseBody);
|
||||
this.elseBody = this.ensureBlock(elseBody);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
@@ -2041,15 +2057,15 @@
|
||||
}
|
||||
};
|
||||
If.prototype.makeReturn = function() {
|
||||
this.body && (this.body = new Expressions([this.body.makeReturn()]));
|
||||
this.elseBody && (this.elseBody = new Expressions([this.elseBody.makeReturn()]));
|
||||
this.body && (this.body = new Block([this.body.makeReturn()]));
|
||||
this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn()]));
|
||||
return this;
|
||||
};
|
||||
If.prototype.ensureExpressions = function(node) {
|
||||
if (node instanceof Expressions) {
|
||||
If.prototype.ensureBlock = function(node) {
|
||||
if (node instanceof Block) {
|
||||
return node;
|
||||
} else {
|
||||
return new Expressions([node]);
|
||||
return new Block([node]);
|
||||
}
|
||||
};
|
||||
If.prototype.compileStatement = function(o) {
|
||||
@@ -2057,7 +2073,7 @@
|
||||
child = del(o, 'chainChild');
|
||||
cond = this.condition.compile(o, LEVEL_PAREN);
|
||||
o.indent += TAB;
|
||||
body = this.ensureExpressions(this.body).compile(o);
|
||||
body = this.ensureBlock(this.body).compile(o);
|
||||
if (body) {
|
||||
body = "\n" + body + "\n" + this.tab;
|
||||
}
|
||||
@@ -2101,7 +2117,7 @@
|
||||
if (expressions.jumps()) {
|
||||
return expressions;
|
||||
}
|
||||
func = new Code([], Expressions.wrap([expressions]));
|
||||
func = new Code([], Block.wrap([expressions]));
|
||||
args = [];
|
||||
if ((mentionsArgs = expressions.contains(this.literalArgs)) || (expressions.contains(this.literalThis))) {
|
||||
meth = new Literal(mentionsArgs ? 'apply' : 'call');
|
||||
@@ -2114,7 +2130,7 @@
|
||||
func.noReturn = noReturn;
|
||||
call = new Call(func, args);
|
||||
if (statement) {
|
||||
return Expressions.wrap([call]);
|
||||
return Block.wrap([call]);
|
||||
} else {
|
||||
return call;
|
||||
}
|
||||
@@ -2150,7 +2166,7 @@
|
||||
LEVEL_ACCESS = 6;
|
||||
TAB = ' ';
|
||||
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
||||
IDENTIFIER = /^[$A-Za-z_][$\w]*$/;
|
||||
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/;
|
||||
SIMPLENUM = /^[+-]?\d+$/;
|
||||
IS_STRING = /^['"]/;
|
||||
utility = function(name) {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
};
|
||||
OptionParser.prototype.help = function() {
|
||||
var letPart, lines, rule, spaces, _i, _len, _ref;
|
||||
lines = ['Available options:'];
|
||||
lines = [];
|
||||
if (this.banner) {
|
||||
lines.unshift("" + this.banner + "\n");
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
25
lib/repl.js
25
lib/repl.js
@@ -1,11 +1,12 @@
|
||||
(function() {
|
||||
var CoffeeScript, error, helpers, readline, repl, run, stdio;
|
||||
var CoffeeScript, error, helpers, readline, repl, run, stdin, stdout;
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers');
|
||||
readline = require('readline');
|
||||
stdio = process.openStdin();
|
||||
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() {
|
||||
@@ -18,10 +19,10 @@
|
||||
val = CoffeeScript.eval(buffer.toString(), {
|
||||
bare: true,
|
||||
globals: true,
|
||||
fileName: 'repl'
|
||||
filename: 'repl'
|
||||
});
|
||||
if (val !== void 0) {
|
||||
console.log(val);
|
||||
process.stdout.write(val + '\n');
|
||||
}
|
||||
} catch (err) {
|
||||
error(err);
|
||||
@@ -29,13 +30,17 @@
|
||||
return repl.prompt();
|
||||
};
|
||||
process.on('uncaughtException', error);
|
||||
repl = readline.createInterface(stdio);
|
||||
if (readline.createInterface.length < 3) {
|
||||
repl = readline.createInterface(stdin);
|
||||
stdin.on('data', function(buffer) {
|
||||
return repl.write(buffer);
|
||||
});
|
||||
} else {
|
||||
repl = readline.createInterface(stdin, stdout);
|
||||
}
|
||||
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();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language", "coffeescript", "compiler"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/jashkenas/coffee-script/raw/master/LICENSE"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -20,7 +20,7 @@ else if require.registerExtension
|
||||
require.registerExtension '.coffee', (content) -> compile content
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION = '1.0.0'
|
||||
exports.VERSION = '1.0.1'
|
||||
|
||||
# Words that cannot be used as identifiers in CoffeeScript code
|
||||
exports.RESERVED = RESERVED
|
||||
@@ -34,7 +34,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.
|
||||
@@ -58,7 +58,7 @@ exports.run = (code, options) ->
|
||||
while root.parent
|
||||
root = root.parent
|
||||
# Set the filename.
|
||||
root.filename = fs.realpathSync options.fileName or '.'
|
||||
root.filename = if options.filename then fs.realpathSync(options.filename) else '.'
|
||||
# Clear the module cache.
|
||||
root.moduleCache = {} if root.moduleCache
|
||||
# Compile.
|
||||
@@ -70,7 +70,7 @@ 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
|
||||
__filename = module.filename = options.filename
|
||||
__dirname = path.dirname __filename
|
||||
eval compile code, options
|
||||
|
||||
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -76,7 +76,7 @@ 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) ->
|
||||
if stats.isDirectory()
|
||||
fs.readdir source, (err, files) ->
|
||||
@@ -98,8 +98,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
|
||||
@@ -135,6 +133,13 @@ compileJoin = ->
|
||||
code = contents.join '\n'
|
||||
compileScript "concatenation", code, "concatenation"
|
||||
|
||||
# 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,
|
||||
# such as `--lint` or `--print`.
|
||||
@@ -157,8 +162,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).toTimeString()} - compiled #{source}"
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p #{dir}", compile
|
||||
|
||||
@@ -191,7 +198,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 +215,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
|
||||
@@ -348,7 +350,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 +403,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 +485,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.
|
||||
@@ -438,10 +439,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
|
||||
@@ -534,7 +536,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?
|
||||
///
|
||||
|
||||
@@ -591,7 +593,7 @@ MULTILINER = /\n/g
|
||||
|
||||
HEREDOC_INDENT = /\n+([^\n\S]*)/g
|
||||
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
||||
ASSIGNED = /^\s*@?([$A-Za-z_][$\w\x7f-\uffff]*|['"].*['"])[^\n\S]*?[:=][^:=>]/
|
||||
|
||||
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?!\.) | :: ) ///
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -256,11 +257,11 @@ exports.Expressions = class Expressions extends Base
|
||||
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 +290,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 +306,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']
|
||||
|
||||
@@ -471,7 +478,7 @@ exports.Call = class Call extends Base
|
||||
rite = new Value left
|
||||
rite = new Call rite, @args
|
||||
rite.isNew = @isNew
|
||||
left = new Literal "typeof #{ left.compile o } === \"function\""
|
||||
left = new Literal "typeof #{ left.compile o } == \"function\""
|
||||
return new If left, new Value(rite), soak: yes
|
||||
call = this
|
||||
list = []
|
||||
@@ -520,7 +527,7 @@ exports.Call = class Call extends Base
|
||||
(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;
|
||||
#{idt}return typeof result == "object" ? result : child;
|
||||
#{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function() {})
|
||||
"""
|
||||
base = new Value @variable
|
||||
@@ -529,6 +536,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
|
||||
@@ -651,7 +659,7 @@ exports.Range = class Range extends Base
|
||||
clause = "#{@fromVar} <= #{@toVar} ?"
|
||||
body = "var #{vars}; #{clause} #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{clause} #{i} += 1 : #{i} -= 1"
|
||||
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
|
||||
|
||||
@@ -747,7 +755,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 +819,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
|
||||
@@ -856,7 +864,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']
|
||||
|
||||
@@ -899,7 +907,10 @@ 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
|
||||
return false if top
|
||||
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`
|
||||
@@ -958,7 +969,7 @@ exports.Assign = class Assign extends Base
|
||||
val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
|
||||
assigns.push new Assign(obj, val, null, param: @param).compile o, LEVEL_TOP
|
||||
assigns.push vvar unless top
|
||||
code = assigns.join ', '
|
||||
code = (compact assigns).join ', '
|
||||
if o.level < LEVEL_LIST then code else "(#{code})"
|
||||
|
||||
# When compiling a conditional assignment, take care to ensure that the
|
||||
@@ -995,7 +1006,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
|
||||
|
||||
@@ -1163,7 +1174,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
|
||||
@@ -1425,7 +1436,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 +1462,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 +1496,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 +1562,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 +1592,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 +1607,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 +1620,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,7 +1667,7 @@ 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)
|
||||
@@ -1667,7 +1677,7 @@ Closure =
|
||||
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
|
||||
@@ -1735,7 +1745,7 @@ TAB = ' '
|
||||
# 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
|
||||
|
||||
@@ -9,12 +9,13 @@ CoffeeScript = require './coffee-script'
|
||||
helpers = require './helpers'
|
||||
readline = require 'readline'
|
||||
|
||||
# Start by opening up **stdio**.
|
||||
stdio = process.openStdin()
|
||||
# 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)
|
||||
@@ -24,8 +25,8 @@ helpers.extend global, quit: -> process.exit(0)
|
||||
# of exiting.
|
||||
run = (buffer) ->
|
||||
try
|
||||
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
|
||||
console.log val if val isnt undefined
|
||||
val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, filename: 'repl'
|
||||
process.stdout.write val + '\n' if val isnt undefined
|
||||
catch err
|
||||
error err
|
||||
repl.prompt()
|
||||
@@ -34,9 +35,13 @@ run = (buffer) ->
|
||||
process.on 'uncaughtException', error
|
||||
|
||||
# Create the REPL by listening to **stdin**.
|
||||
repl = readline.createInterface stdio
|
||||
if readline.createInterface.length < 3
|
||||
repl = readline.createInterface stdin
|
||||
stdin.on 'data', (buffer) -> repl.write buffer
|
||||
else
|
||||
repl = readline.createInterface stdin, stdout
|
||||
|
||||
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()
|
||||
|
||||
@@ -14,7 +14,7 @@ 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) ->
|
||||
|
||||
37
test/array_literals.coffee
Normal file
37
test/array_literals.coffee
Normal file
@@ -0,0 +1,37 @@
|
||||
# Array Literals
|
||||
# --------------
|
||||
|
||||
# * Array Literals
|
||||
# * Splats in Array Literals
|
||||
|
||||
# TODO: refactor array literal tests
|
||||
# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()
|
||||
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
ok a.length is 2
|
||||
|
||||
# Funky indentation within non-comma-seperated arrays.
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
|
||||
|
||||
#### Splats in Array Literals
|
||||
|
||||
test "array splat expansions with assignments", ->
|
||||
nums = [1, 2, 3]
|
||||
list = [a = 0, nums..., b = 4]
|
||||
eq 0, a
|
||||
eq 4, b
|
||||
arrayEq [0,1,2,3,4], list
|
||||
@@ -1,6 +1,14 @@
|
||||
# Assignment
|
||||
# ----------
|
||||
|
||||
# TODO: organize assignment file
|
||||
|
||||
# * Assignment
|
||||
# * Compound Assignment
|
||||
# * Destructuring Assignment
|
||||
# * Context Property (@) Assignment
|
||||
# * Existential Assignment (?=)
|
||||
|
||||
test "context property assignment (using @)", ->
|
||||
nonce = {}
|
||||
addMethod = ->
|
||||
@@ -19,45 +27,81 @@ test "compound assignments should not declare", ->
|
||||
eq Math, (-> Math or= 0)()
|
||||
|
||||
|
||||
#### Statements as Expressions
|
||||
|
||||
test "assign the result of a try/catch block", ->
|
||||
# multiline
|
||||
result = try
|
||||
nonexistent * missing
|
||||
catch error
|
||||
true
|
||||
eq true, result
|
||||
|
||||
# single line
|
||||
result = try nonexistent * missing catch error then true
|
||||
eq true, result
|
||||
|
||||
test "conditionals", ->
|
||||
# assign inside the condition of a conditional statement
|
||||
nonce = {}
|
||||
if a = nonce then 1
|
||||
eq nonce, a
|
||||
1 if b = nonce
|
||||
eq nonce, b
|
||||
|
||||
# assign the result of a conditional statement
|
||||
c = if true then nonce
|
||||
eq nonce, c
|
||||
|
||||
test "assign inside the condition of a `while` loop", ->
|
||||
nonce = {}
|
||||
count = 1
|
||||
a = nonce while count--
|
||||
eq nonce, a
|
||||
count = 1
|
||||
while count--
|
||||
b = nonce
|
||||
eq nonce, b
|
||||
|
||||
|
||||
#### Compound Assignment
|
||||
|
||||
test "boolean operators", ->
|
||||
nonce = {}
|
||||
|
||||
a = 0
|
||||
a or= nonce
|
||||
eq nonce, a
|
||||
|
||||
b = 1
|
||||
b or= nonce
|
||||
eq 1, b
|
||||
|
||||
c = 0
|
||||
c and= nonce
|
||||
eq 0, c
|
||||
|
||||
d = 1
|
||||
d and= nonce
|
||||
eq nonce, d
|
||||
|
||||
# ensure that RHS is treated as a group
|
||||
e = f = false
|
||||
e and= f or true
|
||||
eq false, e
|
||||
|
||||
test "compound assignment as a sub expression", ->
|
||||
[a, b, c] = [1, 2, 3]
|
||||
eq 6, (a + b += c)
|
||||
eq 1, a
|
||||
eq 5, b
|
||||
eq 3, c
|
||||
|
||||
# *note: this test could still use refactoring*
|
||||
test "compound assignment should be careful about caching variables", ->
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq 1, list[1]
|
||||
eq 1, count
|
||||
|
||||
list[++count] ?= 2
|
||||
eq 2, list[2]
|
||||
eq 2, count
|
||||
|
||||
list[count++] and= 6
|
||||
eq 6, list[2]
|
||||
eq 3, count
|
||||
|
||||
base = ->
|
||||
++count
|
||||
base
|
||||
|
||||
base().four or= 4
|
||||
eq 4, base.four
|
||||
eq 4, count
|
||||
|
||||
base().five ?= 5
|
||||
eq 5, base.five
|
||||
eq 5, count
|
||||
|
||||
test "compound assignment with implicit objects", ->
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
eq 1, obj.one
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
eq undefined, obj.one
|
||||
eq 2, obj.two
|
||||
|
||||
test "compound assignment (math operators)", ->
|
||||
num = 10
|
||||
num -= 5
|
||||
@@ -94,5 +138,131 @@ test "more compound 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
|
||||
|
||||
# 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/boolean_literals.coffee
Normal file
21
test/boolean_literals.coffee
Normal file
@@ -0,0 +1,21 @@
|
||||
# Boolean Literals
|
||||
# ----------------
|
||||
|
||||
# TODO: add method invocation tests: true.toString() is "true"
|
||||
|
||||
#764: Boolean should be indexable
|
||||
toString = Boolean::toString
|
||||
|
||||
eq toString, true['toString']
|
||||
eq toString, false['toString']
|
||||
eq toString, yes['toString']
|
||||
eq toString, no['toString']
|
||||
eq toString, on['toString']
|
||||
eq toString, off['toString']
|
||||
|
||||
eq toString, true.toString
|
||||
eq toString, false.toString
|
||||
eq toString, yes.toString
|
||||
eq toString, no.toString
|
||||
eq toString, on.toString
|
||||
eq toString, off.toString
|
||||
@@ -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()
|
||||
4
test/cake.coffee
Normal file
4
test/cake.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
# Cake
|
||||
# ----
|
||||
|
||||
# TODO: add tests
|
||||
@@ -1,3 +1,12 @@
|
||||
# Classes
|
||||
# -------
|
||||
|
||||
# * Class Definition
|
||||
# * Class Instantiation
|
||||
# * Inheritance and Super
|
||||
|
||||
# TODO: refactor class tests
|
||||
|
||||
# Test classes with a four-level inheritance chain.
|
||||
class Base
|
||||
func: (string) ->
|
||||
@@ -253,7 +262,7 @@ ok c instanceof Function
|
||||
# Classes with value'd constructors.
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
counter += 1
|
||||
counter++
|
||||
inner = counter
|
||||
->
|
||||
@value = inner
|
||||
@@ -370,3 +379,35 @@ makeClass = ->
|
||||
makeClass.call A
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
|
||||
|
||||
|
||||
|
||||
# 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...
|
||||
|
||||
# `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
|
||||
4
test/command.coffee
Normal file
4
test/command.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
# Command
|
||||
# -------
|
||||
|
||||
# TODO: add tests
|
||||
@@ -1,6 +1,9 @@
|
||||
# Comments
|
||||
# --------
|
||||
|
||||
# * Single-Line Comments
|
||||
# * Block Comments
|
||||
|
||||
# Note: awkward spacing seen in some tests is likely intentional.
|
||||
|
||||
test "comments in objects", ->
|
||||
|
||||
57
test/compilation.coffee
Normal file
57
test/compilation.coffee
Normal file
@@ -0,0 +1,57 @@
|
||||
# Compilation
|
||||
# -----------
|
||||
|
||||
# TODO: refactor compilation tests
|
||||
|
||||
# helper to assert that a string should fail compilation
|
||||
cantCompile = (code) ->
|
||||
throws -> CoffeeScript.compile code
|
||||
|
||||
|
||||
# Ensure that carriage returns don't break compilation on Windows.
|
||||
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
|
||||
|
||||
# `globals: on` removes `var`s
|
||||
eq -1, CoffeeScript.compile('x = y', bare: on, globals: on).indexOf 'var'
|
||||
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
|
||||
|
||||
# multiple generated references
|
||||
(->
|
||||
a = {b: []}
|
||||
a.b[true] = -> this == a.b
|
||||
c = 0
|
||||
d = []
|
||||
ok a.b[0<++c<2] d...
|
||||
)()
|
||||
|
||||
# Splat on a line by itself is invalid.
|
||||
cantCompile "x 'a'\n...\n"
|
||||
|
||||
#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'
|
||||
|
||||
# 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
|
||||
'''
|
||||
@@ -1,3 +1,14 @@
|
||||
# Comprehensions
|
||||
# --------------
|
||||
|
||||
# * Array Comprehensions
|
||||
# * Range Comprehensions
|
||||
# * Object Comprehensions
|
||||
# * Implicit Destructuring Assignment
|
||||
# * Comprehensions with Nonstandard Step
|
||||
|
||||
# TODO: refactor comprehension tests
|
||||
|
||||
# Basic array comprehensions.
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
@@ -314,5 +325,46 @@ 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()
|
||||
|
||||
|
||||
#### Implicit Destructuring Assignment
|
||||
|
||||
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
|
||||
@@ -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
|
||||
418
test/control_flow.coffee
Normal file
418
test/control_flow.coffee
Normal file
@@ -0,0 +1,418 @@
|
||||
# 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
|
||||
|
||||
|
||||
#### For / While / Until / Loop
|
||||
|
||||
# TODO: refactor while tests
|
||||
|
||||
# While
|
||||
|
||||
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'
|
||||
|
||||
#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
|
||||
|
||||
# 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, []
|
||||
|
||||
# Until
|
||||
|
||||
# TODO: refactor until tests
|
||||
# TODO: add until tests
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i++
|
||||
ok i is 6
|
||||
|
||||
# Loop
|
||||
|
||||
# TODO: refactor loop tests
|
||||
# TODO: add loop tests
|
||||
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
|
||||
# TODO: refactor for tests
|
||||
# TODO: add for tests
|
||||
|
||||
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()
|
||||
|
||||
|
||||
#### Switch
|
||||
|
||||
# TODO: refactor switch tests
|
||||
|
||||
num = 10
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
false
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
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, '
|
||||
|
||||
|
||||
# Issue #997. Switch doesn't fallthrough.
|
||||
val = 1
|
||||
switch true
|
||||
when true
|
||||
if false
|
||||
return 5
|
||||
else
|
||||
val = 2
|
||||
|
||||
eq val, 1
|
||||
@@ -1,5 +1,5 @@
|
||||
# Exceptions
|
||||
# ----------
|
||||
# Exception Handling
|
||||
# ------------------
|
||||
|
||||
# shared nonce
|
||||
nonce = {}
|
||||
|
||||
106
test/formatting.coffee
Normal file
106
test/formatting.coffee
Normal file
@@ -0,0 +1,106 @@
|
||||
# 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
|
||||
|
||||
# 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
|
||||
366
test/function_invocation.coffee
Normal file
366
test/function_invocation.coffee
Normal file
@@ -0,0 +1,366 @@
|
||||
# Function Invocation
|
||||
# -------------------
|
||||
|
||||
# * Function Invocation
|
||||
# * Splats in Function Invocations
|
||||
# * Implicit Returns
|
||||
# * Explicit Returns
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(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)"
|
||||
|
||||
func = ->
|
||||
return if true
|
||||
eq undefined, func()
|
||||
|
||||
result = ("hello".slice) 3
|
||||
ok result is 'lo'
|
||||
|
||||
# And even with strange things like this:
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
ok result is 25
|
||||
|
||||
# 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)()()
|
||||
|
||||
# Multi-blocks with optional parens.
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
# method calls
|
||||
fnId = (fn) -> -> fn.apply this, arguments
|
||||
math = {
|
||||
add: (a, b) -> a + b
|
||||
anonymousAdd: (a, b) -> a + b
|
||||
fastAdd: fnId (a, b) -> a + b
|
||||
}
|
||||
ok math.add(5, 5) is 10
|
||||
ok math.anonymousAdd(10, 10) is 20
|
||||
ok math.fastAdd(20, 20) is 40
|
||||
|
||||
# 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()
|
||||
|
||||
# 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'
|
||||
|
||||
# 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
|
||||
|
||||
# Chained blocks, with proper indentation levels:
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
arrayEq [3,2,1], counter.results
|
||||
|
||||
# This is a crazy one.
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
ok result.one is 1
|
||||
|
||||
# More paren compilation tests:
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
test "#855: execution context for `func arr...` should be `null`", ->
|
||||
contextTest = -> eq @, 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
|
||||
|
||||
obj =
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
ok obj[obj.index++].method([]...), 'should cache base value'
|
||||
|
||||
|
||||
#### Splats in Function Invocations
|
||||
|
||||
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
|
||||
|
||||
#894: Splatting against constructor-chained functions.
|
||||
x = null
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
new Foo().bar([101]...)
|
||||
eq x, 101
|
||||
|
||||
# Functions with splats being called with too few arguments.
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
|
||||
# splats with super() within classes.
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
test "#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]...
|
||||
|
||||
|
||||
#### 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
|
||||
|
||||
|
||||
#### Explicit Returns
|
||||
|
||||
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
|
||||
@@ -1,45 +1,67 @@
|
||||
# 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
|
||||
|
||||
|
||||
#### Bound Function Definition
|
||||
|
||||
obj =
|
||||
bound: ->
|
||||
(=> this)()
|
||||
unbound: ->
|
||||
(-> this)()
|
||||
nested: ->
|
||||
(=>
|
||||
(=>
|
||||
(=> this)()
|
||||
)()
|
||||
)()
|
||||
eq obj, obj.bound()
|
||||
ok obj isnt obj.unbound()
|
||||
eq obj, obj.nested()
|
||||
|
||||
|
||||
#### Parameter List Features
|
||||
@@ -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
|
||||
"\\\`"
|
||||
`
|
||||
39
test/number_literals.coffee
Normal file
39
test/number_literals.coffee
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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
|
||||
@@ -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,69 @@ 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
|
||||
|
||||
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]
|
||||
@@ -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,81 +49,69 @@ 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
|
||||
test "binary existential operator with negative number", ->
|
||||
a = null ? - 1
|
||||
eq -1, a
|
||||
|
||||
# *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
|
||||
#### Existential Operator (Unary)
|
||||
|
||||
list[++count] ?= 2
|
||||
eq 2, list[2]
|
||||
eq 2, count
|
||||
test "postfix existential operator", ->
|
||||
ok (if nonexistent? then false else true)
|
||||
defined = true
|
||||
ok defined?
|
||||
defined = false
|
||||
ok defined?
|
||||
|
||||
list[count++] and= 6
|
||||
eq 6, list[2]
|
||||
eq 3, count
|
||||
test "postfix existential operator only evaluates its operand once", ->
|
||||
semaphore = 0
|
||||
fn = ->
|
||||
ok false if semaphore
|
||||
++semaphore
|
||||
ok(if fn()? then true else false)
|
||||
|
||||
base = ->
|
||||
++count
|
||||
base
|
||||
test "negated postfix existential operator", ->
|
||||
ok !nothing?.value
|
||||
|
||||
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 "postfix existential operator on expressions", ->
|
||||
eq true, (1 or 0)?, true
|
||||
|
||||
|
||||
#### `is`,`isnt`,`==`,`!=`
|
||||
@@ -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`
|
||||
@@ -190,7 +185,7 @@ test "#768: `in` should preserve evaluation order", ->
|
||||
eq 3, share
|
||||
|
||||
|
||||
#### 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/range_literals.coffee
Normal file
85
test/range_literals.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/)
|
||||
@@ -24,9 +28,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']
|
||||
|
||||
@@ -42,15 +43,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 "#{ }", ''
|
||||
@@ -92,30 +92,35 @@
|
||||
say msg, yay
|
||||
|
||||
run name for name in names = [
|
||||
'arguments'
|
||||
'array_literals'
|
||||
'assignment'
|
||||
'break'
|
||||
'boolean_literals'
|
||||
'cake'
|
||||
'classes'
|
||||
'command'
|
||||
'comments'
|
||||
'compilation'
|
||||
'comprehensions'
|
||||
'control_flow'
|
||||
'exception_handling'
|
||||
'formatting'
|
||||
'function_invocation'
|
||||
'function_literals'
|
||||
'helpers'
|
||||
'importing'
|
||||
'interpolation'
|
||||
'javascript_literals'
|
||||
'number_literals'
|
||||
'object_literals'
|
||||
'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'
|
||||
'range_literals'
|
||||
'regular_expression_literals'
|
||||
'repl'
|
||||
'scope'
|
||||
'slicing_and_splicing'
|
||||
'soaks'
|
||||
'string_literals'
|
||||
]
|
||||
</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,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,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