mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-13 16:57:54 -05:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
485346f0e5 | ||
|
|
a8d4c3a567 | ||
|
|
dfb3a13246 | ||
|
|
f84eb9ed47 | ||
|
|
8136c5f3de | ||
|
|
45669e08c6 | ||
|
|
a5db69e1af | ||
|
|
8aceef20e1 | ||
|
|
7e3c71ed19 | ||
|
|
9d09bee6fb | ||
|
|
cd6ee373ff | ||
|
|
4d0acc9b02 | ||
|
|
393fbf1b66 | ||
|
|
3324b03a5d | ||
|
|
eb91f9922d | ||
|
|
9a7420ccd0 | ||
|
|
be72120311 | ||
|
|
c452c3a101 | ||
|
|
0b3bb66708 | ||
|
|
d0d0fa4d10 | ||
|
|
6222ed622f | ||
|
|
1a03e98057 | ||
|
|
46cea93fc3 | ||
|
|
d64b8fd9d8 | ||
|
|
c051daee2f | ||
|
|
ae70d10996 | ||
|
|
52e6399e02 | ||
|
|
ac05f62f2f | ||
|
|
4d935efd09 | ||
|
|
fa8cc7976a | ||
|
|
ee4e34bf6d | ||
|
|
c8e0f8b149 | ||
|
|
b47188763c | ||
|
|
5e5c9df5c4 | ||
|
|
1a97f599dd | ||
|
|
3b264c9572 | ||
|
|
144c096ae6 | ||
|
|
adbcd320b2 | ||
|
|
17ba44056e | ||
|
|
502abade7c | ||
|
|
b746c9018e | ||
|
|
92af641827 | ||
|
|
b5606a247d | ||
|
|
d62baf5a5d | ||
|
|
e17567866a | ||
|
|
76f9596f22 | ||
|
|
2a3a713811 | ||
|
|
175ebb3cd8 | ||
|
|
95367a4a63 | ||
|
|
8950c3c4c8 | ||
|
|
2d1abd099d | ||
|
|
a894db35fd | ||
|
|
328a14014c | ||
|
|
315a2c63fa | ||
|
|
ca4ea7649d | ||
|
|
08c877ec7b | ||
|
|
212ad45be4 | ||
|
|
e9b37c7578 | ||
|
|
1438cecfad | ||
|
|
49824ce1a6 | ||
|
|
bc0ec9dc07 | ||
|
|
5957b9f155 | ||
|
|
72e6e828f1 | ||
|
|
01b4393fa7 | ||
|
|
bf2a5386f9 | ||
|
|
fb4d4a609b | ||
|
|
1cddb2aa88 | ||
|
|
aac9679282 | ||
|
|
90472685e8 | ||
|
|
7bb764b3e4 | ||
|
|
1aed9c545f | ||
|
|
c937e49689 | ||
|
|
0d860516ac | ||
|
|
4ced1d65b4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
raw
|
||||
presentation
|
||||
test.coffee
|
||||
parser.output
|
||||
|
||||
16
Cakefile
16
Cakefile
@@ -1,13 +1,13 @@
|
||||
fs: require 'fs'
|
||||
helpers: require('./lib/helpers').helpers
|
||||
CoffeeScript: require './lib/coffee-script'
|
||||
{spawn: spawn, exec: exec}: require('child_process')
|
||||
fs: require 'fs'
|
||||
{helpers}: require('./lib/helpers')
|
||||
CoffeeScript: require './lib/coffee-script'
|
||||
{spawn, exec}: require('child_process')
|
||||
|
||||
# Run a CoffeeScript through our node/coffee interpreter.
|
||||
run: (args) ->
|
||||
proc: spawn 'bin/coffee', args
|
||||
proc.addListener 'error', (err) -> if err then puts err
|
||||
|
||||
proc.stderr.addListener 'data', (buffer) -> puts buffer.toString()
|
||||
proc.addListener 'exit', (status) -> process.exit(1) if status != 0
|
||||
|
||||
option '-p', '--prefix [DIR]', 'set the installation prefix for `cake install`'
|
||||
|
||||
@@ -20,6 +20,8 @@ task 'install', 'install CoffeeScript into /usr/local (or --prefix)', (options)
|
||||
"cp -rf bin lib LICENSE README package.json src vendor $lib"
|
||||
"ln -sf $lib/bin/coffee $base/bin/coffee"
|
||||
"ln -sf $lib/bin/cake $base/bin/cake"
|
||||
"mkdir -p ~/.node_libraries"
|
||||
"ln -sf $lib/lib ~/.node_libraries/coffee-script"
|
||||
].join(' && '), (err, stdout, stderr) ->
|
||||
if err then print stderr
|
||||
)
|
||||
@@ -93,7 +95,7 @@ task 'test', 'run the CoffeeScript language test suite', ->
|
||||
source: path.join 'test', file
|
||||
fs.readFile source, (err, code) ->
|
||||
try
|
||||
CoffeeScript.run code, {source: source}
|
||||
CoffeeScript.run code.toString(), {source: source}
|
||||
catch err
|
||||
failed_tests += 1
|
||||
puts "${red}failed:${reset} $source"
|
||||
|
||||
2
README
2
README
@@ -50,7 +50,7 @@
|
||||
Mathieu D'Amours (matehat)
|
||||
Chris Hoffman (cehoffman)
|
||||
Jason Huggins (hugs)
|
||||
Tim Jones (Tesco)
|
||||
Timothy Jones (Tesco)
|
||||
Chris Lloyd (chrislloyd)
|
||||
Matt Lyon (mattly)
|
||||
Jeff Olson (olsonjeffery)
|
||||
|
||||
@@ -10,4 +10,4 @@ futurists: {
|
||||
}
|
||||
}
|
||||
|
||||
{poet: {name: poet, address: [street, city]}}: futurists
|
||||
{poet: {name, address: [street, city]}}: futurists
|
||||
@@ -1,7 +1,7 @@
|
||||
# Econ 101
|
||||
if this.studying_economics
|
||||
while supply > demand then buy()
|
||||
while supply < demand then sell()
|
||||
buy() while supply > demand
|
||||
sell() until supply > demand
|
||||
|
||||
# Nursery Rhyme
|
||||
num: 6
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>cake.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> cake.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p><code>cake</code> is a simplified version of <a href="http://www.gnu.org/software/make/">Make</a>
|
||||
<!DOCTYPE html> <html> <head> <title>cake.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> cake.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p><code>cake</code> is a simplified version of <a href="http://www.gnu.org/software/make/">Make</a>
|
||||
(<a href="http://rake.rubyforge.org/">Rake</a>, <a href="http://github.com/280north/jake">Jake</a>)
|
||||
for CoffeeScript. You define tasks with names and descriptions in a Cakefile,
|
||||
and can call them from the command line, or invoke them from other tasks.</p>
|
||||
@@ -27,7 +27,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="mi">2</span><span class="p">...</span><span class="nx">process</span><span class="p">.</span><span class="nx">argv</span><span class="p">.</span><span class="nx">length</span><span class="p">]</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="p">{</span><span class="nv">source: </span><span class="s1">'Cakefile'</span><span class="p">}</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="p">{</span><span class="nv">source: </span><span class="s1">'Cakefile'</span><span class="p">}</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">print_tasks</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>
|
||||
@@ -39,7 +39,7 @@ If no tasks are passed, print the help screen.</p> </td>
|
||||
<span class="nv">desc: </span> <span class="k">if</span> <span class="nx">task</span><span class="p">.</span><span class="nx">description</span> <span class="k">then</span> <span class="s2">"# $task.description"</span> <span class="k">else</span> <span class="s1">''</span>
|
||||
<span class="nx">puts</span> <span class="s2">"cake $name$spaces $desc"</span>
|
||||
<span class="nx">puts</span> <span class="nx">oparse</span><span class="p">.</span><span class="nx">help</span><span class="p">()</span> <span class="k">if</span> <span class="nx">switches</span><span class="p">.</span><span class="nx">length</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Print an error and exit when attempting to all an undefined task.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">no_such_task: </span><span class="p">(</span><span class="nx">task</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">puts</span> <span class="s2">"No such task: \"$task\"\n"</span>
|
||||
<span class="nx">puts</span> <span class="s2">"No such task: \"$task\""</span>
|
||||
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span> <span class="mi">1</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>coffee-script.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> coffee-script.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
<!DOCTYPE html> <html> <head> <title>coffee-script.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> coffee-script.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>CoffeeScript can be used both on the server, as a command-line compiler based
|
||||
on Node.js/V8, or to run CoffeeScripts directly in the browser. This module
|
||||
contains the main entry functions for tokenzing, parsing, and compiling source
|
||||
CoffeeScript into JavaScript.</p>
|
||||
@@ -16,7 +16,7 @@ execute all scripts present in <code>text/coffeescript</code> tags.</p>
|
||||
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span><span class="p">.</span><span class="nv">CoffeeScript: </span><span class="p">{}</span>
|
||||
<span class="nv">Lexer: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Lexer</span>
|
||||
<span class="nv">parser: </span> <span class="k">this</span><span class="p">.</span><span class="nx">parser</span>
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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">'0.6.1'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</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><span class="p">()</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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">'0.6.2'</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</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><span class="p">()</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</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="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">options: </span><span class="o">or</span> <span class="p">{}</span>
|
||||
<span class="k">try</span>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!DOCTYPE html> <html> <head> <title>command.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> command.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
|
||||
<!DOCTYPE html> <html> <head> <title>command.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> command.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <code>coffee</code> utility. Handles command-line compilation of CoffeeScript
|
||||
into various forms: saved into <code>.js</code> files or printed to stdout, piped to
|
||||
<a href="http://javascriptlint.com/">JSLint</a> or recompiled every time the source is
|
||||
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="octowrap"> <a class="octothorpe" 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">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>
|
||||
<span class="p">{</span><span class="nv">spawn: </span><span class="nx">spawn</span><span class="p">,</span> <span class="nv">exec: </span><span class="nx">exec</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'child_process'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER: </span><span class="s1">'''</span>
|
||||
interactive REPL.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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">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>
|
||||
<span class="p">{</span><span class="nx">spawn</span><span class="p">,</span> <span class="nx">exec</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'child_process'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>The help banner that is printed when <code>coffee</code> is called without arguments.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BANNER: </span><span class="s1">'''</span>
|
||||
<span class="s1"> coffee compiles CoffeeScript source files into JavaScript.</span>
|
||||
|
||||
<span class="s1"> Usage:</span>
|
||||
@@ -43,19 +43,25 @@ Many flags cause us to divert before compiling anything. Flags passed after
|
||||
<span class="nv">flags: </span><span class="nx">sources</span><span class="p">[(</span><span class="nx">separator</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)...</span><span class="nx">sources</span><span class="p">.</span><span class="nx">length</span><span class="p">]</span>
|
||||
<span class="nv">sources: </span><span class="nx">sources</span><span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">separator</span><span class="p">]</span>
|
||||
<span class="nv">process.ARGV: process.argv: </span><span class="nx">flags</span>
|
||||
<span class="nx">watch_scripts</span><span class="p">()</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">compile_scripts</span><span class="p">()</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Asynchronously read in each CoffeeScript in a list of source files and
|
||||
compile them.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_scripts: </span><span class="o">-></span>
|
||||
<span class="nv">compile: </span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="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="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="nx">compile_script</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="nv">run: </span><span class="o">-></span> <span class="nx">compile</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="k">return</span> <span class="nx">run</span><span class="p">()</span> <span class="nx">unless</span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span> <span class="o">and</span> <span class="nx">options</span><span class="p">.</span><span class="nx">compile</span>
|
||||
<span class="nx">exec</span> <span class="s2">"mkdir -p $options.output"</span><span class="p">,</span> <span class="nx">run</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
requested options. Both compile_scripts and watch_scripts share this method
|
||||
in common. 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">compile_script: </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="o">-></span>
|
||||
compile them. If a directory is passed, recursively compile all source
|
||||
files in it and all subdirectories.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_scripts: </span><span class="o">-></span>
|
||||
<span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span>
|
||||
<span class="nv">base: </span><span class="nx">source</span>
|
||||
<span class="nv">compile: </span><span class="p">(</span><span class="nx">source</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="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>
|
||||
<span class="k">for</span> <span class="nx">file</span> <span class="k">in</span> <span class="nx">files</span>
|
||||
<span class="nx">compile</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">file</span><span class="p">)</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">path</span><span class="p">.</span><span class="nx">extname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'.coffee'</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span> <span class="nx">source</span><span class="p">,</span> <span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">code</span><span class="p">)</span> <span class="o">-></span> <span class="nx">compile_script</span><span class="p">(</span><span class="nx">source</span><span class="p">,</span> <span class="nx">code</span><span class="p">.</span><span class="nx">toString</span><span class="p">(),</span> <span class="nx">base</span><span class="p">)</span>
|
||||
<span class="nx">watch</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">base</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">watch</span>
|
||||
<span class="nx">compile</span> <span class="nx">source</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Compile a single source script, containing the given code, according to the
|
||||
requested options. If evaluating the script directly sets <code>__filename</code>,
|
||||
<code>__dirname</code> and <code>module.filename</code> to be correct relative to the script's path.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">compile_script: </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">base</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">o: </span><span class="nx">options</span>
|
||||
<span class="nv">code_opts: </span><span class="nx">compile_options</span> <span class="nx">source</span>
|
||||
<span class="k">try</span>
|
||||
@@ -65,7 +71,7 @@ and <code>module.filename</code> to be correct relative to the script's path.</p
|
||||
<span class="k">else</span>
|
||||
<span class="nv">js: </span><span class="nx">CoffeeScript</span><span class="p">.</span><span class="nx">compile</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">code_opts</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">print</span> <span class="k">then</span> <span class="nx">print</span> <span class="nx">js</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">write_js</span> <span class="nx">source</span><span class="p">,</span> <span class="nx">js</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">compile</span> <span class="k">then</span> <span class="nx">write_js</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="k">else</span> <span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">lint</span> <span class="k">then</span> <span class="nx">lint</span> <span class="nx">js</span>
|
||||
<span class="k">catch</span> <span class="nx">err</span>
|
||||
<span class="k">if</span> <span class="nx">o</span><span class="p">.</span><span class="nx">watch</span> <span class="k">then</span> <span class="nx">puts</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span> <span class="k">else</span> <span class="k">throw</span> <span class="nx">err</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
|
||||
@@ -75,22 +81,25 @@ and write them back to <strong>stdout</strong>.</p> </td>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">addListener</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="nv">code: </span><span class="o">+</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="k">if</span> <span class="nx">buffer</span>
|
||||
<span class="nx">stdin</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'end'</span><span class="p">,</span> <span class="o">-></span>
|
||||
<span class="nx">compile_script</span> <span class="s1">'stdio'</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Watch a list of source CoffeeScript files using <code>fs.watchFile</code>, recompiling
|
||||
them every time the files are 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_scripts: </span><span class="o">-></span>
|
||||
<span class="nv">watch: </span><span class="p">(</span><span class="nx">source</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="nv">persistent: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">interval: </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">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="nx">compile_script</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">watch</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span> <span class="k">for</span> <span class="nx">source</span> <span class="k">in</span> <span class="nx">sources</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Write out a JavaScript source file with the compiled code. By default, files
|
||||
<span class="nx">compile_script</span> <span class="s1">'stdio'</span><span class="p">,</span> <span class="nx">code</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</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="nv">persistent: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">interval: </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">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">puts</span> <span class="s2">"Compiled $source"</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">compile</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="nx">compile_script</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-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</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">write_js: </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="o">-></span>
|
||||
directory can be customized with <code>--output</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">write_js: </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>
|
||||
<span class="nv">dir: </span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span> <span class="o">or</span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">source</span><span class="p">)</span>
|
||||
<span class="nv">src_dir: </span> <span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span> <span class="nx">source</span>
|
||||
<span class="nv">base_dir: </span><span class="nx">src_dir</span><span class="p">.</span><span class="nx">substring</span> <span class="nx">base</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">dir: </span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span> <span class="k">then</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">options</span><span class="p">.</span><span class="nx">output</span><span class="p">,</span> <span class="nx">base_dir</span> <span class="k">else</span> <span class="nx">src_dir</span>
|
||||
<span class="nv">js_path: </span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span> <span class="nx">dir</span><span class="p">,</span> <span class="nx">filename</span>
|
||||
<span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">js_path</span><span class="p">,</span> <span class="nx">js</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Pipe compiled JS through JSLint (requires a working <code>jsl</code> command), printing
|
||||
<span class="nv">compile: </span> <span class="o">-></span> <span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span> <span class="nx">js_path</span><span class="p">,</span> <span class="nx">js</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-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</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">js</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">print_it: </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">puts</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nv">print_it: </span><span class="p">(</span><span class="nx">buffer</span><span class="p">)</span> <span class="o">-></span> <span class="nx">print</span> <span class="nx">buffer</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span>
|
||||
<span class="nv">jsl: </span><span class="nx">spawn</span> <span class="s1">'jsl'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'-nologo'</span><span class="p">,</span> <span class="s1">'-stdin'</span><span class="p">]</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">print_it</span>
|
||||
<span class="nx">jsl</span><span class="p">.</span><span class="nx">stderr</span><span class="p">.</span><span class="nx">addListener</span> <span class="s1">'data'</span><span class="p">,</span> <span class="nx">print_it</span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>grammar.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> grammar.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript parser is generated by <a href="http://github.com/zaach/jison">Jison</a>
|
||||
<!DOCTYPE html> <html> <head> <title>grammar.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> grammar.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript parser is generated by <a href="http://github.com/zaach/jison">Jison</a>
|
||||
from this grammar file. Jison is a bottom-up parser generator, similar in
|
||||
style to <a href="http://www.gnu.org/software/bison">Bison</a>, implemented in JavaScript.
|
||||
It can recognize <a href="http://en.wikipedia.org/wiki/LR_grammar">LALR(1), LR(0), SLR(1), and LR(1)</a>
|
||||
@@ -41,16 +41,14 @@ all parsing must end here.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s2">"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="s2">"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="s2">"Body TERMINATOR"</span>
|
||||
<span class="p">]</span>
|
||||
</pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">Line: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">Line: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement"</span>
|
||||
<span class="p">]</span>
|
||||
</pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Pure statements which cannot be expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Statement: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Pure statements which cannot be expressions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Statement: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Return"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Throw"</span>
|
||||
<span class="nx">o</span> <span class="s2">"BREAK"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"CONTINUE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"BREAK"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"CONTINUE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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
|
||||
@@ -79,16 +77,16 @@ token stream.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s2">"INDENT OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">Expressions</span><span class="p">()</span>
|
||||
<span class="nx">o</span> <span class="s2">"TERMINATOR Comment"</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">$2</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" 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="nv">Identifier: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IDENTIFIER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"IDENTIFIER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Alphanumerics are separated from the other <strong>Literal</strong> matchers because
|
||||
they can also serve as keys in object literals.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AlphaNumeric: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"NUMBER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"STRING"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"NUMBER"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"STRING"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>All of our immediate values. These can (in general), be passed straight
|
||||
through and printed to JavaScript.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Literal: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"AlphaNumeric"</span>
|
||||
<span class="nx">o</span> <span class="s2">"JS"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"REGEX"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"JS"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"REGEX"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"TRUE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s2">"FALSE"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">false</span>
|
||||
<span class="nx">o</span> <span class="s2">"YES"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="kc">true</span>
|
||||
@@ -99,6 +97,8 @@ through and printed to JavaScript.</p> </td> <td class="
|
||||
<span class="nx">o</span> <span class="s2">"Assignable ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Assignment when it happens within an object literal. The difference from
|
||||
the ordinary <strong>Assign</strong> is that these allow numbers and strings as keys.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AssignObj: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"AlphaNumeric"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">$1</span><span class="p">),</span> <span class="nx">$3</span><span class="p">,</span> <span class="s1">'object'</span>
|
||||
<span class="nx">o</span> <span class="s2">"AlphaNumeric ASSIGN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AssignNode</span> <span class="k">new</span> <span class="nx">ValueNode</span><span class="p">(</span><span class="nx">$1</span><span class="p">),</span> <span class="nx">$3</span><span class="p">,</span> <span class="s1">'object'</span>
|
||||
<span class="nx">o</span> <span class="s2">"Comment"</span>
|
||||
@@ -108,7 +108,8 @@ 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="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>A comment. Because CoffeeScript passes comments through to JavaScript, we
|
||||
have to parse comments like any other construct, and identify all of the
|
||||
positions in which they can occur in the grammar.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Comment: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"COMMENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CommentNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"COMMENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CommentNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"HERECOMMENT"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CommentNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="s1">'herecomment'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p><a href="http://jashkenas.github.com/coffee-script/#existence">The existential operator</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Existence: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression ?"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ExistenceNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>The <strong>Code</strong> node is the function literal. It's defined by an indented block
|
||||
@@ -120,26 +121,29 @@ list.</p> </td> <td class="code"> <div cla
|
||||
functions, and <code>=></code> is for functions bound to the current value of <em>this</em>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">FuncGlyph: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"->"</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'func'</span>
|
||||
<span class="nx">o</span> <span class="s2">"=>"</span><span class="p">,</span> <span class="o">-></span> <span class="s1">'boundfunc'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>The list of parameters that a function accepts can be of any length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ParamList: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>An optional, trailing comma.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">OptComma: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s1">''</span>
|
||||
<span class="nx">o</span> <span class="s1">','</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>The list of parameters that a function accepts can be of any length.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ParamList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Param"</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ParamList , Param"</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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>A single parameter in a function definition can be ordinary, or a splat
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>A single parameter in a function definition can be ordinary, or a splat
|
||||
that hoovers up the remaining arguments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Param: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"PARAM"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"PARAM"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Param . . ."</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">SplatNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Splat: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>A splat that occurs outside of a parameter list.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Splat: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression . . ."</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">SplatNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">SimpleAssignable: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>Variables and properties that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">SimpleAssignable: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Value Accessor"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"Invocation Accessor"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="p">[</span><span class="nx">$2</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ThisProperty"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assignable: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Everything that can be assigned to.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Assignable: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SimpleAssignable"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Array"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Object"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>The types of things that can be treated as values -- assigned to, invoked
|
||||
as functions, indexed into, named as a class, etc.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Value: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Assignable"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Literal"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
@@ -147,7 +151,7 @@ as functions, indexed into, named as a class, etc.</p> </td>
|
||||
<span class="nx">o</span> <span class="s2">"Range"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"This"</span>
|
||||
<span class="nx">o</span> <span class="s2">"NULL"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'null'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>The general group of accessors into an object, by property, by prototype
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>The general group of accessors into an object, by property, by prototype
|
||||
or by array index or slice.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Accessor: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"PROPERTY_ACCESS Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"PROTOTYPE_ACCESS Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'prototype'</span>
|
||||
@@ -155,24 +159,18 @@ or by array index or slice.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s2">"SOAK_ACCESS Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">AccessorNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'soak'</span>
|
||||
<span class="nx">o</span> <span class="s2">"Index"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Slice"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">SliceNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-31">#</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Index: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>Indexing into an object or array using bracket notation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Index: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_START Expression INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IndexNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"SOAKED_INDEX_START Expression SOAKED_INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IndexNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="s1">'soak'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-32">#</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ AssignList }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ IndentedAssignList }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ AssignList , }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ IndentedAssignList , }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-33">#</a> </div> <p>In CoffeeScript, an object literal is simply a list of assignments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Object</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"{ AssignList OptComma }"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ObjectNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <p>Assignment of properties within an object literal can be separated by
|
||||
comma, as in JavaScript, or simply by newline.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">AssignList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">""</span><span class="p">,</span> <span class="o">-></span> <span class="p">[]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignObj"</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList , AssignObj"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList TERMINATOR AssignObj"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList , TERMINATOR AssignObj"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-34">#</a> </div> <p>An <strong>AssignList</strong> within a block indentation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IndentedAssignList: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT AssignList OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDENT AssignList , OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList OptComma TERMINATOR AssignObj"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"AssignList OptComma INDENT AssignList OptComma OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">concat</span> <span class="nx">$4</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-35">#</a> </div> <p>Class definitions have optional bodies of prototype property assignments,
|
||||
and optional references to the superclass.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Class: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"CLASS SimpleAssignable"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ClassNode</span> <span class="nx">$2</span>
|
||||
@@ -200,11 +198,9 @@ object.</p> </td> <td class="code"> <div c
|
||||
<span class="nx">o</span> <span class="s2">"Value Arguments"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"Invocation Arguments"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-42">#</a> </div> <p>The list of arguments to a function call.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Arguments: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"CALL_START ArgList CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"CALL_START ArgList , CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"CALL_START ArgList OptComma CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-43">#</a> </div> <p>Calling super.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Super: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SUPER CALL_START ArgList CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"SUPER CALL_START ArgList , CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"SUPER CALL_START ArgList OptComma CALL_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">CallNode</span> <span class="s1">'super'</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>A reference to the <em>this</em> current object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">This: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"THIS"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'this'</span>
|
||||
<span class="nx">o</span> <span class="s2">"@"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="k">new</span> <span class="nx">LiteralNode</span> <span class="s1">'this'</span>
|
||||
@@ -217,8 +213,7 @@ object.</p> </td> <td class="code"> <div c
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_START Expression . . Expression INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$5</span>
|
||||
<span class="nx">o</span> <span class="s2">"INDEX_START Expression . . . Expression INDEX_END"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">RangeNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>The array literal.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nb">Array</span><span class="o">:</span> <span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"[ ArgList ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"[ ArgList , ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"[ ArgList OptComma ]"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ArrayNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>The <strong>ArgList</strong> is both the list of objects passed into a function call,
|
||||
as well as the contents of an array literal
|
||||
(i.e. comma-separated expressions). Newlines work as well.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ArgList: </span><span class="p">[</span>
|
||||
@@ -229,8 +224,7 @@ as well as the contents of an array literal
|
||||
<span class="nx">o</span> <span class="s2">"ArgList TERMINATOR Expression"</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="p">[</span><span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList , TERMINATOR Expression"</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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList , INDENT Expression"</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="p">[</span><span class="nx">$4</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList OUTDENT"</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList , OUTDENT"</span>
|
||||
<span class="nx">o</span> <span class="s2">"ArgList OptComma OUTDENT"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p>Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
this to be separate from the <strong>ArgList</strong> for use in <strong>Switch</strong> blocks, where
|
||||
having the newlines wouldn't make sense.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">SimpleArgs: </span><span class="p">[</span>
|
||||
@@ -252,10 +246,12 @@ the trick.</p> </td> <td class="code"> <di
|
||||
<span class="nx">o</span> <span class="s2">"( Line )"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ParentheticalNode</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-55">#</a> </div> <p>A language extension to CoffeeScript from the outside. We simply pass
|
||||
it through unaltered.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Extension: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"EXTENSION"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">yytext</span>
|
||||
<span class="nx">o</span> <span class="s2">"EXTENSION"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-56">#</a> </div> <p>The condition portion of a while loop.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">WhileSource: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"WHILE Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"WHILE Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">filter : </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"WHILE Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">guard : </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"UNTIL Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"UNTIL Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">WhileNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="p">{</span><span class="nv">invert: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-57">#</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="nv">While: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"WhileSource Block"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_body</span> <span class="nx">$2</span>
|
||||
@@ -267,51 +263,59 @@ or postfix, with a single expression.</p> </td> <td clas
|
||||
<span class="nx">o</span> <span class="s2">"Statement FOR ForVariables ForSource"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression FOR ForVariables ForSource"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$3</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"FOR ForVariables ForSource Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ForNode</span> <span class="nx">$4</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="nx">$2</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">$2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-59">#</a> </div> <p>An array or range comprehension has variables for the current element and
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-59">#</a> </div> <p>An array of all accepted values for a variable inside the loop. This
|
||||
enables support for pattern matching.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ForValue: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Array"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="nx">o</span> <span class="s2">"Object"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">ValueNode</span> <span class="nx">$1</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-60">#</a> </div> <p>An array or range comprehension has variables for the current element and
|
||||
(optional) reference to the current index. Or, <em>key, value</em>, in the case
|
||||
of object comprehensions.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ForVariables: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"Identifier , Identifier"</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-60">#</a> </div> <p>The source of a comprehension is an array or object with an optional filter
|
||||
<span class="nx">o</span> <span class="s2">"ForValue"</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">]</span>
|
||||
<span class="nx">o</span> <span class="s2">"ForValue , ForValue"</span><span class="p">,</span> <span class="o">-></span> <span class="p">[</span><span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-61">#</a> </div> <p>The source of a comprehension is an array or object with an optional guard
|
||||
clause. If it's an array comprehension, you can also choose to step through
|
||||
in fixed-size increments.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ForSource: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"OF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"OF Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"OF Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">object: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression BY Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression BY Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$4</span><span class="p">;</span> <span class="nv">step: </span> <span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression BY Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">,</span> <span class="nv">filter: </span><span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-61">#</a> </div> <p>The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression WHEN Expression BY Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$4</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IN Expression BY Expression WHEN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="p">{</span><span class="nv">source: </span><span class="nx">$2</span><span class="p">,</span> <span class="nv">step: </span> <span class="nx">$4</span><span class="p">,</span> <span class="nv">guard: </span><span class="nx">$6</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-62">#</a> </div> <p>The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
switch/case/default by compiling into an if-else chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Switch: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">rewrite_condition</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens ELSE Block OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">rewrite_condition</span><span class="p">(</span><span class="nx">$2</span><span class="p">).</span><span class="nx">add_else</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-62">#</a> </div> <p>The inner list of whens is left recursive. At code-generation time, the
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">switches_over</span> <span class="nx">$2</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH Expression INDENT Whens ELSE Block OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$4</span><span class="p">.</span><span class="nx">switches_over</span><span class="p">(</span><span class="nx">$2</span><span class="p">).</span><span class="nx">add_else</span> <span class="nx">$6</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH INDENT Whens OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"SWITCH INDENT Whens ELSE Block OUTDENT"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$3</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$5</span><span class="p">,</span> <span class="kc">true</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-63">#</a> </div> <p>The inner list of whens is left recursive. At code-generation time, the
|
||||
IfNode will rewrite them into a proper chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">Whens: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"When"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Whens When"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">push</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-63">#</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">When: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block TERMINATOR"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Whens When"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-64">#</a> </div> <p>An individual <strong>When</strong> clause, with action.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">When: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"LEADING_WHEN SimpleArgs Block TERMINATOR"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Comment TERMINATOR When"</span><span class="p">,</span> <span class="o">-></span> <span class="nv">$3.comment: </span><span class="nx">$1</span><span class="p">;</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-64">#</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-65">#</a> </div> <p>The most basic form of <em>if</em> is a condition and an action. The following
|
||||
if-related rules are broken up along these lines in order to avoid
|
||||
ambiguity.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfStart: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IF Expression Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="nx">o</span> <span class="s2">"UNLESS Expression Block"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</span> <span class="nx">$2</span><span class="p">,</span> <span class="nx">$3</span><span class="p">,</span> <span class="p">{</span><span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfStart ElsIf"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$2</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-65">#</a> </div> <p>An <strong>IfStart</strong> can optionally be followed by an else block.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfBlock: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-66">#</a> </div> <p>An <strong>IfStart</strong> can optionally be followed by an else block.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">IfBlock: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfStart"</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfStart ELSE Block"</span><span class="p">,</span> <span class="o">-></span> <span class="nx">$1</span><span class="p">.</span><span class="nx">add_else</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-66">#</a> </div> <p>An <em>else if</em> continuation of the <em>if</em> expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ElsIf: </span><span class="p">[</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-67">#</a> </div> <p>An <em>else if</em> continuation of the <em>if</em> expression.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ElsIf: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"ELSE IF Expression Block"</span><span class="p">,</span> <span class="o">-></span> <span class="p">(</span><span class="k">new</span> <span class="nx">IfNode</span><span class="p">(</span><span class="nx">$3</span><span class="p">,</span> <span class="nx">$4</span><span class="p">)).</span><span class="nx">force_statement</span><span class="p">()</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-67">#</a> </div> <p>The full complement of <em>if</em> expressions, including postfix one-liner
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-68">#</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="nv">If: </span><span class="p">[</span>
|
||||
<span class="nx">o</span> <span class="s2">"IfBlock"</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="kc">null</span><span class="p">,</span> <span class="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-68">#</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
|
||||
<span class="nx">o</span> <span class="s2">"Statement IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression IF Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Statement UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">o</span> <span class="s2">"Expression UNLESS Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">IfNode</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="p">{</span><span class="nv">statement: </span><span class="kc">true</span><span class="p">,</span> <span class="nv">invert: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-69">#</a> </div> <p>Arithmetic and logical operators, working on one or more operands.
|
||||
Here they are grouped by order of precedence. The actual precedence rules
|
||||
are defined at the bottom of the page. It would be shorter if we could
|
||||
combine most of these rules into a single generic <em>Operand OpSymbol Operand</em>
|
||||
@@ -368,7 +372,7 @@ rules are necessary.</p> </td> <td class="code">
|
||||
<span class="nx">o</span> <span class="s2">"Expression IN Expression"</span><span class="p">,</span> <span class="o">-></span> <span class="k">new</span> <span class="nx">OpNode</span> <span class="s1">'in'</span><span class="p">,</span> <span class="nx">$1</span><span class="p">,</span> <span class="nx">$3</span>
|
||||
<span class="p">]</span>
|
||||
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-69">#</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-70">#</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
|
||||
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-70">#</a> </div> <h2>Precedence</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-71">#</a> </div> <p>Operators at the top of this list have higher precedence than the ones lower
|
||||
down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
|
||||
<pre><code>2 + (3 * 4)
|
||||
@@ -383,12 +387,37 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'*'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">,</span> <span class="s1">'%'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'+'</span><span class="p">,</span> <span class="s1">'-'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'<<'</span><span class="p">,</span> <span class="s1">'>>'</span><span class="p">,</span> <span class="s1">'>>>'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'&'</span><span class="p">,</span> <span class="s1">'|'</span><span class="p">,</span> <span class="s1">'^'</span>
|
||||
|
||||
</pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-71">#</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre>undefined</pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-72">#</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'&'</span><span class="p">,</span> <span class="s1">'|'</span><span class="p">,</span> <span class="s1">'^'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'<='</span><span class="p">,</span> <span class="s1">'<'</span><span class="p">,</span> <span class="s1">'>'</span><span class="p">,</span> <span class="s1">'>='</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'DELETE'</span><span class="p">,</span> <span class="s1">'INSTANCEOF'</span><span class="p">,</span> <span class="s1">'TYPEOF'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'=='</span><span class="p">,</span> <span class="s1">'!='</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'&&'</span><span class="p">,</span> <span class="s1">'||'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'-='</span><span class="p">,</span> <span class="s1">'+='</span><span class="p">,</span> <span class="s1">'/='</span><span class="p">,</span> <span class="s1">'*='</span><span class="p">,</span> <span class="s1">'%='</span><span class="p">,</span> <span class="s1">'||='</span><span class="p">,</span> <span class="s1">'&&='</span><span class="p">,</span> <span class="s1">'?='</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'.'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'LEADING_WHEN'</span><span class="p">,</span> <span class="s1">'IN'</span><span class="p">,</span> <span class="s1">'OF'</span><span class="p">,</span> <span class="s1">'BY'</span><span class="p">,</span> <span class="s1">'THROW'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'NEW'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">'CLASS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"left"</span><span class="p">,</span> <span class="s1">'EXTENDS'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'ASSIGN'</span><span class="p">,</span> <span class="s1">'RETURN'</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="s2">"right"</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'<-'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">]</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-72">#</a> </div> <h2>Wrapping Up</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-73">#</a> </div> <p>Finally, now what we have our <strong>grammar</strong> and our <strong>operators</strong>, we can create
|
||||
our <strong>Jison.Parser</strong>. We do this by processing all of our rules, recording all
|
||||
terminals (every symbol which does not appear as the name of a rule above)
|
||||
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre>undefined</pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-73">#</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
as "tokens".</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">tokens: </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">alternatives</span> <span class="k">of</span> <span class="nx">grammar</span>
|
||||
<span class="nx">grammar</span><span class="p">[</span><span class="nx">name</span><span class="p">]</span><span class="o">:</span> <span class="k">for</span> <span class="nx">alt</span> <span class="k">in</span> <span class="nx">alternatives</span>
|
||||
<span class="k">for</span> <span class="nx">token</span> <span class="k">in</span> <span class="nx">alt</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">split</span> <span class="s1">' '</span>
|
||||
<span class="nx">tokens</span><span class="p">.</span><span class="nx">push</span> <span class="nx">token</span> <span class="nx">unless</span> <span class="nx">grammar</span><span class="p">[</span><span class="nx">token</span><span class="p">]</span>
|
||||
<span class="nx">alt</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"return ${alt[1]}"</span> <span class="k">if</span> <span class="nx">name</span> <span class="o">is</span> <span class="s1">'Root'</span>
|
||||
<span class="nx">alt</span></pre></div> </td> </tr> <tr id="section-74"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-74">#</a> </div> <p>Initialize the <strong>Parser</strong> with our list of terminal <strong>tokens</strong>, our <strong>grammar</strong>
|
||||
rules, and the name of the root. Reverse the operators because Jison orders
|
||||
precedence from low to high, and we have it high to low
|
||||
(as in <a href="http://dinosaur.compilertools.net/yacc/index.html">Yacc</a>).</p> </td> <td class="code"> <div class="highlight"><pre>undefined</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
(as in <a href="http://dinosaur.compilertools.net/yacc/index.html">Yacc</a>).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.parser: </span><span class="k">new</span> <span class="nx">Parser</span> <span class="p">{</span>
|
||||
<span class="nv">tokens: </span> <span class="nx">tokens</span><span class="p">.</span><span class="nx">join</span> <span class="s1">' '</span>
|
||||
<span class="nv">bnf: </span> <span class="nx">grammar</span>
|
||||
<span class="nv">operators: </span> <span class="nx">operators</span><span class="p">.</span><span class="nx">reverse</span><span class="p">()</span>
|
||||
<span class="nv">startSymbol: </span> <span class="s1">'Root'</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,32 +1,37 @@
|
||||
<!DOCTYPE html> <html> <head> <title>helpers.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> helpers.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>This file contains the common helper functions that we'd like to share among
|
||||
<!DOCTYPE html> <html> <head> <title>helpers.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> helpers.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>This file contains the common helper functions that we'd like to share among
|
||||
the <strong>Lexer</strong>, <strong>Rewriter</strong>, and the <strong>Nodes</strong>. Merge objects, flatten
|
||||
arrays, count characters, that sort of thing.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both <strong>Node.js</strong> and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span> <span class="nx">unless</span> <span class="nx">process</span><span class="o">?</span>
|
||||
<span class="nv">helpers: exports.helpers: </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Does a list include a value?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.include: include: </span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">list</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Peek at the beginning of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.starts: starts: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">start</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">string</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">start</span><span class="p">,</span> <span class="p">(</span><span class="nx">start</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="o">is</span> <span class="nx">literal</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.compact: compact: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span> <span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Count the number of occurences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.count: count: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">helpers: exports.helpers: </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Cross-browser indexOf, so that IE can join the party.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.index_of: index_of: </span><span class="p">(</span><span class="nx">array</span><span class="p">,</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">from</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">return</span> <span class="nx">array</span><span class="p">.</span><span class="nx">indexOf</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">from</span> <span class="k">if</span> <span class="nx">array</span><span class="p">.</span><span class="nx">indexOf</span>
|
||||
<span class="k">for</span> <span class="nx">other</span><span class="p">,</span> <span class="nx">index</span> <span class="k">in</span> <span class="nx">array</span>
|
||||
<span class="k">if</span> <span class="nx">other</span> <span class="o">is</span> <span class="nx">item</span> <span class="o">and</span> <span class="p">(</span><span class="o">not</span> <span class="nx">from</span> <span class="o">or</span> <span class="p">(</span><span class="nx">from</span> <span class="o"><=</span> <span class="nx">index</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="nx">index</span>
|
||||
<span class="o">-</span><span class="mi">1</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Does a list include a value?</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.include: include: </span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">index_of</span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Peek at the beginning of a given string to see if it matches a sequence.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.starts: starts: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">literal</span><span class="p">,</span> <span class="nx">start</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">string</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">start</span><span class="p">,</span> <span class="p">(</span><span class="nx">start</span> <span class="o">or</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="nx">literal</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="o">is</span> <span class="nx">literal</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Trim out all falsy values from an array.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.compact: compact: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span> <span class="nx">item</span> <span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span> <span class="k">when</span> <span class="nx">item</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Count the number of occurences of a character in a string.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.count: count: </span><span class="p">(</span><span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">num: </span><span class="mi">0</span>
|
||||
<span class="nv">pos: </span><span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">letter</span><span class="p">)</span>
|
||||
<span class="nv">pos: </span><span class="nx">index_of</span> <span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span>
|
||||
<span class="k">while</span> <span class="nx">pos</span> <span class="o">isnt</span> <span class="o">-</span><span class="mi">1</span>
|
||||
<span class="nv">num: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">pos: </span><span class="nx">string</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="nx">num</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
<span class="nv">pos: </span><span class="nx">index_of</span> <span class="nx">string</span><span class="p">,</span> <span class="nx">letter</span><span class="p">,</span> <span class="nx">pos</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">num</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Merge objects, returning a fresh copy with attributes from both sides.
|
||||
Used every time <code>BaseNode#compile</code> is called, to allow properties in the
|
||||
options hash to propagate down the tree without polluting other branches.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.merge: merge: </span><span class="p">(</span><span class="nx">options</span><span class="p">,</span> <span class="nx">overrides</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">fresh: </span><span class="p">{}</span>
|
||||
<span class="p">(</span><span class="nx">fresh</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">options</span>
|
||||
<span class="p">(</span><span class="nx">fresh</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">overrides</span> <span class="k">if</span> <span class="nx">overrides</span>
|
||||
<span class="nx">fresh</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Extend a source object with the properties of another object (shallow copy).
|
||||
<span class="nx">fresh</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Extend a source object with the properties of another object (shallow copy).
|
||||
We use this to simulate Node's deprecated <code>process.mixin</code></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.extend: extend: </span><span class="p">(</span><span class="nx">object</span><span class="p">,</span> <span class="nx">properties</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="p">(</span><span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Return a completely flattened version of an array. Handy for getting a
|
||||
<span class="p">(</span><span class="nx">object</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">properties</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Return a completely flattened version of an array. Handy for getting a
|
||||
list of <code>children</code> from the nodes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.flatten: flatten: </span><span class="p">(</span><span class="nx">array</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">memo: </span><span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">array</span>
|
||||
<span class="k">if</span> <span class="nx">item</span> <span class="k">instanceof</span> <span class="nb">Array</span> <span class="k">then</span> <span class="nv">memo: </span><span class="nx">memo</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="k">else</span> <span class="nx">memo</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span>
|
||||
<span class="nx">memo</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-10">#</a> </div> <p>Delete a key from an object, returning the value. Useful when a node is
|
||||
<span class="nx">memo</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Delete a key from an object, returning the value. Useful when a node is
|
||||
looking for a particular method in an options hash.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.del: del: </span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">key</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">val: </span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
|
||||
<span class="k">delete</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span>
|
||||
<span class="nx">val</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-11">#</a> </div> <p>Matches a balanced group such as a single or double-quoted string. Pass in
|
||||
<span class="nx">val</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Matches a balanced group such as a single or double-quoted string. Pass in
|
||||
a series of delimiters, all of which must be nested correctly within the
|
||||
contents of the string. This method allows us to have strings within
|
||||
interpolations within strings, ad infinitum.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">helpers.balanced_string: balanced_string: </span><span class="p">(</span><span class="nx">str</span><span class="p">,</span> <span class="nx">delimited</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
|
||||
3
documentation/docs/index.html
Normal file
3
documentation/docs/index.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!DOCTYPE html> <html> <head> <title>index.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> index.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>Loader for CoffeeScript as a Node.js library.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">(</span><span class="nx">exports</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">:</span> <span class="nx">val</span><span class="p">)</span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">val</span> <span class="k">of</span> <span class="nx">require</span> <span class="s1">'./coffee-script'</span>
|
||||
|
||||
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>lexer.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lexer.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
<!DOCTYPE html> <html> <head> <title>lexer.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lexer.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
matches against the beginning of the source code. When a match is found,
|
||||
a token is produced, we consume the match, and start again. Tokens are in the
|
||||
form:</p>
|
||||
@@ -7,16 +7,12 @@ form:</p>
|
||||
</code></pre>
|
||||
|
||||
<p>Which is a format that can be fed directly into <a href="http://github.com/zaach/jison">Jison</a>.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up the Lexer for both Node.js and the browser, depending on where we are.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
|
||||
<span class="nv">Rewriter: </span><span class="nx">require</span><span class="p">(</span><span class="s1">'./rewriter'</span><span class="p">).</span><span class="nx">Rewriter</span>
|
||||
<span class="nv">helpers: </span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">).</span><span class="nx">helpers</span>
|
||||
<span class="p">{</span><span class="nx">Rewriter</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./rewriter'</span><span class="p">)</span>
|
||||
<span class="p">{</span><span class="nx">helpers</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
|
||||
<span class="nv">Rewriter: </span> <span class="k">this</span><span class="p">.</span><span class="nx">Rewriter</span>
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">include: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">include</span>
|
||||
<span class="nv">count: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">count</span>
|
||||
<span class="nv">starts: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">starts</span>
|
||||
<span class="nv">compact: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">compact</span>
|
||||
<span class="nv">balanced_string: </span> <span class="nx">helpers</span><span class="p">.</span><span class="nx">balanced_string</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <h2>The Lexer Class</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">include</span><span class="p">,</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">starts</span><span class="p">,</span> <span class="nx">compact</span><span class="p">,</span> <span class="nx">balanced_string</span><span class="p">}</span><span class="o">:</span> <span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <h2>The Lexer Class</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
|
||||
tokens. Some potential ambiguity in the grammar has been avoided by
|
||||
pushing some extra smarts into the Lexer.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Lexer: </span><span class="nx">class</span> <span class="nx">Lexer</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p><strong>tokenize</strong> is the Lexer's main method. Scan by attempting to match tokens
|
||||
one at a time, using a regular expression anchored at the start of the
|
||||
@@ -74,7 +70,7 @@ though <code>is</code> means <code>===</code> otherwise.</p> </td>
|
||||
<span class="nx">@identifier_error</span> <span class="nx">id</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">RESERVED</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="nv">tag: </span><span class="s1">'LEADING_WHEN'</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'WHEN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">id</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="k">if</span> <span class="o">not</span> <span class="nx">accessed</span>
|
||||
<span class="nx">unless</span> <span class="nx">accessed</span>
|
||||
<span class="nv">tag: id: </span><span class="nx">CONVERSIONS</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">COFFEE_ALIASES</span><span class="p">,</span> <span class="nx">id</span>
|
||||
<span class="k">return</span> <span class="nx">@tag_half_assignment</span> <span class="nx">tag</span> <span class="k">if</span> <span class="nx">@prev</span><span class="p">()</span> <span class="o">and</span> <span class="nx">@prev</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'ASSIGN'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">HALF_ASSIGNMENTS</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="nx">@token</span> <span class="nx">tag</span><span class="p">,</span> <span class="nx">id</span>
|
||||
@@ -95,23 +91,38 @@ are balanced within the string's contents, and within nested interpolations.</p>
|
||||
preserve whitespace, but ignore indentation to the left.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">heredoc_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">HEREDOC</span><span class="p">)</span>
|
||||
<span class="nv">quote: </span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">substr</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nv">doc: </span><span class="nx">@sanitize_heredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">or</span> <span class="nx">match</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="nx">quote</span>
|
||||
<span class="nv">doc: </span><span class="nx">@sanitize_heredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">or</span> <span class="nx">match</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="p">{</span><span class="nx">quote</span><span class="p">}</span>
|
||||
<span class="nx">@interpolate_string</span> <span class="s2">"$quote$doc$quote"</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">js_token: </span><span class="o">-></span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-14">#</a> </div> <p>Matches and conumes comments. We pass through comments into JavaScript,
|
||||
so they're treated as real tokens, like any other part of the language.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">comment_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">match: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">COMMENT</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nx">match</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
|
||||
<span class="nv">comment: </span><span class="nx">@sanitize_heredoc</span> <span class="nx">match</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="p">{</span><span class="nv">herecomment: </span><span class="kc">true</span><span class="p">}</span>
|
||||
<span class="nx">@token</span> <span class="s1">'HERECOMMENT'</span><span class="p">,</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">split</span> <span class="nx">MULTILINER</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">lines: </span><span class="nx">compact</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">replace</span><span class="p">(</span><span class="nx">COMMENT_CLEANER</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nx">split</span> <span class="nx">MULTILINER</span>
|
||||
<span class="nv">i: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">@unfinished</span><span class="p">()</span>
|
||||
<span class="nv">i: </span><span class="o">-</span> <span class="mi">1</span> <span class="k">while</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'COMMENT'</span><span class="p">,</span> <span class="nx">lines</span><span class="p">,</span> <span class="nx">@line</span><span class="p">],</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'\n'</span><span class="p">,</span> <span class="nx">@line</span><span class="p">])</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Matches JavaScript interpolated directly into the source via backticks.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">js_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">starts</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="s1">'`'</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">script: </span><span class="nx">@balanced_token</span> <span class="p">[</span><span class="s1">'`'</span><span class="p">,</span> <span class="s1">'`'</span><span class="p">]</span>
|
||||
<span class="nx">@token</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="nx">script</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">JS_CLEANER</span><span class="p">,</span> <span class="s1">''</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">script</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <p>Matches regular expression literals. Lexing regular expressions is difficult
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Matches regular expression literals. Lexing regular expressions is difficult
|
||||
to distinguish from division, so we borrow some basic heuristics from
|
||||
JavaScript and Ruby, borrow slash balancing from <code>@balanced_token</code>, and
|
||||
borrow interpolation from <code>@interpolate_string</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">regex_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nx">@chunk</span><span class="p">.</span><span class="nx">match</span> <span class="nx">REGEX_START</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">include</span> <span class="nx">NOT_REGEX</span><span class="p">,</span> <span class="nx">@tag</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">regex: </span><span class="nx">@balanced_token</span> <span class="p">[</span><span class="s1">'/'</span><span class="p">,</span> <span class="s1">'/'</span><span class="p">]</span>
|
||||
<span class="nv">regex: </span><span class="o">+</span> <span class="p">(</span><span class="nv">flags: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">length</span><span class="p">).</span><span class="nx">match</span> <span class="nx">REGEX_FLAGS</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">end: </span><span class="nx">@chunk</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">length</span><span class="p">).</span><span class="nx">match</span> <span class="nx">REGEX_END</span>
|
||||
<span class="nv">regex: </span><span class="o">+</span> <span class="nv">flags: </span><span class="nx">end</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">if</span> <span class="nx">end</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">match</span> <span class="nx">REGEX_INTERPOLATION</span>
|
||||
<span class="nv">str: </span><span class="nx">regex</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nx">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">str: </span><span class="nx">str</span><span class="p">.</span><span class="nx">replace</span> <span class="nx">REGEX_ESCAPE</span><span class="p">,</span> <span class="p">(</span><span class="nx">escaped</span><span class="p">)</span> <span class="o">-></span> <span class="s1">'\\'</span> <span class="o">+</span> <span class="nx">escaped</span>
|
||||
@@ -121,19 +132,9 @@ borrow interpolation from <code>@interpolate_string</code>.</p> </td
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@token</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="nx">regex</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">regex</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>Matches a token in which which the passed delimiter pairs must be correctly
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Matches a token in which which the passed delimiter pairs must be correctly
|
||||
balanced (ie. strings, JS literals).</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">balanced_token: </span><span class="p">(</span><span class="nx">delimited</span><span class="p">...)</span> <span class="o">-></span>
|
||||
<span class="nx">balanced_string</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="nx">delimited</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-17">#</a> </div> <p>Matches and conumes comments. We pass through comments into JavaScript,
|
||||
so they're treated as real tokens, like any other part of the language.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">comment_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">comment: </span><span class="nx">@match</span> <span class="nx">COMMENT</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="p">(</span><span class="nx">comment</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">)</span> <span class="o">or</span> <span class="p">[]).</span><span class="nx">length</span>
|
||||
<span class="nv">lines: </span><span class="nx">compact</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">COMMENT_CLEANER</span><span class="p">,</span> <span class="s1">''</span><span class="p">).</span><span class="nx">split</span> <span class="nx">MULTILINER</span>
|
||||
<span class="nv">i: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">@unfinished</span><span class="p">()</span>
|
||||
<span class="nv">i: </span><span class="o">-</span> <span class="mi">1</span> <span class="k">while</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">and</span> <span class="o">not</span> <span class="nx">include</span> <span class="nx">LINE_BREAK</span><span class="p">,</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'COMMENT'</span><span class="p">,</span> <span class="nx">lines</span><span class="p">,</span> <span class="nx">@line</span><span class="p">],</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'\n'</span><span class="p">,</span> <span class="nx">@line</span><span class="p">])</span>
|
||||
<span class="vi">@i: </span><span class="o">+</span> <span class="nx">comment</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Matches newlines, indents, and outdents, and determines which is which.
|
||||
<span class="nx">balanced_string</span> <span class="nx">@chunk</span><span class="p">,</span> <span class="nx">delimited</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>Matches newlines, indents, and outdents, and determines which is which.
|
||||
If we can detect that the current line is continued onto the the next line,
|
||||
then the newline is suppressed:</p>
|
||||
|
||||
@@ -145,7 +146,7 @@ then the newline is suppressed:</p>
|
||||
<p>Keeps track of the level of indentation, because a single outdent token
|
||||
can close multiple indents, so we need to know how far in we happen to be.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">line_token: </span><span class="o">-></span>
|
||||
<span class="k">return</span> <span class="kc">false</span> <span class="nx">unless</span> <span class="nv">indent: </span><span class="nx">@match</span> <span class="nx">MULTI_DENT</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">).</span><span class="nx">length</span>
|
||||
<span class="vi">@line: </span><span class="o">+</span> <span class="nx">count</span> <span class="nx">indent</span><span class="p">,</span> <span class="s2">"\n"</span>
|
||||
<span class="vi">@i : </span><span class="o">+</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">prev: </span><span class="nx">@prev</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="nv">size: </span><span class="nx">indent</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">LAST_DENTS</span><span class="p">).</span><span class="nx">reverse</span><span class="p">()[</span><span class="mi">0</span><span class="p">].</span><span class="nx">match</span><span class="p">(</span><span class="nx">LAST_DENT</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="nx">length</span>
|
||||
@@ -218,12 +219,15 @@ if it's a special kind of accessor.</p> </td> <td class=
|
||||
<span class="nx">@tag</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'SOAK_ACCESS'</span><span class="p">)</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'PROPERTY_ACCESS'</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Sanitize a heredoc by escaping internal double quotes and erasing all
|
||||
external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">sanitize_heredoc: </span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">quote</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">indent: </span><span class="p">(</span><span class="nx">doc</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">HEREDOC_INDENT</span><span class="p">)</span> <span class="o">or</span> <span class="p">[</span><span class="s1">''</span><span class="p">]).</span><span class="nx">sort</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">"^"</span> <span class="o">+</span><span class="nx">indent</span><span class="p">,</span> <span class="s1">'gm'</span><span class="p">),</span> <span class="s1">''</span><span class="p">)</span>
|
||||
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">,</span> <span class="s2">"\\n"</span><span class="p">)</span>
|
||||
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="nx">quote</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="s1">'\\"'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>Tag a half assignment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag_half_assignment: </span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nx">@tag</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'PROPERTY_ACCESS'</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-26">#</a> </div> <p>Sanitize a heredoc or herecomment by escaping internal double quotes and
|
||||
erasing all external indentation on the left-hand side.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">sanitize_heredoc: </span><span class="p">(</span><span class="nx">doc</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="k">while</span> <span class="nv">match: </span><span class="nx">HEREDOC_INDENT</span><span class="p">.</span><span class="nx">exec</span> <span class="nx">doc</span>
|
||||
<span class="nv">attempt: </span><span class="k">if</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">?</span> <span class="k">then</span> <span class="nx">match</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">else</span> <span class="nx">match</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
|
||||
<span class="nv">indent: </span><span class="nx">attempt</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">indent</span> <span class="o">or</span> <span class="nx">attempt</span><span class="p">.</span><span class="nx">length</span> <span class="o"><</span> <span class="nx">indent</span><span class="p">.</span><span class="nx">length</span>
|
||||
<span class="nv">doc: </span><span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">"^"</span> <span class="o">+</span><span class="nx">indent</span><span class="p">,</span> <span class="s1">'gm'</span><span class="p">),</span> <span class="s1">''</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="nx">doc</span> <span class="k">if</span> <span class="nx">options</span><span class="p">.</span><span class="nx">herecomment</span>
|
||||
<span class="nx">doc</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">MULTILINER</span><span class="p">,</span> <span class="s2">"\\n"</span><span class="p">)</span>
|
||||
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">quote</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="s1">'\\"'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-27">#</a> </div> <p>Tag a half assignment.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">tag_half_assignment: </span><span class="p">(</span><span class="nx">tag</span><span class="p">)</span> <span class="o">-></span>
|
||||
<span class="nv">last: </span><span class="nx">@tokens</span><span class="p">.</span><span class="nx">pop</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="s2">"$tag="</span><span class="p">,</span> <span class="s2">"$tag="</span><span class="p">,</span> <span class="nx">last</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-28">#</a> </div> <p>A source of ambiguity in our grammar used to be parameter lists in function
|
||||
@@ -236,9 +240,9 @@ parameters specially in order to make things easier for the parser.</p>
|
||||
<span class="nv">tok: </span><span class="nx">@prev</span> <span class="nx">i</span>
|
||||
<span class="k">return</span> <span class="k">if</span> <span class="o">not</span> <span class="nx">tok</span>
|
||||
<span class="k">switch</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">when</span> <span class="s1">'IDENTIFIER'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM'</span>
|
||||
<span class="k">when</span> <span class="s1">')'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_END'</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_START'</span>
|
||||
<span class="k">when</span> <span class="s1">'IDENTIFIER'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM'</span>
|
||||
<span class="k">when</span> <span class="s1">')'</span> <span class="k">then</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_END'</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'CALL_START'</span> <span class="k">then</span> <span class="k">return</span> <span class="nx">tok</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">:</span> <span class="s1">'PARAM_START'</span>
|
||||
<span class="kc">true</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-29">#</a> </div> <p>Close up all remaining open blocks at the end of the file.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">close_indentation: </span><span class="o">-></span>
|
||||
<span class="nx">@outdent_token</span> <span class="nx">@indent</span></pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-30">#</a> </div> <p>The error for when you try to use a forbidden word in JavaScript as
|
||||
an identifier.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">identifier_error: </span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="o">-></span>
|
||||
@@ -327,7 +331,7 @@ match if successful, and <code>false</code> otherwise.</p> </td>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-44">#</a> </div> <p>CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
|
||||
be used standalone, but you can reference them as an attached property.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">COFFEE_ALIASES: </span> <span class="p">[</span><span class="s2">"and"</span><span class="p">,</span> <span class="s2">"or"</span><span class="p">,</span> <span class="s2">"is"</span><span class="p">,</span> <span class="s2">"isnt"</span><span class="p">,</span> <span class="s2">"not"</span><span class="p">]</span>
|
||||
<span class="nv">COFFEE_KEYWORDS: </span><span class="nx">COFFEE_ALIASES</span><span class="p">.</span><span class="nx">concat</span> <span class="p">[</span>
|
||||
<span class="s2">"then"</span><span class="p">,</span> <span class="s2">"unless"</span><span class="p">,</span>
|
||||
<span class="s2">"then"</span><span class="p">,</span> <span class="s2">"unless"</span><span class="p">,</span> <span class="s2">"until"</span><span class="p">,</span>
|
||||
<span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"no"</span><span class="p">,</span> <span class="s2">"on"</span><span class="p">,</span> <span class="s2">"off"</span><span class="p">,</span>
|
||||
<span class="s2">"of"</span><span class="p">,</span> <span class="s2">"by"</span><span class="p">,</span> <span class="s2">"where"</span><span class="p">,</span> <span class="s2">"when"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-45">#</a> </div> <p>The combined list of keywords is the superset that gets passed verbatim to
|
||||
@@ -335,7 +339,7 @@ the parser.</p> </td> <td class="code"> <d
|
||||
used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
to avoid having a JavaScript error at runtime.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">RESERVED: </span><span class="p">[</span>
|
||||
<span class="s2">"case"</span><span class="p">,</span> <span class="s2">"default"</span><span class="p">,</span> <span class="s2">"do"</span><span class="p">,</span> <span class="s2">"function"</span><span class="p">,</span> <span class="s2">"var"</span><span class="p">,</span> <span class="s2">"void"</span><span class="p">,</span> <span class="s2">"with"</span>
|
||||
<span class="s2">"const"</span><span class="p">,</span> <span class="s2">"let"</span><span class="p">,</span> <span class="s2">"debugger"</span><span class="p">,</span> <span class="s2">"enum"</span><span class="p">,</span> <span class="s2">"export"</span><span class="p">,</span> <span class="s2">"import"</span><span class="p">,</span> <span class="s2">"native"</span>
|
||||
<span class="s2">"const"</span><span class="p">,</span> <span class="s2">"let"</span><span class="p">,</span> <span class="s2">"enum"</span><span class="p">,</span> <span class="s2">"export"</span><span class="p">,</span> <span class="s2">"import"</span><span class="p">,</span> <span class="s2">"native"</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-47">#</a> </div> <p>The superset of both JavaScript keywords and reserved words, none of which may
|
||||
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></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-48">#</a> </div> <p>Token matching regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IDENTIFIER : </span><span class="sr">/^([a-zA-Z\$_](\w|\$)*)/</span>
|
||||
<span class="nv">NUMBER : </span><span class="sr">/^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i</span>
|
||||
@@ -343,26 +347,26 @@ be used as identifiers or properties.</p> </td> <td clas
|
||||
<span class="nv">INTERPOLATION : </span><span class="sr">/^\$([a-zA-Z_@]\w*(\.\w+)*)/</span>
|
||||
<span class="nv">OPERATOR : </span><span class="sr">/^([+\*&|\/\-%=<>:!?]+)([ \t]*)/</span>
|
||||
<span class="nv">WHITESPACE : </span><span class="sr">/^([ \t]+)/</span>
|
||||
<span class="nv">COMMENT : </span><span class="sr">/^(((\n?[ \t]*)?#[^\n]*)+)/</span>
|
||||
<span class="nv">COMMENT : </span><span class="sr">/^((\n?[ \t]*)?#{3}(?!#)\n*([\s\S]*?)\n*([ \t]*)#{3}|((\n?[ \t]*)?#[^\n]*)+)/</span>
|
||||
<span class="nv">CODE : </span><span class="sr">/^((-|=)>)/</span>
|
||||
<span class="nv">MULTI_DENT : </span><span class="sr">/^((\n([ \t]*))+)(\.)?/</span>
|
||||
<span class="nv">LAST_DENTS : </span><span class="sr">/\n([ \t]*)/g</span>
|
||||
<span class="nv">LAST_DENT : </span><span class="sr">/\n([ \t]*)/</span>
|
||||
<span class="nv">ASSIGNMENT : </span><span class="sr">/^(:|=)$/</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-49">#</a> </div> <p>Regex-matching-regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">REGEX_START : </span><span class="sr">/^\/[^\/ ]/</span>
|
||||
<span class="nv">REGEX_INTERPOLATION: </span><span class="sr">/([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/</span>
|
||||
<span class="nv">REGEX_FLAGS : </span><span class="sr">/^[imgy]{0,4}/</span>
|
||||
<span class="nv">REGEX_END : </span><span class="sr">/^(([imgy]{1,4})\b|\W)/</span>
|
||||
<span class="nv">REGEX_ESCAPE : </span><span class="sr">/\\[^\$]/g</span></pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-50">#</a> </div> <p>Token cleaning regexes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">JS_CLEANER : </span><span class="sr">/(^`|`$)/g</span>
|
||||
<span class="nv">MULTILINER : </span><span class="sr">/\n/g</span>
|
||||
<span class="nv">STRING_NEWLINES : </span><span class="sr">/\n[ \t]*/g</span>
|
||||
<span class="nv">COMMENT_CLEANER : </span><span class="sr">/(^[ \t]*#|\n[ \t]*$)/mg</span>
|
||||
<span class="nv">NO_NEWLINE : </span><span class="sr">/^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/</span>
|
||||
<span class="nv">HEREDOC_INDENT : </span><span class="sr">/^[ \t]+/mg</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Tokens which a regular expression will never immediately follow, but which
|
||||
<span class="nv">HEREDOC_INDENT : </span><span class="sr">/(\n+([ \t]*)|^([ \t]+))/g</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-51">#</a> </div> <p>Tokens which a regular expression will never immediately follow, but which
|
||||
a division operator might.</p>
|
||||
|
||||
<p>See: <a href='http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions'>http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</a></p>
|
||||
<p>See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions</p>
|
||||
|
||||
<p>Our list is shorter, due to sans-parentheses method calls.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">NOT_REGEX: </span><span class="p">[</span>
|
||||
<span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'++'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'NULL'</span><span class="p">,</span> <span class="s1">'TRUE'</span>
|
||||
<span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'++'</span><span class="p">,</span> <span class="s1">'--'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'NULL'</span><span class="p">,</span> <span class="s1">'TRUE'</span><span class="p">,</span> <span class="s1">']'</span>
|
||||
<span class="p">]</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-52">#</a> </div> <p>Tokens which could legitimately be invoked or indexed. A opening
|
||||
parentheses or bracket following these tokens will be recorded as the start
|
||||
of a function invocation or indexing operation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">CALLABLE: </span><span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">']'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">,</span> <span class="s1">'THIS'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-53">#</a> </div> <p>Tokens that indicate an access -- keywords immediately following will be
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>optparse.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> optparse.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||||
<!DOCTYPE html> <html> <head> <title>optparse.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> optparse.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A simple <strong>OptionParser</strong> class to parse option flags from the command-line.
|
||||
Use it like so:</p>
|
||||
|
||||
<pre><code>parser: new OptionParser switches, help_banner
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>repl.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> repl.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
|
||||
<!DOCTYPE html> <html> <head> <title>repl.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> repl.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript
|
||||
and evaluates it. Good for simple tests, or poking around the <strong>Node.js</strong> API.
|
||||
Using it looks like this:</p>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html> <html> <head> <title>rewriter.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> rewriter.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
<!DOCTYPE html> <html> <head> <title>rewriter.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> rewriter.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The CoffeeScript language has a good deal of optional syntax, implicit syntax,
|
||||
and shorthand syntax. This can greatly complicate a grammar and bloat
|
||||
the resulting parse table. Instead of making the parser handle it all, we take
|
||||
a series of passes over the token stream, using this <strong>Rewriter</strong> to convert
|
||||
shorthand into the unambiguous long form, add implicit indentation and
|
||||
parentheses, balance incorrect nestings, and generally clean things up.</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-2">#</a> </div> <p>Set up exported variables for both Node.js and the browser.</p> </td> <td class="code"> <div class="highlight"><pre><span class="k">if</span> <span class="nx">process</span><span class="o">?</span>
|
||||
<span class="nv">helpers: </span><span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">).</span><span class="nx">helpers</span>
|
||||
<span class="p">{</span><span class="nx">helpers</span><span class="p">}</span><span class="o">:</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./helpers'</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">this</span><span class="p">.</span><span class="nv">exports: </span><span class="k">this</span>
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">include: </span><span class="nx">helpers</span><span class="p">.</span><span class="nx">include</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
|
||||
<span class="nv">helpers: </span> <span class="k">this</span><span class="p">.</span><span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <p>Import the helpers we need.</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">{</span><span class="nx">include</span><span class="p">}</span><span class="o">:</span> <span class="nx">helpers</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>The <strong>Rewriter</strong> class is used by the <a href="lexer.html">Lexer</a>, directly against
|
||||
its internal array of tokens.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">exports.Rewriter: </span><span class="nx">class</span> <span class="nx">Rewriter</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Rewrite the token stream in multiple passes, one logical filter at
|
||||
a time. This could certainly be changed into a single pass through the
|
||||
stream, with a big ol' efficient switch, but it's much nicer to work with
|
||||
@@ -36,10 +36,13 @@ our feet.</p> </td> <td class="code"> <div
|
||||
correctly indented, or appear on a line of their own.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">adjust_comments: </span><span class="o">-></span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'COMMENT'</span>
|
||||
<span class="nv">after: </span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span>
|
||||
<span class="p">[</span><span class="nx">before</span><span class="p">,</span> <span class="nx">after</span><span class="p">]</span><span class="o">:</span> <span class="p">[</span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">],</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="k">if</span> <span class="nx">after</span> <span class="o">and</span> <span class="nx">after</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'INDENT'</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">after</span>
|
||||
<span class="k">if</span> <span class="nx">before</span> <span class="o">and</span> <span class="nx">before</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">post</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="nx">post</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="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">-</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">after</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">else</span> <span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'TERMINATOR'</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'INDENT'</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'OUTDENT'</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s2">"\n"</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
@@ -79,38 +82,40 @@ close.</p> </td> <td class="code"> <div cl
|
||||
Insert the implicit parentheses here, so that the parser doesn't have to
|
||||
deal with them.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add_implicit_parentheses: </span><span class="o">-></span>
|
||||
<span class="nv">stack: </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nv">calls: </span> <span class="mi">0</span>
|
||||
<span class="nv">parens: </span><span class="mi">0</span>
|
||||
<span class="nv">start_parens: </span><span class="mi">0</span>
|
||||
<span class="nv">close_calls: </span><span class="p">(</span><span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="k">for</span> <span class="nx">tmp</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_END'</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">i</span><span class="p">][</span><span class="mi">2</span><span class="p">]])</span>
|
||||
<span class="nv">size: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="mi">0</span>
|
||||
<span class="nx">size</span>
|
||||
<span class="nx">@scan_tokens</span> <span class="p">(</span><span class="nx">prev</span><span class="p">,</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">post</span><span class="p">,</span> <span class="nx">i</span><span class="p">)</span> <span class="o">=></span>
|
||||
<span class="nv">tag: </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">switch</span> <span class="nx">tag</span>
|
||||
<span class="k">when</span> <span class="s1">'CALL_START'</span> <span class="k">then</span> <span class="nv">calls: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">'CALL_END'</span> <span class="k">then</span> <span class="nv">calls: </span><span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">'('</span> <span class="k">then</span> <span class="nv">parens: </span><span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">')'</span> <span class="k">then</span> <span class="nv">parens: </span><span class="o">-</span> <span class="mi">1</span>
|
||||
<span class="k">when</span> <span class="s1">'INDENT'</span> <span class="k">then</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">when</span> <span class="s1">'OUTDENT'</span>
|
||||
<span class="nv">last: </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">last</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'OUTDENT'</span>
|
||||
<span class="nv">open: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">if</span> <span class="o">!</span><span class="nx">post</span><span class="o">?</span> <span class="o">or</span> <span class="p">(</span><span class="nx">start_parens</span> <span class="o">></span> <span class="nx">parens</span><span class="p">)</span> <span class="o">or</span> <span class="p">(</span><span class="nx">start_parens</span> <span class="o">is</span> <span class="nx">parens</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="o">and</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">IMPLICIT_BLOCK</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">token</span><span class="p">.</span><span class="nx">generated</span>
|
||||
<span class="k">if</span> <span class="nx">open</span> <span class="o">or</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span>
|
||||
<span class="nv">idx: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'OUTDENT'</span> <span class="k">then</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">i</span>
|
||||
<span class="nv">stack_pointer: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="k">then</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">1</span>
|
||||
<span class="k">for</span> <span class="nx">tmp</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">...</span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">idx</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_END'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]])</span>
|
||||
<span class="nv">size: </span><span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="nx">stack_pointer</span><span class="p">]</span><span class="o">:</span> <span class="mi">0</span>
|
||||
<span class="k">if</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">prev</span><span class="p">.</span><span class="nx">spaced</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_FUNC</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_CALL</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span> <span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">EXPRESSION_START</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="nx">include</span><span class="p">(</span><span class="nx">EXPRESSION_START</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'INDENT'</span> <span class="o">and</span> <span class="o">!</span><span class="nx">token</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="nx">open</span> <span class="o">and</span> <span class="o">not</span> <span class="p">(</span><span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_BLOCK</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
|
||||
<span class="nv">size: </span><span class="nx">close_calls</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="nx">size</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="nx">unless</span> <span class="nx">prev</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_FUNC</span><span class="p">,</span> <span class="nx">prev</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_CALL</span><span class="p">,</span> <span class="nx">tag</span><span class="p">)</span>
|
||||
<span class="nv">calls: </span><span class="mi">0</span>
|
||||
<span class="nv">start_parens: </span><span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'('</span> <span class="k">then</span> <span class="nx">parens</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">else</span> <span class="nx">parens</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'CALL_START'</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">2</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Because our grammar is LALR(1), it can't handle some single-line
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span> <span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="nx">open</span> <span class="o">and</span> <span class="o">!</span><span class="nx">token</span><span class="p">.</span><span class="nx">generated</span> <span class="o">and</span> <span class="p">(</span><span class="o">!</span><span class="nx">post</span> <span class="o">or</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">tag</span><span class="p">))</span>
|
||||
<span class="nv">j: </span><span class="mi">1</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span> <span class="k">while</span> <span class="p">(</span><span class="nv">nx: </span><span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="nx">j</span><span class="p">])</span><span class="o">?</span> <span class="o">and</span> <span class="nx">include</span><span class="p">(</span><span class="nx">IMPLICIT_END</span><span class="p">,</span> <span class="nx">nx</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
|
||||
<span class="k">if</span> <span class="nx">nx</span><span class="o">?</span> <span class="o">and</span> <span class="nx">nx</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">','</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="s1">'TERMINATOR'</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">size: </span><span class="nx">close_calls</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">EXPRESSION_END</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="k">return</span> <span class="nx">size</span>
|
||||
<span class="k">if</span> <span class="nx">tag</span> <span class="o">isnt</span> <span class="s1">'OUTDENT'</span> <span class="o">and</span> <span class="nx">include</span> <span class="nx">EXPRESSION_END</span><span class="p">,</span> <span class="nx">tag</span>
|
||||
<span class="nx">stack</span><span class="p">[</span><span class="nx">stack</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-12">#</a> </div> <p>Because our grammar is LALR(1), it can't handle some single-line
|
||||
expressions that lack ending delimiters. The <strong>Rewriter</strong> adds the implicit
|
||||
blocks, so it doesn't need to. ')' can close a single-line block,
|
||||
but we need to make sure it's balanced.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add_implicit_indentation: </span><span class="o">-></span>
|
||||
@@ -119,7 +124,9 @@ but we need to make sure it's balanced.</p> </td> <td cl
|
||||
<span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">isnt</span> <span class="s1">'INDENT'</span> <span class="o">and</span>
|
||||
<span class="o">not</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="o">is</span> <span class="s1">'ELSE'</span> <span class="o">and</span> <span class="nx">post</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="s1">'IF'</span><span class="p">)</span>
|
||||
<span class="nv">starter: </span><span class="nx">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nv">indent: </span><span class="p">[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">token</span><span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
|
||||
<span class="nv">indent.generated: </span><span class="kc">true</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">indent</span>
|
||||
<span class="nv">idx: </span><span class="nx">i</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">parens: </span><span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="kc">true</span>
|
||||
@@ -173,6 +180,8 @@ to the stack. If you see an <code>EXPRESSION_END</code>, pop the stack and repla
|
||||
it with the inverse of what we've just popped.</li>
|
||||
<li>Keep track of "debt" for tokens that we manufacture, to make sure we end
|
||||
up balanced in the end.</li>
|
||||
<li>Be careful not to alter array or parentheses delimiters with overzealous
|
||||
rewriting.</li>
|
||||
</ol> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">rewrite_closing_parens: </span><span class="o">-></span>
|
||||
<span class="nv">stack: </span><span class="p">[]</span>
|
||||
<span class="nv">debt: </span> <span class="p">{}</span>
|
||||
@@ -191,10 +200,15 @@ up balanced in the end.</li>
|
||||
<span class="k">else</span>
|
||||
<span class="nv">match: </span><span class="nx">stack</span><span class="p">.</span><span class="nx">pop</span><span class="p">()</span>
|
||||
<span class="nv">mtag: </span> <span class="nx">match</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
|
||||
<span class="nv">oppos: </span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="mi">1</span> <span class="k">if</span> <span class="nx">tag</span> <span class="o">is</span> <span class="nx">oppos</span>
|
||||
<span class="nx">debt</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span><span class="o">:</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<span class="nv">val: </span><span class="k">if</span> <span class="nx">mtag</span> <span class="o">is</span> <span class="s1">'INDENT'</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="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">]</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="nx">INVERSES</span><span class="p">[</span><span class="nx">mtag</span><span class="p">],</span> <span class="nx">val</span><span class="p">]</span>
|
||||
<span class="nv">val: </span><span class="p">[</span><span class="nx">oppos</span><span class="p">,</span> <span class="k">if</span> <span class="nx">mtag</span> <span class="o">is</span> <span class="s1">'INDENT'</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="nx">oppos</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="nx">@tokens</span><span class="p">[</span><span class="nx">i</span> <span class="o">+</span> <span class="mi">2</span><span class="p">]</span><span class="o">?</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">is</span> <span class="nx">mtag</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">val</span>
|
||||
<span class="nx">stack</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">match</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="nx">@tokens</span><span class="p">.</span><span class="nx">splice</span> <span class="nx">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">val</span>
|
||||
<span class="k">return</span> <span class="mi">1</span>
|
||||
<span class="k">else</span>
|
||||
<span class="k">return</span> <span class="mi">1</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-15">#</a> </div> <h2>Constants</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-16">#</a> </div> <p>List of the token pairs that must be balanced.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">BALANCED_PAIRS: </span><span class="p">[[</span><span class="s1">'('</span><span class="p">,</span> <span class="s1">')'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'['</span><span class="p">,</span> <span class="s1">']'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'{'</span><span class="p">,</span> <span class="s1">'}'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">],</span>
|
||||
@@ -203,11 +217,11 @@ up balanced in the end.</li>
|
||||
look things up from either end.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">INVERSES: </span><span class="p">{}</span>
|
||||
<span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span>
|
||||
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>The tokens that signal the start of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START: </span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>The tokens that signal the end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_END: </span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Tokens that indicate the close of a clause of an expression.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_CLOSE: </span><span class="p">[</span><span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_FUNC: </span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">'CALL_END'</span><span class="p">,</span> <span class="s1">']'</span><span class="p">,</span> <span class="s1">'INDEX_END'</span><span class="p">,</span> <span class="s1">'<-'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_CALL: </span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'NEW'</span><span class="p">,</span> <span class="s1">'PARAM_START'</span><span class="p">,</span>
|
||||
<span class="nx">INVERSES</span><span class="p">[</span><span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">:</span> <span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-18">#</a> </div> <p>The tokens that signal the start of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_START: </span><span class="nx">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-19">#</a> </div> <p>The tokens that signal the end of a balanced pair.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_END: </span> <span class="nx">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="nx">pair</span> <span class="k">in</span> <span class="nx">BALANCED_PAIRS</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-20">#</a> </div> <p>Tokens that indicate the close of a clause of an expression.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">EXPRESSION_CLOSE: </span><span class="p">[</span><span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'WHEN'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-21">#</a> </div> <p>Tokens that, if followed by an <code>IMPLICIT_CALL</code>, indicate a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_FUNC: </span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'SUPER'</span><span class="p">,</span> <span class="s1">')'</span><span class="p">,</span> <span class="s1">'CALL_END'</span><span class="p">,</span> <span class="s1">']'</span><span class="p">,</span> <span class="s1">'INDEX_END'</span><span class="p">,</span> <span class="s1">'<-'</span><span class="p">,</span> <span class="s1">'@'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-22">#</a> </div> <p>If preceded by an <code>IMPLICIT_FUNC</code>, indicates a function invocation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_CALL: </span> <span class="p">[</span><span class="s1">'IDENTIFIER'</span><span class="p">,</span> <span class="s1">'NUMBER'</span><span class="p">,</span> <span class="s1">'STRING'</span><span class="p">,</span> <span class="s1">'JS'</span><span class="p">,</span> <span class="s1">'REGEX'</span><span class="p">,</span> <span class="s1">'NEW'</span><span class="p">,</span> <span class="s1">'PARAM_START'</span><span class="p">,</span>
|
||||
<span class="s1">'TRY'</span><span class="p">,</span> <span class="s1">'DELETE'</span><span class="p">,</span> <span class="s1">'TYPEOF'</span><span class="p">,</span> <span class="s1">'SWITCH'</span><span class="p">,</span> <span class="s1">'EXTENSION'</span><span class="p">,</span>
|
||||
<span class="s1">'TRUE'</span><span class="p">,</span> <span class="s1">'FALSE'</span><span class="p">,</span> <span class="s1">'YES'</span><span class="p">,</span> <span class="s1">'NO'</span><span class="p">,</span> <span class="s1">'ON'</span><span class="p">,</span> <span class="s1">'OFF'</span><span class="p">,</span> <span class="s1">'!'</span><span class="p">,</span> <span class="s1">'!!'</span><span class="p">,</span> <span class="s1">'NOT'</span><span class="p">,</span>
|
||||
<span class="s1">'THIS'</span><span class="p">,</span> <span class="s1">'NULL'</span><span class="p">,</span>
|
||||
<span class="s1">'@'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK: </span><span class="p">[</span><span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">','</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END: </span> <span class="p">[</span><span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
|
||||
<span class="s1">'@'</span><span class="p">,</span> <span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">'('</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-23">#</a> </div> <p>Tokens indicating that the implicit call must enclose a block of expressions.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_BLOCK: </span><span class="p">[</span><span class="s1">'->'</span><span class="p">,</span> <span class="s1">'=>'</span><span class="p">,</span> <span class="s1">'{'</span><span class="p">,</span> <span class="s1">'['</span><span class="p">,</span> <span class="s1">','</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-24">#</a> </div> <p>Tokens that always mark the end of an implicit call for single-liners.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">IMPLICIT_END: </span> <span class="p">[</span><span class="s1">'IF'</span><span class="p">,</span> <span class="s1">'UNLESS'</span><span class="p">,</span> <span class="s1">'FOR'</span><span class="p">,</span> <span class="s1">'WHILE'</span><span class="p">,</span> <span class="s1">'UNTIL'</span><span class="p">,</span> <span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'INDENT'</span><span class="p">].</span><span class="nx">concat</span> <span class="nx">EXPRESSION_END</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-25">#</a> </div> <p>Single-line flavors of block expressions that have unclosed endings.
|
||||
The grammar can't disambiguate them, so we insert the implicit indentation.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">SINGLE_LINERS: </span><span class="p">[</span><span class="s1">'ELSE'</span><span class="p">,</span> <span class="s2">"->"</span><span class="p">,</span> <span class="s2">"=>"</span><span class="p">,</span> <span class="s1">'TRY'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">,</span> <span class="s1">'THEN'</span><span class="p">]</span>
|
||||
<span class="nv">SINGLE_CLOSERS: </span><span class="p">[</span><span class="s1">'TERMINATOR'</span><span class="p">,</span> <span class="s1">'CATCH'</span><span class="p">,</span> <span class="s1">'FINALLY'</span><span class="p">,</span> <span class="s1">'ELSE'</span><span class="p">,</span> <span class="s1">'OUTDENT'</span><span class="p">,</span> <span class="s1">'LEADING_WHEN'</span><span class="p">]</span>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html> <html> <head> <title>scope.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> scope.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <strong>Scope</strong> class regulates lexical scoping within CoffeeScript. As you
|
||||
<!DOCTYPE html> <html> <head> <title>scope.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <div id="jump_to"> Jump To … <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="cake.html"> cake.coffee </a> <a class="source" href="coffee-script.html"> coffee-script.coffee </a> <a class="source" href="command.html"> command.coffee </a> <a class="source" href="grammar.html"> grammar.coffee </a> <a class="source" href="helpers.html"> helpers.coffee </a> <a class="source" href="index.html"> index.coffee </a> <a class="source" href="lexer.html"> lexer.coffee </a> <a class="source" href="nodes.html"> nodes.coffee </a> <a class="source" href="optparse.html"> optparse.coffee </a> <a class="source" href="repl.html"> repl.coffee </a> <a class="source" href="rewriter.html"> rewriter.coffee </a> <a class="source" href="scope.html"> scope.coffee </a> </div> </div> </div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> scope.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-1">#</a> </div> <p>The <strong>Scope</strong> class regulates lexical scoping within CoffeeScript. As you
|
||||
generate code, you create a tree of scopes in the same shape as the nested
|
||||
function bodies. Each scope knows about the variables declared within it,
|
||||
and has a reference to its parent enclosing scope. In this way, we know which
|
||||
|
||||
@@ -7,7 +7,7 @@ Portions of Underscore are inspired by or borrowed from
|
||||
<a href="http://osteele.com">Functional</a>, and John Resig's
|
||||
<a href="http://ejohn.com">Micro-Templating</a>.
|
||||
For all details and documentation:
|
||||
<a href='http://documentcloud.github.com/underscore/'>http://documentcloud.github.com/underscore/</a></p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <h2>Baseline setup</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Establish the root object, <code>window</code> in the browser, or <code>global</code> on the server.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root: </span><span class="k">this</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Save the previous value of the <code>_</code> variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">previousUnderscore: </span><span class="nx">root</span><span class="p">.</span><span class="nx">_</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Establish the object that gets thrown to break out of a loop iteration.
|
||||
http://documentcloud.github.com/underscore/</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-3">#</a> </div> <h2>Baseline setup</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-4">#</a> </div> <p>Establish the root object, <code>window</code> in the browser, or <code>global</code> on the server.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">root: </span><span class="k">this</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-5">#</a> </div> <p>Save the previous value of the <code>_</code> variable.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">previousUnderscore: </span><span class="nx">root</span><span class="p">.</span><span class="nx">_</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-6">#</a> </div> <p>Establish the object that gets thrown to break out of a loop iteration.
|
||||
<code>StopIteration</code> is SOP on Mozilla.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">breaker: </span><span class="k">if</span> <span class="k">typeof</span><span class="p">(</span><span class="nx">StopIteration</span><span class="p">)</span> <span class="o">is</span> <span class="s1">'undefined'</span> <span class="k">then</span> <span class="s1">'__break__'</span> <span class="k">else</span> <span class="nx">StopIteration</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-7">#</a> </div> <p>Helper function to escape <strong>RegExp</strong> contents, because JS doesn't have one.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">escapeRegExp: </span><span class="p">(</span><span class="nx">string</span><span class="p">)</span> <span class="o">-></span> <span class="nx">string</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/([.*+?^${}()|[\]\/\\])/g</span><span class="p">,</span> <span class="s1">'\\$1'</span><span class="p">)</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-8">#</a> </div> <p>Save bytes in the minified (but not gzipped) version:</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">ArrayProto: </span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span>
|
||||
<span class="nv">ObjProto: </span> <span class="nb">Object</span><span class="p">.</span><span class="nx">prototype</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="octowrap"> <a class="octothorpe" href="#section-9">#</a> </div> <p>Create quick reference variables for speed access to core prototypes.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">slice: </span> <span class="nx">ArrayProto</span><span class="p">.</span><span class="nx">slice</span>
|
||||
<span class="nv">unshift: </span> <span class="nx">ArrayProto</span><span class="p">.</span><span class="nx">unshift</span>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a>
|
||||
<a href="#aliases">Aliases</a>
|
||||
<a href="#splats">Splats...</a>
|
||||
<a href="#while">While Loops</a>
|
||||
<a href="#while">While & Until Loops</a>
|
||||
<a href="#comprehensions">Comprehensions (Arrays, Objects, and Ranges)</a>
|
||||
<a href="#slice_splice">Array Slicing and Splicing with Ranges</a>
|
||||
<a href="#expressions">Everything is an Expression</a>
|
||||
@@ -130,7 +130,7 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/0.6.1">0.6.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/0.6.2">0.6.2</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -176,7 +176,7 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
Then clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download the latest
|
||||
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.6.1">0.6.1</a>.
|
||||
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.6.2">0.6.2</a>.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
@@ -483,7 +483,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
|
||||
<p>
|
||||
<span id="while" class="bookmark"></span>
|
||||
<b class="header">While Loops</b>
|
||||
<b class="header">While & Until Loops</b>
|
||||
The only low-level loop that CoffeeScript provides is the <b>while</b> loop. The
|
||||
main difference from JavaScript is that the <b>while</b> loop can be used
|
||||
as an expression, returning an array containing the result of each iteration
|
||||
@@ -491,6 +491,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
</p>
|
||||
<%= code_for('while', 'lyrics.join("\n")') %>
|
||||
<p>
|
||||
For readability, the <b>until</b> loop serves as an inverted <b>while</b> loop.
|
||||
Other JavaScript loops, such as <b>for</b> loops and <b>do-while</b> loops
|
||||
can be mimicked by variations on <b>while</b>, but the hope is that you
|
||||
won't need to do that with CoffeeScript, either because you're using
|
||||
@@ -665,7 +666,7 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
Pattern matching can be used with any depth of array and object nesting,
|
||||
to help pull out deeply nested properties.
|
||||
</p>
|
||||
<%= code_for('object_extraction', 'poet + " — " + street') %>
|
||||
<%= code_for('object_extraction', 'name + " — " + street') %>
|
||||
<p>
|
||||
Pattern matching can even be combined with splats.
|
||||
</p>
|
||||
@@ -858,6 +859,11 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
|
||||
— A Java Library that uses Rhino to compile CoffeeScript, allowing
|
||||
compilation within Java projects or on systems that Node.js doesn't support.
|
||||
</li>
|
||||
<li>
|
||||
<b>defunkt</b>'s <a href="http://github.com/defunkt/coffee-mode">CoffeeScript Major Mode</a>
|
||||
— a Emacs major mode that provides syntax highlighting, indentation
|
||||
@@ -872,6 +878,10 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<b>kchmck</b>'s <a href="http://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a>
|
||||
— which adds Vim syntax highlighting and indentation support.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
@@ -882,6 +892,11 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
— a plugin that serves and bundles CoffeeScript from within your
|
||||
Rails application.
|
||||
</li>
|
||||
<li>
|
||||
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
|
||||
— a BistroCar alternative that integrates well with
|
||||
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
|
||||
</li>
|
||||
<li>
|
||||
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
|
||||
— a custom filter for rendering CoffeeScript inline within
|
||||
@@ -908,7 +923,22 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<span id="change_log" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.2</b>
|
||||
The <tt>coffee</tt> command will now preserve directory structure when
|
||||
compiling a directory full of scripts. Fixed two omissions that were preventing
|
||||
the CoffeeScript compiler from running live within Internet Explorer.
|
||||
There's now a syntax for block comments, similar in spirit to CoffeeScript's heredocs.
|
||||
ECMA Harmony DRY-style pattern matching is now supported, where the name
|
||||
of the property is the same as the name of the value: <tt>{name, length}: func</tt>.
|
||||
Pattern matching is now allowed within comprehension variables. <tt>unless</tt>
|
||||
is now allowed in block form. <tt>until</tt> loops were added, as the inverse
|
||||
of <tt>while</tt> loops. <tt>switch</tt> statements are now allowed without
|
||||
switch object clauses. Compatible
|
||||
with Node.js <b>v0.1.95</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.1</b>
|
||||
Upgraded CoffeeScript for compatibility with the new Node.js <b>v0.1.90</b>
|
||||
|
||||
@@ -7,28 +7,31 @@
|
||||
child.prototype = new ctor();
|
||||
child.prototype.constructor = child;
|
||||
};
|
||||
Animal = function Animal() { };
|
||||
Animal.prototype.move = function move(meters) {
|
||||
Animal = function() { };
|
||||
Animal.prototype.move = function(meters) {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
};
|
||||
Snake = function Snake(name) {
|
||||
|
||||
Snake = function(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
};
|
||||
__extends(Snake, Animal);
|
||||
Snake.prototype.move = function move() {
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return Snake.__superClass__.move.call(this, 5);
|
||||
};
|
||||
Horse = function Horse(name) {
|
||||
|
||||
Horse = function(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
};
|
||||
__extends(Horse, Animal);
|
||||
Horse.prototype.move = function move() {
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return Horse.__superClass__.move.call(this, 45);
|
||||
};
|
||||
|
||||
sam = new Snake("Sammy the Python");
|
||||
tom = new Horse("Tommy the Palomino");
|
||||
sam.move();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(function(){
|
||||
var eldest, grade;
|
||||
grade = function grade(student) {
|
||||
grade = function(student) {
|
||||
if (student.excellent_work) {
|
||||
return "A+";
|
||||
} else if (student.okay_stuff) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
||||
};
|
||||
};
|
||||
Account = function Account(customer, cart) {
|
||||
Account = function(customer, cart) {
|
||||
this.customer = customer;
|
||||
this.cart = cart;
|
||||
return $('.shopping_cart').bind('click', __bind(function(event) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(function(){
|
||||
var cube, square;
|
||||
square = function square(x) {
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
cube = function cube(x) {
|
||||
cube = function(x) {
|
||||
return square(x) * x;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(function(){
|
||||
var _a, city, forecast, temp, weather_report;
|
||||
weather_report = function weather_report(location) {
|
||||
weather_report = function(location) {
|
||||
// Make an Ajax request to fetch the weather...
|
||||
return [location, 72, "Mostly Sunny"];
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var _a, _b, _c, city, futurists, poet, street;
|
||||
var _a, _b, _c, city, futurists, name, street;
|
||||
futurists = {
|
||||
sculptor: "Umberto Boccioni",
|
||||
painter: "Vladimir Burliuk",
|
||||
@@ -10,7 +10,7 @@
|
||||
};
|
||||
_a = futurists;
|
||||
_b = _a.poet;
|
||||
poet = _b.name;
|
||||
name = _b.name;
|
||||
_c = _b.address;
|
||||
street = _c[0];
|
||||
city = _c[1];
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
number = -42;
|
||||
}
|
||||
// Functions:
|
||||
square = function square(x) {
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
// Arrays:
|
||||
@@ -18,14 +18,15 @@
|
||||
math = {
|
||||
root: Math.sqrt,
|
||||
square: square,
|
||||
cube: function cube(x) {
|
||||
cube: function(x) {
|
||||
return x * square(x);
|
||||
}
|
||||
};
|
||||
// Splats:
|
||||
race = function race(winner) {
|
||||
race = function(winner) {
|
||||
var runners;
|
||||
runners = __slice.call(arguments, 1, arguments.length - 0);
|
||||
var _a = arguments.length, _b = _a >= 2;
|
||||
runners = __slice.call(arguments, 1, _a - 0);
|
||||
return print(winner, runners);
|
||||
};
|
||||
// Existence:
|
||||
|
||||
2
documentation/js/prototypes.js
vendored
2
documentation/js/prototypes.js
vendored
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
String.prototype.dasherize = function dasherize() {
|
||||
String.prototype.dasherize = function() {
|
||||
return this.replace(/_/g, "-");
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
(function(){
|
||||
var _a, _b, _c, _d, countdown, egg_delivery, num;
|
||||
var _a, _b, _c, countdown, egg_delivery, num;
|
||||
countdown = (function() {
|
||||
_a = []; _c = 10; _d = 1;
|
||||
for (_b = 0, num = _c; (_c <= _d ? num <= _d : num >= _d); (_c <= _d ? num += 1 : num -= 1), _b++) {
|
||||
_a = []; _b = 10; _c = 1;
|
||||
for (num = _b; (_b <= _c ? num <= _c : num >= _c); (_b <= _c ? num += 1 : num -= 1)) {
|
||||
_a.push(num);
|
||||
}
|
||||
return _a;
|
||||
})();
|
||||
egg_delivery = function egg_delivery() {
|
||||
var _e, _f, _g, _h, dozen_eggs, i;
|
||||
_e = []; _g = 0; _h = eggs.length;
|
||||
for (_f = 0, i = _g; (_g <= _h ? i < _h : i > _h); (_g <= _h ? i += 12 : i -= 12), _f++) {
|
||||
_e.push((function() {
|
||||
egg_delivery = function() {
|
||||
var _d, _e, _f, dozen_eggs, i;
|
||||
_d = []; _e = 0; _f = eggs.length;
|
||||
for (i = _e; (_e <= _f ? i < _f : i > _f); (_e <= _f ? i += 12 : i -= 12)) {
|
||||
_d.push((function() {
|
||||
dozen_eggs = eggs.slice(i, i + 12);
|
||||
return deliver(new egg_carton(dozen));
|
||||
})());
|
||||
}
|
||||
return _e;
|
||||
return _d;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function(){
|
||||
var change_numbers, new_num, num;
|
||||
num = 1;
|
||||
change_numbers = function change_numbers() {
|
||||
change_numbers = function() {
|
||||
var new_num;
|
||||
new_num = -1;
|
||||
num = 10;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(function(){
|
||||
var _a;
|
||||
(_a = lottery.draw_winner()) == undefined ? undefined : _a.address == undefined ? undefined : _a.address.zipcode;
|
||||
typeof (_a = (lottery.draw_winner())) === "undefined" || _a == undefined ? undefined : _a.address == undefined ? undefined : _a.address.zipcode;
|
||||
})();
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
var award_medals, contenders, gold, silver, the_field;
|
||||
var __slice = Array.prototype.slice;
|
||||
gold = (silver = (the_field = "unknown"));
|
||||
award_medals = function award_medals(first, second) {
|
||||
award_medals = function(first, second) {
|
||||
var rest;
|
||||
rest = __slice.call(arguments, 2, arguments.length - 0);
|
||||
var _a = arguments.length, _b = _a >= 3;
|
||||
rest = __slice.call(arguments, 2, _a - 0);
|
||||
gold = first;
|
||||
silver = second;
|
||||
the_field = rest;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
}
|
||||
while (supply < demand) {
|
||||
while (!(supply > demand)) {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
182
index.html
182
index.html
@@ -32,7 +32,7 @@
|
||||
<a href="#conditionals">Conditionals, Ternaries, and Conditional Assignment</a>
|
||||
<a href="#aliases">Aliases</a>
|
||||
<a href="#splats">Splats...</a>
|
||||
<a href="#while">While Loops</a>
|
||||
<a href="#while">While & Until Loops</a>
|
||||
<a href="#comprehensions">Comprehensions (Arrays, Objects, and Ranges)</a>
|
||||
<a href="#slice_splice">Array Slicing and Splicing with Ranges</a>
|
||||
<a href="#expressions">Everything is an Expression</a>
|
||||
@@ -116,7 +116,7 @@ alert reverse '.eeffoC yrT'</textarea></div>
|
||||
|
||||
<p>
|
||||
<b>Latest Version:</b>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/0.6.1">0.6.1</a>
|
||||
<a href="http://github.com/jashkenas/coffee-script/tarball/0.6.2">0.6.2</a>
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
@@ -165,7 +165,7 @@ opposite_day <span class="Keyword">=</span> <span class="BuiltInConstant">true</
|
||||
number <span class="Keyword">=</span> <span class="Keyword">-</span><span class="Number">42</span>;
|
||||
}
|
||||
<span class="Comment"><span class="Comment">//</span> Functions:</span>
|
||||
square <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">square</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="FunctionName">square</span> = <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="Keyword">return</span> x <span class="Keyword">*</span> x;
|
||||
};
|
||||
<span class="Comment"><span class="Comment">//</span> Arrays:</span>
|
||||
@@ -174,14 +174,15 @@ list <span class="Keyword">=</span> [<span class="Number">1</span>, <span class=
|
||||
math <span class="Keyword">=</span> {
|
||||
root: <span class="LibraryClassType">Math</span>.sqrt,
|
||||
square: square,
|
||||
cube: <span class="Storage">function</span> <span class="FunctionName">cube</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="FunctionName">cube</span>: <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="Keyword">return</span> x <span class="Keyword">*</span> square(x);
|
||||
}
|
||||
};
|
||||
<span class="Comment"><span class="Comment">//</span> Splats:</span>
|
||||
race <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">race</span>(<span class="FunctionArgument">winner</span>) {
|
||||
<span class="FunctionName">race</span> = <span class="Storage">function</span>(<span class="FunctionArgument">winner</span>) {
|
||||
<span class="Storage">var</span> runners;
|
||||
runners <span class="Keyword">=</span> __slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">1</span>, arguments.<span class="LibraryConstant">length</span> <span class="Keyword">-</span> <span class="Number">0</span>);
|
||||
<span class="Storage">var</span> _a <span class="Keyword">=</span> arguments.<span class="LibraryConstant">length</span>, _b <span class="Keyword">=</span> _a <span class="Keyword">>=</span> <span class="Number">2</span>;
|
||||
runners <span class="Keyword">=</span> __slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">1</span>, _a <span class="Keyword">-</span> <span class="Number">0</span>);
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">print</span>(winner, runners);
|
||||
};
|
||||
<span class="Comment"><span class="Comment">//</span> Existence:</span>
|
||||
@@ -207,7 +208,7 @@ if (opposite_day) {
|
||||
number = -42;
|
||||
}
|
||||
// Functions:
|
||||
square = function square(x) {
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
// Arrays:
|
||||
@@ -216,14 +217,15 @@ list = [1, 2, 3, 4, 5];
|
||||
math = {
|
||||
root: Math.sqrt,
|
||||
square: square,
|
||||
cube: function cube(x) {
|
||||
cube: function(x) {
|
||||
return x * square(x);
|
||||
}
|
||||
};
|
||||
// Splats:
|
||||
race = function race(winner) {
|
||||
race = function(winner) {
|
||||
var runners;
|
||||
runners = __slice.call(arguments, 1, arguments.length - 0);
|
||||
var _a = arguments.length, _b = _a >= 2;
|
||||
runners = __slice.call(arguments, 1, _a - 0);
|
||||
return print(winner, runners);
|
||||
};
|
||||
// Existence:
|
||||
@@ -275,7 +277,7 @@ cubed_list = (function() {
|
||||
Then clone the CoffeeScript
|
||||
<a href="http://github.com/jashkenas/coffee-script">source repository</a>
|
||||
from GitHub, or download the latest
|
||||
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.6.1">0.6.1</a>.
|
||||
release: <a href="http://github.com/jashkenas/coffee-script/tarball/0.6.2">0.6.2</a>.
|
||||
To install the CoffeeScript compiler system-wide
|
||||
under <tt>/usr/local</tt>, open the directory and run:
|
||||
</p>
|
||||
@@ -450,17 +452,17 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
|
||||
<div class='code'><pre class="idle"><span class="FunctionName">square</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">x</span><span class="FunctionArgument">)</span> <span class="Storage">-></span> x <span class="Keyword">*</span> x
|
||||
<span class="FunctionName">cube</span><span class="Keyword">:</span> <span class="FunctionArgument">(</span><span class="FunctionArgument">x</span><span class="FunctionArgument">)</span> <span class="Storage">-></span> square(x) <span class="Keyword">*</span> x
|
||||
</pre><pre class="idle"><span class="Storage">var</span> cube, square;
|
||||
square <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">square</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="FunctionName">square</span> = <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="Keyword">return</span> x <span class="Keyword">*</span> x;
|
||||
};
|
||||
cube <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">cube</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="FunctionName">cube</span> = <span class="Storage">function</span>(<span class="FunctionArgument">x</span>) {
|
||||
<span class="Keyword">return</span> square(x) <span class="Keyword">*</span> x;
|
||||
};
|
||||
</pre><button onclick='javascript: var cube, square;
|
||||
square = function square(x) {
|
||||
square = function(x) {
|
||||
return x * x;
|
||||
};
|
||||
cube = function cube(x) {
|
||||
cube = function(x) {
|
||||
return square(x) * x;
|
||||
};
|
||||
;alert(cube(5));'>run: cube(5)</button><br class='clear' /></div>
|
||||
@@ -546,7 +548,7 @@ matrix = [1, 0, 1, 0, 0, 1, 1, 1, 0];
|
||||
new_num<span class="Keyword">:</span> change_numbers()
|
||||
</pre><pre class="idle"><span class="Storage">var</span> change_numbers, new_num, num;
|
||||
num <span class="Keyword">=</span> <span class="Number">1</span>;
|
||||
change_numbers <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">change_numbers</span>() {
|
||||
<span class="FunctionName">change_numbers</span> = <span class="Storage">function</span>() {
|
||||
<span class="Storage">var</span> new_num;
|
||||
new_num <span class="Keyword">=</span> <span class="Keyword">-</span><span class="Number">1</span>;
|
||||
num <span class="Keyword">=</span> <span class="Number">10</span>;
|
||||
@@ -555,7 +557,7 @@ change_numbers <span class="Keyword">=</span> <span class="Storage">function</sp
|
||||
new_num <span class="Keyword">=</span> change_numbers();
|
||||
</pre><button onclick='javascript: var change_numbers, new_num, num;
|
||||
num = 1;
|
||||
change_numbers = function change_numbers() {
|
||||
change_numbers = function() {
|
||||
var new_num;
|
||||
new_num = -1;
|
||||
num = 10;
|
||||
@@ -722,9 +724,10 @@ alert <span class="String"><span class="String">"</span>The Field: <span cl
|
||||
</pre><pre class="idle"><span class="Storage">var</span> award_medals, contenders, gold, silver, the_field;
|
||||
<span class="Storage">var</span> __slice <span class="Keyword">=</span> <span class="LibraryClassType">Array</span>.<span class="LibraryConstant">prototype</span>.slice;
|
||||
gold <span class="Keyword">=</span> (silver <span class="Keyword">=</span> (the_field <span class="Keyword">=</span> <span class="String"><span class="String">"</span>unknown<span class="String">"</span></span>));
|
||||
award_medals <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">award_medals</span>(<span class="FunctionArgument">first, second</span>) {
|
||||
<span class="FunctionName">award_medals</span> = <span class="Storage">function</span>(<span class="FunctionArgument">first, second</span>) {
|
||||
<span class="Storage">var</span> rest;
|
||||
rest <span class="Keyword">=</span> __slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">2</span>, arguments.<span class="LibraryConstant">length</span> <span class="Keyword">-</span> <span class="Number">0</span>);
|
||||
<span class="Storage">var</span> _a <span class="Keyword">=</span> arguments.<span class="LibraryConstant">length</span>, _b <span class="Keyword">=</span> _a <span class="Keyword">>=</span> <span class="Number">3</span>;
|
||||
rest <span class="Keyword">=</span> __slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">2</span>, _a <span class="Keyword">-</span> <span class="Number">0</span>);
|
||||
gold <span class="Keyword">=</span> first;
|
||||
silver <span class="Keyword">=</span> second;
|
||||
the_field <span class="Keyword">=</span> rest;
|
||||
@@ -738,9 +741,10 @@ award_medals.<span class="LibraryFunction">apply</span>(<span class="Variable">t
|
||||
</pre><button onclick='javascript: var award_medals, contenders, gold, silver, the_field;
|
||||
var __slice = Array.prototype.slice;
|
||||
gold = (silver = (the_field = "unknown"));
|
||||
award_medals = function award_medals(first, second) {
|
||||
award_medals = function(first, second) {
|
||||
var rest;
|
||||
rest = __slice.call(arguments, 2, arguments.length - 0);
|
||||
var _a = arguments.length, _b = _a >= 3;
|
||||
rest = __slice.call(arguments, 2, _a - 0);
|
||||
gold = first;
|
||||
silver = second;
|
||||
the_field = rest;
|
||||
@@ -755,7 +759,7 @@ alert("The Field: " + the_field);
|
||||
|
||||
<p>
|
||||
<span id="while" class="bookmark"></span>
|
||||
<b class="header">While Loops</b>
|
||||
<b class="header">While & Until Loops</b>
|
||||
The only low-level loop that CoffeeScript provides is the <b>while</b> loop. The
|
||||
main difference from JavaScript is that the <b>while</b> loop can be used
|
||||
as an expression, returning an array containing the result of each iteration
|
||||
@@ -763,8 +767,8 @@ alert("The Field: " + the_field);
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="Comment"><span class="Comment">#</span> Econ 101</span>
|
||||
<span class="Keyword">if</span> <span class="Variable">this</span>.studying_economics
|
||||
<span class="Keyword">while</span> supply <span class="Keyword">></span> demand <span class="Keyword">then</span> buy()
|
||||
<span class="Keyword">while</span> supply <span class="Keyword"><</span> demand <span class="Keyword">then</span> sell()
|
||||
buy() <span class="Keyword">while</span> supply <span class="Keyword">></span> demand
|
||||
sell() <span class="Keyword">until</span> supply <span class="Keyword">></span> demand
|
||||
|
||||
<span class="Comment"><span class="Comment">#</span> Nursery Rhyme</span>
|
||||
num<span class="Keyword">:</span> <span class="Number">6</span>
|
||||
@@ -777,7 +781,7 @@ lyrics<span class="Keyword">:</span> <span class="Keyword">while</span> num <spa
|
||||
<span class="Keyword">while</span> (supply <span class="Keyword">></span> demand) {
|
||||
buy();
|
||||
}
|
||||
<span class="Keyword">while</span> (supply <span class="Keyword"><</span> demand) {
|
||||
<span class="Keyword">while</span> (<span class="Keyword">!</span>(supply <span class="Keyword">></span> demand)) {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
@@ -797,7 +801,7 @@ if (this.studying_economics) {
|
||||
while (supply > demand) {
|
||||
buy();
|
||||
}
|
||||
while (supply < demand) {
|
||||
while (!(supply > demand)) {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
@@ -813,6 +817,7 @@ One fell out and bumped his head.");
|
||||
})();
|
||||
;alert(lyrics.join("\n"));'>run: lyrics.join("\n")</button><br class='clear' /></div>
|
||||
<p>
|
||||
For readability, the <b>until</b> loop serves as an inverted <b>while</b> loop.
|
||||
Other JavaScript loops, such as <b>for</b> loops and <b>do-while</b> loops
|
||||
can be mimicked by variations on <b>while</b>, but the hope is that you
|
||||
won't need to do that with CoffeeScript, either because you're using
|
||||
@@ -873,43 +878,43 @@ _f <span class="Keyword">=</span> asteroids;
|
||||
<span class="Keyword">for</span> i <span class="Keyword">in</span> [<span class="Number">0</span>...eggs.length] <span class="Keyword">by</span> <span class="Number">12</span>
|
||||
dozen_eggs<span class="Keyword">:</span> eggs[i...i<span class="Keyword">+</span><span class="Number">12</span>]
|
||||
deliver <span class="Keyword">new</span> <span class="TypeName">egg_carton</span>(dozen)
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _a, _b, _c, _d, countdown, egg_delivery, num;
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _a, _b, _c, countdown, egg_delivery, num;
|
||||
countdown <span class="Keyword">=</span> (<span class="Storage">function</span>() {
|
||||
_a <span class="Keyword">=</span> []; _c <span class="Keyword">=</span> <span class="Number">10</span>; _d <span class="Keyword">=</span> <span class="Number">1</span>;
|
||||
<span class="Keyword">for</span> (_b <span class="Keyword">=</span> <span class="Number">0</span>, num <span class="Keyword">=</span> _c; (_c <span class="Keyword"><=</span> _d ? num <span class="Keyword"><=</span> _d : num <span class="Keyword">>=</span> _d); (_c <span class="Keyword"><=</span> _d ? num <span class="Keyword">+</span><span class="Keyword">=</span> <span class="Number">1</span> : num <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">1</span>), _b<span class="Keyword">++</span>) {
|
||||
_a <span class="Keyword">=</span> []; _b <span class="Keyword">=</span> <span class="Number">10</span>; _c <span class="Keyword">=</span> <span class="Number">1</span>;
|
||||
<span class="Keyword">for</span> (num <span class="Keyword">=</span> _b; (_b <span class="Keyword"><=</span> _c ? num <span class="Keyword"><=</span> _c : num <span class="Keyword">>=</span> _c); (_b <span class="Keyword"><=</span> _c ? num <span class="Keyword">+</span><span class="Keyword">=</span> <span class="Number">1</span> : num <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">1</span>)) {
|
||||
_a.<span class="LibraryFunction">push</span>(num);
|
||||
}
|
||||
<span class="Keyword">return</span> _a;
|
||||
})();
|
||||
egg_delivery <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">egg_delivery</span>() {
|
||||
<span class="Storage">var</span> _e, _f, _g, _h, dozen_eggs, i;
|
||||
_e <span class="Keyword">=</span> []; _g <span class="Keyword">=</span> <span class="Number">0</span>; _h <span class="Keyword">=</span> eggs.<span class="LibraryConstant">length</span>;
|
||||
<span class="Keyword">for</span> (_f <span class="Keyword">=</span> <span class="Number">0</span>, i <span class="Keyword">=</span> _g; (_g <span class="Keyword"><=</span> _h ? i <span class="Keyword"><</span> _h : i <span class="Keyword">></span> _h); (_g <span class="Keyword"><=</span> _h ? i <span class="Keyword">+</span><span class="Keyword">=</span> <span class="Number">12</span> : i <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">12</span>), _f<span class="Keyword">++</span>) {
|
||||
_e.<span class="LibraryFunction">push</span>((<span class="Storage">function</span>() {
|
||||
<span class="FunctionName">egg_delivery</span> = <span class="Storage">function</span>() {
|
||||
<span class="Storage">var</span> _d, _e, _f, dozen_eggs, i;
|
||||
_d <span class="Keyword">=</span> []; _e <span class="Keyword">=</span> <span class="Number">0</span>; _f <span class="Keyword">=</span> eggs.<span class="LibraryConstant">length</span>;
|
||||
<span class="Keyword">for</span> (i <span class="Keyword">=</span> _e; (_e <span class="Keyword"><=</span> _f ? i <span class="Keyword"><</span> _f : i <span class="Keyword">></span> _f); (_e <span class="Keyword"><=</span> _f ? i <span class="Keyword">+</span><span class="Keyword">=</span> <span class="Number">12</span> : i <span class="Keyword">-</span><span class="Keyword">=</span> <span class="Number">12</span>)) {
|
||||
_d.<span class="LibraryFunction">push</span>((<span class="Storage">function</span>() {
|
||||
dozen_eggs <span class="Keyword">=</span> eggs.<span class="LibraryFunction">slice</span>(i, i <span class="Keyword">+</span> <span class="Number">12</span>);
|
||||
<span class="Keyword">return</span> deliver(<span class="Keyword">new</span> <span class="TypeName">egg_carton</span>(dozen));
|
||||
})());
|
||||
}
|
||||
<span class="Keyword">return</span> _e;
|
||||
<span class="Keyword">return</span> _d;
|
||||
};
|
||||
</pre><button onclick='javascript: var _a, _b, _c, _d, countdown, egg_delivery, num;
|
||||
</pre><button onclick='javascript: var _a, _b, _c, countdown, egg_delivery, num;
|
||||
countdown = (function() {
|
||||
_a = []; _c = 10; _d = 1;
|
||||
for (_b = 0, num = _c; (_c <= _d ? num <= _d : num >= _d); (_c <= _d ? num += 1 : num -= 1), _b++) {
|
||||
_a = []; _b = 10; _c = 1;
|
||||
for (num = _b; (_b <= _c ? num <= _c : num >= _c); (_b <= _c ? num += 1 : num -= 1)) {
|
||||
_a.push(num);
|
||||
}
|
||||
return _a;
|
||||
})();
|
||||
egg_delivery = function egg_delivery() {
|
||||
var _e, _f, _g, _h, dozen_eggs, i;
|
||||
_e = []; _g = 0; _h = eggs.length;
|
||||
for (_f = 0, i = _g; (_g <= _h ? i < _h : i > _h); (_g <= _h ? i += 12 : i -= 12), _f++) {
|
||||
_e.push((function() {
|
||||
egg_delivery = function() {
|
||||
var _d, _e, _f, dozen_eggs, i;
|
||||
_d = []; _e = 0; _f = eggs.length;
|
||||
for (i = _e; (_e <= _f ? i < _f : i > _f); (_e <= _f ? i += 12 : i -= 12)) {
|
||||
_d.push((function() {
|
||||
dozen_eggs = eggs.slice(i, i + 12);
|
||||
return deliver(new egg_carton(dozen));
|
||||
})());
|
||||
}
|
||||
return _e;
|
||||
return _d;
|
||||
};
|
||||
;alert(countdown);'>run: countdown</button><br class='clear' /></div>
|
||||
<p>
|
||||
@@ -1015,7 +1020,7 @@ numbers.splice.apply(numbers, [3, 6 - 3 + 1].concat([-3, -4, -5, -6]));
|
||||
|
||||
eldest<span class="Keyword">:</span> <span class="Keyword">if</span> <span class="Number">24</span> <span class="Keyword">></span> <span class="Number">21</span> <span class="Keyword">then</span> <span class="String"><span class="String">"</span>Liz<span class="String">"</span></span> <span class="Keyword">else</span> <span class="String"><span class="String">"</span>Ike<span class="String">"</span></span>
|
||||
</pre><pre class="idle"><span class="Storage">var</span> eldest, grade;
|
||||
grade <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">grade</span>(<span class="FunctionArgument">student</span>) {
|
||||
<span class="FunctionName">grade</span> = <span class="Storage">function</span>(<span class="FunctionArgument">student</span>) {
|
||||
<span class="Keyword">if</span> (student.excellent_work) {
|
||||
<span class="Keyword">return</span> <span class="String"><span class="String">"</span>A+<span class="String">"</span></span>;
|
||||
} <span class="Keyword">else</span> <span class="Keyword">if</span> (student.okay_stuff) {
|
||||
@@ -1030,7 +1035,7 @@ grade <span class="Keyword">=</span> <span class="Storage">function</span> <span
|
||||
};
|
||||
eldest <span class="Keyword">=</span> <span class="Number">24</span> <span class="Keyword">></span> <span class="Number">21</span> ? <span class="String"><span class="String">"</span>Liz<span class="String">"</span></span> : <span class="String"><span class="String">"</span>Ike<span class="String">"</span></span>;
|
||||
</pre><button onclick='javascript: var eldest, grade;
|
||||
grade = function grade(student) {
|
||||
grade = function(student) {
|
||||
if (student.excellent_work) {
|
||||
return "A+";
|
||||
} else if (student.okay_stuff) {
|
||||
@@ -1164,7 +1169,7 @@ speed = (typeof speed !== "undefined" && speed !== null) ? speed : 140;
|
||||
</p>
|
||||
<div class='code'><pre class="idle">lottery.draw_winner()<span class="Keyword">?</span>.address<span class="Keyword">?</span>.zipcode
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _a;
|
||||
(_a <span class="Keyword">=</span> lottery.draw_winner()) <span class="Keyword">==</span> undefined ? undefined : _a.address <span class="Keyword">==</span> undefined ? undefined : _a.address.zipcode;
|
||||
<span class="Keyword">typeof</span> (_a <span class="Keyword">=</span> (lottery.draw_winner())) <span class="Keyword">===</span> <span class="String"><span class="String">"</span>undefined<span class="String">"</span></span> <span class="Keyword">||</span> _a <span class="Keyword">==</span> undefined ? undefined : _a.address <span class="Keyword">==</span> undefined ? undefined : _a.address.zipcode;
|
||||
</pre><br class='clear' /></div>
|
||||
<p>
|
||||
Soaking up nulls is similar to Ruby's
|
||||
@@ -1231,28 +1236,31 @@ tom.move()
|
||||
<span class="LibraryClassType">child</span>.<span class="LibraryConstant">prototype</span> = <span class="Keyword">new</span> <span class="TypeName">ctor</span>();
|
||||
<span class="LibraryClassType">child</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">constructor</span> = child;
|
||||
};
|
||||
Animal <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">Animal</span>() { };
|
||||
<span class="LibraryClassType">Animal</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span> <span class="FunctionName">move</span>(<span class="FunctionArgument">meters</span>) {
|
||||
<span class="FunctionName">Animal</span> = <span class="Storage">function</span>() { };
|
||||
<span class="LibraryClassType">Animal</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>(<span class="FunctionArgument">meters</span>) {
|
||||
<span class="Keyword">return</span> <span class="LibraryFunction">alert</span>(<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">+</span> <span class="String"><span class="String">"</span> moved <span class="String">"</span></span> <span class="Keyword">+</span> meters <span class="Keyword">+</span> <span class="String"><span class="String">"</span>m.<span class="String">"</span></span>);
|
||||
};
|
||||
Snake <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">Snake</span>(<span class="FunctionArgument">name</span>) {
|
||||
|
||||
<span class="FunctionName">Snake</span> = <span class="Storage">function</span>(<span class="FunctionArgument">name</span>) {
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>;
|
||||
};
|
||||
__extends(Snake, Animal);
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span> <span class="FunctionName">move</span>() {
|
||||
<span class="LibraryClassType">Snake</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>Slithering...<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> Snake.__superClass__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">5</span>);
|
||||
};
|
||||
Horse <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">Horse</span>(<span class="FunctionArgument">name</span>) {
|
||||
|
||||
<span class="FunctionName">Horse</span> = <span class="Storage">function</span>(<span class="FunctionArgument">name</span>) {
|
||||
<span class="Variable">this</span>.<span class="LibraryConstant">name</span> <span class="Keyword">=</span> name;
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>;
|
||||
};
|
||||
__extends(Horse, Animal);
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span> <span class="FunctionName">move</span>() {
|
||||
<span class="LibraryClassType">Horse</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">move</span> = <span class="Storage">function</span>() {
|
||||
<span class="LibraryFunction">alert</span>(<span class="String"><span class="String">"</span>Galloping...<span class="String">"</span></span>);
|
||||
<span class="Keyword">return</span> Horse.__superClass__.move.<span class="LibraryFunction">call</span>(<span class="Variable">this</span>, <span class="Number">45</span>);
|
||||
};
|
||||
|
||||
sam <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Snake</span>(<span class="String"><span class="String">"</span>Sammy the Python<span class="String">"</span></span>);
|
||||
tom <span class="Keyword">=</span> <span class="Keyword">new</span> <span class="TypeName">Horse</span>(<span class="String"><span class="String">"</span>Tommy the Palomino<span class="String">"</span></span>);
|
||||
sam.move();
|
||||
@@ -1265,28 +1273,31 @@ var __extends = function(child, parent) {
|
||||
child.prototype = new ctor();
|
||||
child.prototype.constructor = child;
|
||||
};
|
||||
Animal = function Animal() { };
|
||||
Animal.prototype.move = function move(meters) {
|
||||
Animal = function() { };
|
||||
Animal.prototype.move = function(meters) {
|
||||
return alert(this.name + " moved " + meters + "m.");
|
||||
};
|
||||
Snake = function Snake(name) {
|
||||
|
||||
Snake = function(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
};
|
||||
__extends(Snake, Animal);
|
||||
Snake.prototype.move = function move() {
|
||||
Snake.prototype.move = function() {
|
||||
alert("Slithering...");
|
||||
return Snake.__superClass__.move.call(this, 5);
|
||||
};
|
||||
Horse = function Horse(name) {
|
||||
|
||||
Horse = function(name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
};
|
||||
__extends(Horse, Animal);
|
||||
Horse.prototype.move = function move() {
|
||||
Horse.prototype.move = function() {
|
||||
alert("Galloping...");
|
||||
return Horse.__superClass__.move.call(this, 45);
|
||||
};
|
||||
|
||||
sam = new Snake("Sammy the Python");
|
||||
tom = new Horse("Tommy the Palomino");
|
||||
sam.move();
|
||||
@@ -1301,10 +1312,10 @@ tom.move();
|
||||
</p>
|
||||
<div class='code'><pre class="idle"><span class="FunctionName">String::dasherize</span><span class="Keyword">:</span> <span class="Storage">-></span>
|
||||
<span class="Variable">this</span>.replace(<span class="String"><span class="String">/</span>_<span class="String">/</span>g</span>, <span class="String"><span class="String">"</span>-<span class="String">"</span></span>)
|
||||
</pre><pre class="idle"><span class="LibraryClassType">String</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">dasherize</span> = <span class="Storage">function</span> <span class="FunctionName">dasherize</span>() {
|
||||
</pre><pre class="idle"><span class="LibraryClassType">String</span>.<span class="LibraryConstant">prototype</span>.<span class="FunctionName">dasherize</span> = <span class="Storage">function</span>() {
|
||||
<span class="Keyword">return</span> <span class="Variable">this</span>.<span class="LibraryFunction">replace</span>(<span class="String"><span class="String">/</span>_<span class="String">/</span>g</span>, <span class="String"><span class="String">"</span>-<span class="String">"</span></span>);
|
||||
};
|
||||
</pre><button onclick='javascript: String.prototype.dasherize = function dasherize() {
|
||||
</pre><button onclick='javascript: String.prototype.dasherize = function() {
|
||||
return this.replace(/_/g, "-");
|
||||
};
|
||||
;alert("one_two".dasherize());'>run: "one_two".dasherize()</button><br class='clear' /></div>
|
||||
@@ -1351,7 +1362,7 @@ and_switch = _a[1];
|
||||
|
||||
<span class="Keyword">[</span>city, temp, forecast<span class="Keyword">]:</span> weather_report <span class="String"><span class="String">"</span>Berkeley, CA<span class="String">"</span></span>
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _a, city, forecast, temp, weather_report;
|
||||
weather_report <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">weather_report</span>(<span class="FunctionArgument">location</span>) {
|
||||
<span class="FunctionName">weather_report</span> = <span class="Storage">function</span>(<span class="FunctionArgument">location</span>) {
|
||||
<span class="Comment"><span class="Comment">//</span> Make an Ajax request to fetch the weather...</span>
|
||||
<span class="Keyword">return</span> [location, <span class="Number">72</span>, <span class="String"><span class="String">"</span>Mostly Sunny<span class="String">"</span></span>];
|
||||
};
|
||||
@@ -1360,7 +1371,7 @@ city <span class="Keyword">=</span> _a[<span class="Number">0</span>];
|
||||
temp <span class="Keyword">=</span> _a[<span class="Number">1</span>];
|
||||
forecast <span class="Keyword">=</span> _a[<span class="Number">2</span>];
|
||||
</pre><button onclick='javascript: var _a, city, forecast, temp, weather_report;
|
||||
weather_report = function weather_report(location) {
|
||||
weather_report = function(location) {
|
||||
// Make an Ajax request to fetch the weather...
|
||||
return [location, 72, "Mostly Sunny"];
|
||||
};
|
||||
@@ -1385,8 +1396,8 @@ forecast = _a[2];
|
||||
}
|
||||
}
|
||||
|
||||
{poet<span class="Keyword">:</span> {name<span class="Keyword">:</span> poet, address<span class="Keyword">:</span> [street, city]}}<span class="Keyword">:</span> futurists
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _a, _b, _c, city, futurists, poet, street;
|
||||
{poet<span class="Keyword">:</span> {name, address<span class="Keyword">:</span> [street, city]}}<span class="Keyword">:</span> futurists
|
||||
</pre><pre class="idle"><span class="Storage">var</span> _a, _b, _c, city, futurists, name, street;
|
||||
futurists <span class="Keyword">=</span> {
|
||||
sculptor: <span class="String"><span class="String">"</span>Umberto Boccioni<span class="String">"</span></span>,
|
||||
painter: <span class="String"><span class="String">"</span>Vladimir Burliuk<span class="String">"</span></span>,
|
||||
@@ -1397,11 +1408,11 @@ futurists <span class="Keyword">=</span> {
|
||||
};
|
||||
_a <span class="Keyword">=</span> futurists;
|
||||
_b <span class="Keyword">=</span> _a.poet;
|
||||
poet <span class="Keyword">=</span> _b.<span class="LibraryConstant">name</span>;
|
||||
name <span class="Keyword">=</span> _b.<span class="LibraryConstant">name</span>;
|
||||
_c <span class="Keyword">=</span> _b.address;
|
||||
street <span class="Keyword">=</span> _c[<span class="Number">0</span>];
|
||||
city <span class="Keyword">=</span> _c[<span class="Number">1</span>];
|
||||
</pre><button onclick='javascript: var _a, _b, _c, city, futurists, poet, street;
|
||||
</pre><button onclick='javascript: var _a, _b, _c, city, futurists, name, street;
|
||||
futurists = {
|
||||
sculptor: "Umberto Boccioni",
|
||||
painter: "Vladimir Burliuk",
|
||||
@@ -1412,11 +1423,11 @@ futurists = {
|
||||
};
|
||||
_a = futurists;
|
||||
_b = _a.poet;
|
||||
poet = _b.name;
|
||||
name = _b.name;
|
||||
_c = _b.address;
|
||||
street = _c[0];
|
||||
city = _c[1];
|
||||
;alert(poet + " — " + street);'>run: poet + " — " + street</button><br class='clear' /></div>
|
||||
;alert(name + " — " + street);'>run: name + " — " + street</button><br class='clear' /></div>
|
||||
<p>
|
||||
Pattern matching can even be combined with splats.
|
||||
</p>
|
||||
@@ -1473,7 +1484,7 @@ close = _a[_a.length - 1];
|
||||
<span class="Keyword">return</span> func.<span class="LibraryFunction">apply</span>(obj <span class="Keyword">||</span> {}, args ? args.<span class="LibraryFunction">concat</span>(__slice.<span class="LibraryFunction">call</span>(arguments, <span class="Number">0</span>)) : arguments);
|
||||
};
|
||||
};
|
||||
Account <span class="Keyword">=</span> <span class="Storage">function</span> <span class="FunctionName">Account</span>(<span class="FunctionArgument">customer, cart</span>) {
|
||||
<span class="FunctionName">Account</span> = <span class="Storage">function</span>(<span class="FunctionArgument">customer, cart</span>) {
|
||||
<span class="Variable">this</span>.customer <span class="Keyword">=</span> customer;
|
||||
<span class="Variable">this</span>.cart <span class="Keyword">=</span> cart;
|
||||
<span class="Keyword">return</span> <span class="Keyword">$</span>(<span class="String"><span class="String">'</span>.shopping_cart<span class="String">'</span></span>).bind(<span class="String"><span class="String">'</span>click<span class="String">'</span></span>, __bind(<span class="Storage">function</span>(<span class="LibraryClassType">event</span>) {
|
||||
@@ -1806,6 +1817,11 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
IRC client of your choice, or on
|
||||
<a href="http://webchat.freenode.net/">webchat.freenode.net</a>.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://github.com/yeungda/jcoffeescript">JCoffeeScript</a>
|
||||
— A Java Library that uses Rhino to compile CoffeeScript, allowing
|
||||
compilation within Java projects or on systems that Node.js doesn't support.
|
||||
</li>
|
||||
<li>
|
||||
<b>defunkt</b>'s <a href="http://github.com/defunkt/coffee-mode">CoffeeScript Major Mode</a>
|
||||
— a Emacs major mode that provides syntax highlighting, indentation
|
||||
@@ -1820,6 +1836,10 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
<b>kchmck</b>'s <a href="http://github.com/kchmck/vim-coffee-script">Vim CoffeeScript</a>
|
||||
— which adds Vim syntax highlighting and indentation support.
|
||||
</li>
|
||||
<li>
|
||||
<b>yeungda</b>'s <a href="http://yeungda.github.com/coffeescript-idea/">coffeescript-idea</a>
|
||||
— a plugin for IntelliJ IDEA and RubyMine providing syntax highlighting.
|
||||
</li>
|
||||
<li>
|
||||
<b>mattly</b>'s <a href="http://github.com/mattly/rack-coffee">rack-coffee</a>
|
||||
— a small Rack middleware for serving CoffeeScript files as
|
||||
@@ -1830,6 +1850,11 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
— a plugin that serves and bundles CoffeeScript from within your
|
||||
Rails application.
|
||||
</li>
|
||||
<li>
|
||||
<b>sutto</b>'s <a href="http://github.com/Sutto/barista">Barista</a>
|
||||
— a BistroCar alternative that integrates well with
|
||||
<a href="http://documentcloud.github.com/jammit">Jammit</a> and Rails 3.
|
||||
</li>
|
||||
<li>
|
||||
<b>inem</b> and <b>gerad</b>'s <a href="http://github.com/gerad/coffee-haml-filter">coffee-haml-filter</a>
|
||||
— a custom filter for rendering CoffeeScript inline within
|
||||
@@ -1856,7 +1881,22 @@ html <span class="Keyword">=</span> <span class="String"><span class="String">'<
|
||||
<span id="change_log" class="bookmark"></span>
|
||||
Change Log
|
||||
</h2>
|
||||
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.2</b>
|
||||
The <tt>coffee</tt> command will now preserve directory structure when
|
||||
compiling a directory full of scripts. Fixed two omissions that were preventing
|
||||
the CoffeeScript compiler from running live within Internet Explorer.
|
||||
There's now a syntax for block comments, similar in spirit to CoffeeScript's heredocs.
|
||||
ECMA Harmony DRY-style pattern matching is now supported, where the name
|
||||
of the property is the same as the name of the value: <tt>{name, length}: func</tt>.
|
||||
Pattern matching is now allowed within comprehension variables. <tt>unless</tt>
|
||||
is now allowed in block form. <tt>until</tt> loops were added, as the inverse
|
||||
of <tt>while</tt> loops. <tt>switch</tt> statements are now allowed without
|
||||
switch object clauses. Compatible
|
||||
with Node.js <b>v0.1.95</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b class="header" style="margin-top: 20px;">0.6.1</b>
|
||||
Upgraded CoffeeScript for compatibility with the new Node.js <b>v0.1.90</b>
|
||||
|
||||
22
lib/cake.js
22
lib/cake.js
@@ -22,7 +22,7 @@
|
||||
helpers.extend(global, {
|
||||
// Define a Cake task with a short name, an optional sentence description,
|
||||
// and the function to run as the action itself.
|
||||
task: function task(name, description, action) {
|
||||
task: function(name, description, action) {
|
||||
var _a;
|
||||
if (!(action)) {
|
||||
_a = [description, action];
|
||||
@@ -39,11 +39,11 @@
|
||||
// Define an option that the Cakefile accepts. The parsed options hash,
|
||||
// containing all of the command-line options passed, will be made available
|
||||
// as the first argument to the action.
|
||||
option: function option(letter, flag, description) {
|
||||
option: function(letter, flag, description) {
|
||||
return switches.push([letter, flag, description]);
|
||||
},
|
||||
// Invoke another task in the current Cakefile.
|
||||
invoke: function invoke(name) {
|
||||
invoke: function(name) {
|
||||
if (!(tasks[name])) {
|
||||
no_such_task(name);
|
||||
}
|
||||
@@ -53,14 +53,14 @@
|
||||
// Run `cake`. Executes all of the tasks you pass, in order. Note that Node's
|
||||
// asynchrony may cause tasks to execute in a different order than you'd expect.
|
||||
// If no tasks are passed, print the help screen.
|
||||
exports.run = function run() {
|
||||
exports.run = function() {
|
||||
return path.exists('Cakefile', function(exists) {
|
||||
var _a, _b, _c, _d, arg, args;
|
||||
if (!(exists)) {
|
||||
throw new Error(("Cakefile not found in " + (process.cwd())));
|
||||
}
|
||||
args = process.argv.slice(2, process.argv.length);
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile'), {
|
||||
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
|
||||
source: 'Cakefile'
|
||||
});
|
||||
oparse = new optparse.OptionParser(switches);
|
||||
@@ -77,16 +77,16 @@
|
||||
});
|
||||
};
|
||||
// Display the list of Cake tasks in a format similar to `rake -T`
|
||||
print_tasks = function print_tasks() {
|
||||
var _a, _b, _c, _d, _e, desc, i, name, spaces, task;
|
||||
print_tasks = function() {
|
||||
var _a, _b, _c, _d, desc, i, name, spaces, task;
|
||||
puts('');
|
||||
_a = tasks;
|
||||
for (name in _a) { if (__hasProp.call(_a, name)) {
|
||||
task = _a[name];
|
||||
spaces = 20 - name.length;
|
||||
spaces = spaces > 0 ? (function() {
|
||||
_b = []; _d = 0; _e = spaces;
|
||||
for (_c = 0, i = _d; (_d <= _e ? i <= _e : i >= _e); (_d <= _e ? i += 1 : i -= 1), _c++) {
|
||||
_b = []; _c = 0; _d = spaces;
|
||||
for (i = _c; (_c <= _d ? i <= _d : i >= _d); (_c <= _d ? i += 1 : i -= 1)) {
|
||||
_b.push(' ');
|
||||
}
|
||||
return _b;
|
||||
@@ -99,8 +99,8 @@
|
||||
}
|
||||
};
|
||||
// Print an error and exit when attempting to all an undefined task.
|
||||
no_such_task = function no_such_task(task) {
|
||||
puts(("No such task: \"" + task + "\"\n"));
|
||||
no_such_task = function(task) {
|
||||
puts(("No such task: \"" + task + "\""));
|
||||
return process.exit(1);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
helpers = this.helpers;
|
||||
}
|
||||
// The current CoffeeScript version number.
|
||||
exports.VERSION = '0.6.1';
|
||||
exports.VERSION = '0.6.2';
|
||||
// Instantiate a Lexer for our use here.
|
||||
lexer = new Lexer();
|
||||
// Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
|
||||
// compiler.
|
||||
exports.compile = (compile = function compile(code, options) {
|
||||
exports.compile = (compile = function(code, options) {
|
||||
options = options || {};
|
||||
try {
|
||||
return (parser.parse(lexer.tokenize(code))).compile(options);
|
||||
@@ -40,13 +40,13 @@
|
||||
}
|
||||
});
|
||||
// Tokenize a string of CoffeeScript code, and return the array of tokens.
|
||||
exports.tokens = function tokens(code) {
|
||||
exports.tokens = function(code) {
|
||||
return lexer.tokenize(code);
|
||||
};
|
||||
// Tokenize and parse a string of CoffeeScript code, and return the AST. You can
|
||||
// then compile it by calling `.compile()` on the root, or traverse it by using
|
||||
// `.traverse()` with a callback.
|
||||
exports.nodes = function nodes(code) {
|
||||
exports.nodes = function(code) {
|
||||
return parser.parse(lexer.tokenize(code));
|
||||
};
|
||||
// Compile and execute a string of CoffeeScript (on the server), correctly
|
||||
@@ -61,14 +61,14 @@
|
||||
// the **Lexer** (as a peer of any of the lexer's tokenizing methods), and
|
||||
// push a token on to the stack that contains a **Node** as the value (as a
|
||||
// peer of the nodes in [nodes.coffee](nodes.html)).
|
||||
exports.extend = function extend(func) {
|
||||
exports.extend = function(func) {
|
||||
return Lexer.extensions.push(func);
|
||||
};
|
||||
// The real Lexer produces a generic stream of tokens. This object provides a
|
||||
// thin wrapper around it, compatible with the Jison API. We can then pass it
|
||||
// directly as a "Jison lexer".
|
||||
parser.lexer = {
|
||||
lex: function lex() {
|
||||
lex: function() {
|
||||
var token;
|
||||
token = this.tokens[this.pos] || [""];
|
||||
this.pos += 1;
|
||||
@@ -76,15 +76,15 @@
|
||||
this.yytext = token[1];
|
||||
return token[0];
|
||||
},
|
||||
setInput: function setInput(tokens) {
|
||||
setInput: function(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.pos = 0;
|
||||
return this.pos;
|
||||
},
|
||||
upcomingInput: function upcomingInput() {
|
||||
upcomingInput: function() {
|
||||
return "";
|
||||
},
|
||||
showPosition: function showPosition() {
|
||||
showPosition: function() {
|
||||
return this.pos;
|
||||
}
|
||||
};
|
||||
@@ -93,7 +93,7 @@
|
||||
// on page load. Unfortunately, the text contents of remote scripts cannot be
|
||||
// accessed from the browser, so only inline script tags will work.
|
||||
if ((typeof document !== "undefined" && document !== null) && document.getElementsByTagName) {
|
||||
process_scripts = function process_scripts() {
|
||||
process_scripts = function() {
|
||||
var _a, _b, _c, _d, tag;
|
||||
_a = []; _c = document.getElementsByTagName('script');
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
|
||||
157
lib/command.js
157
lib/command.js
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var BANNER, CoffeeScript, SWITCHES, _a, compile_options, compile_script, compile_scripts, compile_stdio, exec, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, spawn, usage, version, watch_scripts, write_js;
|
||||
var BANNER, CoffeeScript, SWITCHES, _a, compile_options, compile_script, compile_scripts, compile_stdio, exec, fs, lint, option_parser, options, optparse, parse_options, path, print_tokens, sources, spawn, usage, version, watch, write_js;
|
||||
// The `coffee` utility. Handles command-line compilation of CoffeeScript
|
||||
// into various forms: saved into `.js` files or printed to stdout, piped to
|
||||
// [JSLint](http://javascriptlint.com/) or recompiled every time the source is
|
||||
@@ -24,7 +24,7 @@
|
||||
// Run `coffee` by parsing passed options and determining what action to take.
|
||||
// Many flags cause us to divert before compiling anything. Flags passed after
|
||||
// `--` will be passed verbatim to your script as arguments in `process.argv`
|
||||
exports.run = function run() {
|
||||
exports.run = function() {
|
||||
var flags, separator;
|
||||
parse_options();
|
||||
if (options.help) {
|
||||
@@ -52,44 +52,54 @@
|
||||
sources = sources.slice(0, separator);
|
||||
}
|
||||
process.ARGV = (process.argv = flags);
|
||||
if (options.watch) {
|
||||
watch_scripts();
|
||||
}
|
||||
return compile_scripts();
|
||||
};
|
||||
// Asynchronously read in each CoffeeScript in a list of source files and
|
||||
// compile them.
|
||||
compile_scripts = function compile_scripts() {
|
||||
var compile, run;
|
||||
compile = function compile(source) {
|
||||
return path.exists(source, function(exists) {
|
||||
if (!(exists)) {
|
||||
throw new Error(("File not found: " + source));
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
return compile_script(source, code);
|
||||
});
|
||||
});
|
||||
};
|
||||
run = function run() {
|
||||
var _b, _c, _d, _e, source;
|
||||
_b = []; _d = sources;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
source = _d[_c];
|
||||
_b.push(compile(source));
|
||||
}
|
||||
return _b;
|
||||
};
|
||||
if (!(options.output && options.compile)) {
|
||||
return run();
|
||||
// compile them. If a directory is passed, recursively compile all source
|
||||
// files in it and all subdirectories.
|
||||
compile_scripts = function() {
|
||||
var _b, _c, _d, _e, base, compile, source;
|
||||
_b = []; _d = sources;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
source = _d[_c];
|
||||
_b.push((function() {
|
||||
base = source;
|
||||
compile = function(source) {
|
||||
return path.exists(source, function(exists) {
|
||||
if (!(exists)) {
|
||||
throw new Error(("File not found: " + source));
|
||||
}
|
||||
return fs.stat(source, function(err, stats) {
|
||||
if (stats.isDirectory()) {
|
||||
return fs.readdir(source, function(err, files) {
|
||||
var _f, _g, _h, _i, file;
|
||||
_f = []; _h = files;
|
||||
for (_g = 0, _i = _h.length; _g < _i; _g++) {
|
||||
file = _h[_g];
|
||||
_f.push(compile(path.join(source, file)));
|
||||
}
|
||||
return _f;
|
||||
});
|
||||
} else if (path.extname(source) === '.coffee') {
|
||||
fs.readFile(source, function(err, code) {
|
||||
return compile_script(source, code.toString(), base);
|
||||
});
|
||||
if (options.watch) {
|
||||
return watch(source, base);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
return compile(source);
|
||||
})());
|
||||
}
|
||||
return exec(("mkdir -p " + options.output), run);
|
||||
return _b;
|
||||
};
|
||||
// Compile a single source script, containing the given code, according to the
|
||||
// requested options. Both compile_scripts and watch_scripts share this method
|
||||
// in common. If evaluating the script directly sets `__filename`, `__dirname`
|
||||
// and `module.filename` to be correct relative to the script's path.
|
||||
compile_script = function compile_script(source, code) {
|
||||
// requested options. If evaluating the script directly sets `__filename`,
|
||||
// `__dirname` and `module.filename` to be correct relative to the script's path.
|
||||
compile_script = function(source, code, base) {
|
||||
var code_opts, js, o;
|
||||
o = options;
|
||||
code_opts = compile_options(source);
|
||||
@@ -105,7 +115,7 @@
|
||||
if (o.print) {
|
||||
return print(js);
|
||||
} else if (o.compile) {
|
||||
return write_js(source, js);
|
||||
return write_js(source, js, base);
|
||||
} else if (o.lint) {
|
||||
return lint(js);
|
||||
}
|
||||
@@ -120,7 +130,7 @@
|
||||
};
|
||||
// Attach the appropriate listeners to compile scripts incoming over **stdin**,
|
||||
// and write them back to **stdout**.
|
||||
compile_stdio = function compile_stdio() {
|
||||
compile_stdio = function() {
|
||||
var code, stdin;
|
||||
code = '';
|
||||
stdin = process.openStdin();
|
||||
@@ -133,47 +143,52 @@
|
||||
return compile_script('stdio', code);
|
||||
});
|
||||
};
|
||||
// Watch a list of source CoffeeScript files using `fs.watchFile`, recompiling
|
||||
// them every time the files are updated. May be used in combination with other
|
||||
// options, such as `--lint` or `--print`.
|
||||
watch_scripts = function watch_scripts() {
|
||||
var _b, _c, _d, _e, source, watch;
|
||||
watch = function watch(source) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
interval: 500
|
||||
}, function(curr, prev) {
|
||||
if (curr.mtime.getTime() === prev.mtime.getTime()) {
|
||||
return null;
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
return compile_script(source, code);
|
||||
});
|
||||
// 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`.
|
||||
watch = function(source, base) {
|
||||
return fs.watchFile(source, {
|
||||
persistent: true,
|
||||
interval: 500
|
||||
}, function(curr, prev) {
|
||||
if (curr.mtime.getTime() === prev.mtime.getTime()) {
|
||||
return null;
|
||||
}
|
||||
if (options.compile) {
|
||||
puts(("Compiled " + source));
|
||||
}
|
||||
return fs.readFile(source, function(err, code) {
|
||||
return compile_script(source, code.toString(), base);
|
||||
});
|
||||
};
|
||||
_b = []; _d = sources;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
source = _d[_c];
|
||||
_b.push(watch(source));
|
||||
}
|
||||
return _b;
|
||||
});
|
||||
};
|
||||
// Write out a JavaScript source file with the compiled code. By default, files
|
||||
// are written out in `cwd` as `.js` files with the same name, but the output
|
||||
// directory can be customized with `--output`.
|
||||
write_js = function write_js(source, js) {
|
||||
var dir, filename, js_path;
|
||||
write_js = function(source, js, base) {
|
||||
var base_dir, compile, dir, filename, js_path, src_dir;
|
||||
filename = path.basename(source, path.extname(source)) + '.js';
|
||||
dir = options.output || path.dirname(source);
|
||||
src_dir = path.dirname(source);
|
||||
base_dir = src_dir.substring(base.length);
|
||||
dir = options.output ? path.join(options.output, base_dir) : src_dir;
|
||||
js_path = path.join(dir, filename);
|
||||
return fs.writeFile(js_path, js);
|
||||
compile = function() {
|
||||
return fs.writeFile(js_path, js);
|
||||
};
|
||||
return path.exists(dir, function(exists) {
|
||||
if (exists) {
|
||||
return compile();
|
||||
} else {
|
||||
return exec(("mkdir -p " + dir), compile);
|
||||
}
|
||||
});
|
||||
};
|
||||
// Pipe compiled JS through JSLint (requires a working `jsl` command), printing
|
||||
// any errors or warnings that arise.
|
||||
lint = function lint(js) {
|
||||
lint = function(js) {
|
||||
var jsl, print_it;
|
||||
print_it = function print_it(buffer) {
|
||||
return puts(buffer.toString());
|
||||
print_it = function(buffer) {
|
||||
return print(buffer.toString());
|
||||
};
|
||||
jsl = spawn('jsl', ['-nologo', '-stdin']);
|
||||
jsl.stdout.addListener('data', print_it);
|
||||
@@ -182,7 +197,7 @@
|
||||
return jsl.stdin.end();
|
||||
};
|
||||
// Pretty-print a stream of tokens.
|
||||
print_tokens = function print_tokens(tokens) {
|
||||
print_tokens = function(tokens) {
|
||||
var _b, _c, _d, _e, _f, strings, tag, token, value;
|
||||
strings = (function() {
|
||||
_b = []; _d = tokens;
|
||||
@@ -201,7 +216,7 @@
|
||||
};
|
||||
// Use the [OptionParser module](optparse.html) to extract all options from
|
||||
// `process.argv` that are specified in `SWITCHES`.
|
||||
parse_options = function parse_options() {
|
||||
parse_options = function() {
|
||||
var o;
|
||||
option_parser = new optparse.OptionParser(SWITCHES, BANNER);
|
||||
o = (options = option_parser.parse(process.argv));
|
||||
@@ -211,7 +226,7 @@
|
||||
return sources;
|
||||
};
|
||||
// The compile-time options to pass to the CoffeeScript compiler.
|
||||
compile_options = function compile_options(source) {
|
||||
compile_options = function(source) {
|
||||
var o;
|
||||
o = {
|
||||
source: source
|
||||
@@ -220,12 +235,12 @@
|
||||
return o;
|
||||
};
|
||||
// Print the `--help` usage message and exit.
|
||||
usage = function usage() {
|
||||
usage = function() {
|
||||
puts(option_parser.help());
|
||||
return process.exit(0);
|
||||
};
|
||||
// Print the `--version` message and exit.
|
||||
version = function version() {
|
||||
version = function() {
|
||||
puts(("CoffeeScript version " + CoffeeScript.VERSION));
|
||||
return process.exit(0);
|
||||
};
|
||||
|
||||
289
lib/grammar.js
289
lib/grammar.js
@@ -28,7 +28,7 @@
|
||||
// we pass the pattern-defining string, the action to run, and extra options,
|
||||
// optionally. If no action is specified, we simply pass the value of the
|
||||
// previous nonterminal.
|
||||
o = function o(pattern_string, action, options) {
|
||||
o = function(pattern_string, action, options) {
|
||||
var match;
|
||||
if (!(action)) {
|
||||
return [pattern_string, '$$ = $1;', options];
|
||||
@@ -49,14 +49,16 @@
|
||||
grammar = {
|
||||
// The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
|
||||
// all parsing must end here.
|
||||
Root: [o("", function() {
|
||||
Root: [
|
||||
o("", function() {
|
||||
return new Expressions();
|
||||
}), o("TERMINATOR", function() {
|
||||
return new Expressions();
|
||||
}), o("Body"), o("Block TERMINATOR")
|
||||
],
|
||||
// Any list of statements and expressions, seperated by line breaks or semicolons.
|
||||
Body: [o("Line", function() {
|
||||
Body: [
|
||||
o("Line", function() {
|
||||
return Expressions.wrap([$1]);
|
||||
}), o("Body TERMINATOR Line", function() {
|
||||
return $1.push($3);
|
||||
@@ -65,10 +67,11 @@
|
||||
// Expressions and statements, which make up a line in a body.
|
||||
Line: [o("Expression"), o("Statement")],
|
||||
// Pure statements which cannot be expressions.
|
||||
Statement: [o("Return"), o("Throw"), o("BREAK", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Statement: [
|
||||
o("Return"), o("Throw"), o("BREAK", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("CONTINUE", function() {
|
||||
return new LiteralNode(yytext);
|
||||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
// All the different types of expressions in our language. The basic unit of
|
||||
@@ -79,7 +82,8 @@
|
||||
// A an indented block of expressions. Note that the [Rewriter](rewriter.html)
|
||||
// will convert some postfix forms into blocks for us, by adjusting the
|
||||
// token stream.
|
||||
Block: [o("INDENT Body OUTDENT", function() {
|
||||
Block: [
|
||||
o("INDENT Body OUTDENT", function() {
|
||||
return $2;
|
||||
}), o("INDENT OUTDENT", function() {
|
||||
return new Expressions();
|
||||
@@ -88,24 +92,27 @@
|
||||
})
|
||||
],
|
||||
// A literal identifier, a variable name or property.
|
||||
Identifier: [o("IDENTIFIER", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Identifier: [
|
||||
o("IDENTIFIER", function() {
|
||||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
// Alphanumerics are separated from the other **Literal** matchers because
|
||||
// they can also serve as keys in object literals.
|
||||
AlphaNumeric: [o("NUMBER", function() {
|
||||
return new LiteralNode(yytext);
|
||||
AlphaNumeric: [
|
||||
o("NUMBER", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("STRING", function() {
|
||||
return new LiteralNode(yytext);
|
||||
return new LiteralNode($1);
|
||||
})
|
||||
],
|
||||
// All of our immediate values. These can (in general), be passed straight
|
||||
// through and printed to JavaScript.
|
||||
Literal: [o("AlphaNumeric"), o("JS", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Literal: [
|
||||
o("AlphaNumeric"), o("JS", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("REGEX", function() {
|
||||
return new LiteralNode(yytext);
|
||||
return new LiteralNode($1);
|
||||
}), o("TRUE", function() {
|
||||
return new LiteralNode(true);
|
||||
}), o("FALSE", function() {
|
||||
@@ -121,20 +128,25 @@
|
||||
})
|
||||
],
|
||||
// Assignment of a variable, property, or index to a value.
|
||||
Assign: [o("Assignable ASSIGN Expression", function() {
|
||||
Assign: [
|
||||
o("Assignable ASSIGN Expression", function() {
|
||||
return new AssignNode($1, $3);
|
||||
})
|
||||
],
|
||||
// Assignment when it happens within an object literal. The difference from
|
||||
// the ordinary **Assign** is that these allow numbers and strings as keys.
|
||||
AssignObj: [o("Identifier ASSIGN Expression", function() {
|
||||
AssignObj: [
|
||||
o("Identifier", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("AlphaNumeric"), o("Identifier ASSIGN Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'object');
|
||||
}), o("AlphaNumeric ASSIGN Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'object');
|
||||
}), o("Comment")
|
||||
],
|
||||
// A return statement from a function body.
|
||||
Return: [o("RETURN Expression", function() {
|
||||
Return: [
|
||||
o("RETURN Expression", function() {
|
||||
return new ReturnNode($2);
|
||||
}), o("RETURN", function() {
|
||||
return new ReturnNode(new ValueNode(new LiteralNode('null')));
|
||||
@@ -143,19 +155,24 @@
|
||||
// A comment. Because CoffeeScript passes comments through to JavaScript, we
|
||||
// have to parse comments like any other construct, and identify all of the
|
||||
// positions in which they can occur in the grammar.
|
||||
Comment: [o("COMMENT", function() {
|
||||
return new CommentNode(yytext);
|
||||
Comment: [
|
||||
o("COMMENT", function() {
|
||||
return new CommentNode($1);
|
||||
}), o("HERECOMMENT", function() {
|
||||
return new CommentNode($1, 'herecomment');
|
||||
})
|
||||
],
|
||||
// [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
|
||||
Existence: [o("Expression ?", function() {
|
||||
Existence: [
|
||||
o("Expression ?", function() {
|
||||
return new ExistenceNode($1);
|
||||
})
|
||||
],
|
||||
// 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
|
||||
// list.
|
||||
Code: [o("PARAM_START ParamList PARAM_END FuncGlyph Block", function() {
|
||||
Code: [
|
||||
o("PARAM_START ParamList PARAM_END FuncGlyph Block", function() {
|
||||
return new CodeNode($2, $5, $4);
|
||||
}), o("FuncGlyph Block", function() {
|
||||
return new CodeNode([], $2, $1);
|
||||
@@ -163,14 +180,18 @@
|
||||
],
|
||||
// CoffeeScript has two different symbols for functions. `->` is for ordinary
|
||||
// functions, and `=>` is for functions bound to the current value of *this*.
|
||||
FuncGlyph: [o("->", function() {
|
||||
FuncGlyph: [
|
||||
o("->", function() {
|
||||
return 'func';
|
||||
}), o("=>", function() {
|
||||
return 'boundfunc';
|
||||
})
|
||||
],
|
||||
// An optional, trailing comma.
|
||||
OptComma: [o(''), o(',')],
|
||||
// The list of parameters that a function accepts can be of any length.
|
||||
ParamList: [o("", function() {
|
||||
ParamList: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("Param", function() {
|
||||
return [$1];
|
||||
@@ -180,19 +201,22 @@
|
||||
],
|
||||
// A single parameter in a function definition can be ordinary, or a splat
|
||||
// that hoovers up the remaining arguments.
|
||||
Param: [o("PARAM", function() {
|
||||
return new LiteralNode(yytext);
|
||||
Param: [
|
||||
o("PARAM", function() {
|
||||
return new LiteralNode($1);
|
||||
}), o("Param . . .", function() {
|
||||
return new SplatNode($1);
|
||||
})
|
||||
],
|
||||
// A splat that occurs outside of a parameter list.
|
||||
Splat: [o("Expression . . .", function() {
|
||||
Splat: [
|
||||
o("Expression . . .", function() {
|
||||
return new SplatNode($1);
|
||||
})
|
||||
],
|
||||
// Variables and properties that can be assigned to.
|
||||
SimpleAssignable: [o("Identifier", function() {
|
||||
SimpleAssignable: [
|
||||
o("Identifier", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Value Accessor", function() {
|
||||
return $1.push($2);
|
||||
@@ -201,7 +225,8 @@
|
||||
}), o("ThisProperty")
|
||||
],
|
||||
// Everything that can be assigned to.
|
||||
Assignable: [o("SimpleAssignable"), o("Array", function() {
|
||||
Assignable: [
|
||||
o("SimpleAssignable"), o("Array", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Object", function() {
|
||||
return new ValueNode($1);
|
||||
@@ -209,7 +234,8 @@
|
||||
],
|
||||
// The types of things that can be treated as values -- assigned to, invoked
|
||||
// as functions, indexed into, named as a class, etc.
|
||||
Value: [o("Assignable"), o("Literal", function() {
|
||||
Value: [
|
||||
o("Assignable"), o("Literal", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Parenthetical", function() {
|
||||
return new ValueNode($1);
|
||||
@@ -221,7 +247,8 @@
|
||||
],
|
||||
// The general group of accessors into an object, by property, by prototype
|
||||
// or by array index or slice.
|
||||
Accessor: [o("PROPERTY_ACCESS Identifier", function() {
|
||||
Accessor: [
|
||||
o("PROPERTY_ACCESS Identifier", function() {
|
||||
return new AccessorNode($2);
|
||||
}), o("PROTOTYPE_ACCESS Identifier", function() {
|
||||
return new AccessorNode($2, 'prototype');
|
||||
@@ -234,47 +261,38 @@
|
||||
})
|
||||
],
|
||||
// Indexing into an object or array using bracket notation.
|
||||
Index: [o("INDEX_START Expression INDEX_END", function() {
|
||||
Index: [
|
||||
o("INDEX_START Expression INDEX_END", function() {
|
||||
return new IndexNode($2);
|
||||
}), o("SOAKED_INDEX_START Expression SOAKED_INDEX_END", function() {
|
||||
return new IndexNode($2, 'soak');
|
||||
})
|
||||
],
|
||||
// In CoffeeScript, an object literal is simply a list of assignments.
|
||||
Object: [o("{ AssignList }", function() {
|
||||
return new ObjectNode($2);
|
||||
}), o("{ IndentedAssignList }", function() {
|
||||
return new ObjectNode($2);
|
||||
}), o("{ AssignList , }", function() {
|
||||
return new ObjectNode($2);
|
||||
}), o("{ IndentedAssignList , }", function() {
|
||||
Object: [
|
||||
o("{ AssignList OptComma }", function() {
|
||||
return new ObjectNode($2);
|
||||
})
|
||||
],
|
||||
// Assignment of properties within an object literal can be separated by
|
||||
// comma, as in JavaScript, or simply by newline.
|
||||
AssignList: [o("", function() {
|
||||
AssignList: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("AssignObj", function() {
|
||||
return [$1];
|
||||
}), o("AssignList , AssignObj", function() {
|
||||
return $1.concat([$3]);
|
||||
}), o("AssignList TERMINATOR AssignObj", function() {
|
||||
return $1.concat([$3]);
|
||||
}), o("AssignList , TERMINATOR AssignObj", function() {
|
||||
}), o("AssignList OptComma TERMINATOR AssignObj", function() {
|
||||
return $1.concat([$4]);
|
||||
})
|
||||
],
|
||||
// An **AssignList** within a block indentation.
|
||||
IndentedAssignList: [o("INDENT AssignList OUTDENT", function() {
|
||||
return $2;
|
||||
}), o("INDENT AssignList , OUTDENT", function() {
|
||||
return $2;
|
||||
}), o("AssignList OptComma INDENT AssignList OptComma OUTDENT", function() {
|
||||
return $1.concat($4);
|
||||
})
|
||||
],
|
||||
// Class definitions have optional bodies of prototype property assignments,
|
||||
// and optional references to the superclass.
|
||||
Class: [o("CLASS SimpleAssignable", function() {
|
||||
Class: [
|
||||
o("CLASS SimpleAssignable", function() {
|
||||
return new ClassNode($2);
|
||||
}), o("CLASS SimpleAssignable EXTENDS Value", function() {
|
||||
return new ClassNode($2, $4);
|
||||
@@ -285,14 +303,16 @@
|
||||
})
|
||||
],
|
||||
// Assignments that can happen directly inside a class declaration.
|
||||
ClassAssign: [o("AssignObj", function() {
|
||||
ClassAssign: [
|
||||
o("AssignObj", function() {
|
||||
return $1;
|
||||
}), o("ThisProperty ASSIGN Expression", function() {
|
||||
return new AssignNode(new ValueNode($1), $3, 'this');
|
||||
})
|
||||
],
|
||||
// A list of assignments to a class.
|
||||
ClassBody: [o("", function() {
|
||||
ClassBody: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("ClassAssign", function() {
|
||||
return [$1];
|
||||
@@ -302,79 +322,85 @@
|
||||
],
|
||||
// The three flavors of function call: normal, object instantiation with `new`,
|
||||
// and calling `super()`
|
||||
Call: [o("Invocation"), o("NEW Invocation", function() {
|
||||
Call: [
|
||||
o("Invocation"), o("NEW Invocation", function() {
|
||||
return $2.new_instance();
|
||||
}), o("Super")
|
||||
],
|
||||
// Binds a function call to a context and/or arguments.
|
||||
Curry: [o("Value <- Arguments", function() {
|
||||
Curry: [
|
||||
o("Value <- Arguments", function() {
|
||||
return new CurryNode($1, $3);
|
||||
})
|
||||
],
|
||||
// Extending an object by setting its prototype chain to reference a parent
|
||||
// object.
|
||||
Extends: [o("SimpleAssignable EXTENDS Value", function() {
|
||||
Extends: [
|
||||
o("SimpleAssignable EXTENDS Value", function() {
|
||||
return new ExtendsNode($1, $3);
|
||||
})
|
||||
],
|
||||
// Ordinary function invocation, or a chained series of calls.
|
||||
Invocation: [o("Value Arguments", function() {
|
||||
Invocation: [
|
||||
o("Value Arguments", function() {
|
||||
return new CallNode($1, $2);
|
||||
}), o("Invocation Arguments", function() {
|
||||
return new CallNode($1, $2);
|
||||
})
|
||||
],
|
||||
// The list of arguments to a function call.
|
||||
Arguments: [o("CALL_START ArgList CALL_END", function() {
|
||||
return $2;
|
||||
}), o("CALL_START ArgList , CALL_END", function() {
|
||||
Arguments: [
|
||||
o("CALL_START ArgList OptComma CALL_END", function() {
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
// Calling super.
|
||||
Super: [o("SUPER CALL_START ArgList CALL_END", function() {
|
||||
return new CallNode('super', $3);
|
||||
}), o("SUPER CALL_START ArgList , CALL_END", function() {
|
||||
Super: [
|
||||
o("SUPER CALL_START ArgList OptComma CALL_END", function() {
|
||||
return new CallNode('super', $3);
|
||||
})
|
||||
],
|
||||
// A reference to the *this* current object.
|
||||
This: [o("THIS", function() {
|
||||
This: [
|
||||
o("THIS", function() {
|
||||
return new ValueNode(new LiteralNode('this'));
|
||||
}), o("@", function() {
|
||||
return new ValueNode(new LiteralNode('this'));
|
||||
})
|
||||
],
|
||||
// A reference to a property on *this*.
|
||||
ThisProperty: [o("@ Identifier", function() {
|
||||
ThisProperty: [
|
||||
o("@ Identifier", function() {
|
||||
return new ValueNode(new LiteralNode('this'), [new AccessorNode($2)]);
|
||||
})
|
||||
],
|
||||
// The CoffeeScript range literal.
|
||||
Range: [o("[ Expression . . Expression ]", function() {
|
||||
Range: [
|
||||
o("[ Expression . . Expression ]", function() {
|
||||
return new RangeNode($2, $5);
|
||||
}), o("[ Expression . . . Expression ]", function() {
|
||||
return new RangeNode($2, $6, true);
|
||||
})
|
||||
],
|
||||
// The slice literal.
|
||||
Slice: [o("INDEX_START Expression . . Expression INDEX_END", function() {
|
||||
Slice: [
|
||||
o("INDEX_START Expression . . Expression INDEX_END", function() {
|
||||
return new RangeNode($2, $5);
|
||||
}), o("INDEX_START Expression . . . Expression INDEX_END", function() {
|
||||
return new RangeNode($2, $6, true);
|
||||
})
|
||||
],
|
||||
// The array literal.
|
||||
Array: [o("[ ArgList ]", function() {
|
||||
return new ArrayNode($2);
|
||||
}), o("[ ArgList , ]", function() {
|
||||
Array: [
|
||||
o("[ ArgList OptComma ]", function() {
|
||||
return new ArrayNode($2);
|
||||
})
|
||||
],
|
||||
// The **ArgList** is both the list of objects passed into a function call,
|
||||
// as well as the contents of an array literal
|
||||
// (i.e. comma-separated expressions). Newlines work as well.
|
||||
ArgList: [o("", function() {
|
||||
ArgList: [
|
||||
o("", function() {
|
||||
return [];
|
||||
}), o("Expression", function() {
|
||||
return [$1];
|
||||
@@ -388,12 +414,13 @@
|
||||
return $1.concat([$4]);
|
||||
}), o("ArgList , INDENT Expression", function() {
|
||||
return $1.concat([$4]);
|
||||
}), o("ArgList OUTDENT"), o("ArgList , OUTDENT")
|
||||
}), o("ArgList OptComma OUTDENT")
|
||||
],
|
||||
// Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
// this to be separate from the **ArgList** for use in **Switch** blocks, where
|
||||
// having the newlines wouldn't make sense.
|
||||
SimpleArgs: [o("Expression"), o("SimpleArgs , Expression", function() {
|
||||
SimpleArgs: [
|
||||
o("Expression"), o("SimpleArgs , Expression", function() {
|
||||
if ($1 instanceof Array) {
|
||||
return $1.concat([$3]);
|
||||
} else {
|
||||
@@ -402,7 +429,8 @@
|
||||
})
|
||||
],
|
||||
// The variants of *try/catch/finally* exception handling blocks.
|
||||
Try: [o("TRY Block Catch", function() {
|
||||
Try: [
|
||||
o("TRY Block Catch", function() {
|
||||
return new TryNode($2, $3[0], $3[1]);
|
||||
}), o("TRY Block FINALLY Block", function() {
|
||||
return new TryNode($2, null, null, $4);
|
||||
@@ -411,12 +439,14 @@
|
||||
})
|
||||
],
|
||||
// A catch clause names its error and runs a block of code.
|
||||
Catch: [o("CATCH Identifier Block", function() {
|
||||
Catch: [
|
||||
o("CATCH Identifier Block", function() {
|
||||
return [$2, $3];
|
||||
})
|
||||
],
|
||||
// Throw an exception object.
|
||||
Throw: [o("THROW Expression", function() {
|
||||
Throw: [
|
||||
o("THROW Expression", function() {
|
||||
return new ThrowNode($2);
|
||||
})
|
||||
],
|
||||
@@ -424,28 +454,37 @@
|
||||
// not an **Expression**, so if you need to use an expression in a place
|
||||
// where only values are accepted, wrapping it in parentheses will always do
|
||||
// the trick.
|
||||
Parenthetical: [o("( Line )", function() {
|
||||
Parenthetical: [
|
||||
o("( Line )", function() {
|
||||
return new ParentheticalNode($2);
|
||||
})
|
||||
],
|
||||
// A language extension to CoffeeScript from the outside. We simply pass
|
||||
// it through unaltered.
|
||||
Extension: [o("EXTENSION", function() {
|
||||
return yytext;
|
||||
})
|
||||
],
|
||||
Extension: [o("EXTENSION")],
|
||||
// The condition portion of a while loop.
|
||||
WhileSource: [o("WHILE Expression", function() {
|
||||
WhileSource: [
|
||||
o("WHILE Expression", function() {
|
||||
return new WhileNode($2);
|
||||
}), o("WHILE Expression WHEN Expression", function() {
|
||||
return new WhileNode($2, {
|
||||
filter: $4
|
||||
guard: $4
|
||||
});
|
||||
}), o("UNTIL Expression", function() {
|
||||
return new WhileNode($2, {
|
||||
invert: true
|
||||
});
|
||||
}), o("UNTIL Expression WHEN Expression", function() {
|
||||
return new WhileNode($2, {
|
||||
invert: true,
|
||||
guard: $4
|
||||
});
|
||||
})
|
||||
],
|
||||
// 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.
|
||||
While: [o("WhileSource Block", function() {
|
||||
While: [
|
||||
o("WhileSource Block", function() {
|
||||
return $1.add_body($2);
|
||||
}), o("Statement WhileSource", function() {
|
||||
return $2.add_body(Expressions.wrap([$1]));
|
||||
@@ -456,7 +495,8 @@
|
||||
// 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.
|
||||
For: [o("Statement FOR ForVariables ForSource", function() {
|
||||
For: [
|
||||
o("Statement FOR ForVariables ForSource", function() {
|
||||
return new ForNode($1, $4, $3[0], $3[1]);
|
||||
}), o("Expression FOR ForVariables ForSource", function() {
|
||||
return new ForNode($1, $4, $3[0], $3[1]);
|
||||
@@ -464,19 +504,30 @@
|
||||
return new ForNode($4, $3, $2[0], $2[1]);
|
||||
})
|
||||
],
|
||||
// An array of all accepted values for a variable inside the loop. This
|
||||
// enables support for pattern matching.
|
||||
ForValue: [
|
||||
o("Identifier"), o("Array", function() {
|
||||
return new ValueNode($1);
|
||||
}), o("Object", function() {
|
||||
return new ValueNode($1);
|
||||
})
|
||||
],
|
||||
// An array or range comprehension has variables for the current element and
|
||||
// (optional) reference to the current index. Or, *key, value*, in the case
|
||||
// of object comprehensions.
|
||||
ForVariables: [o("Identifier", function() {
|
||||
ForVariables: [
|
||||
o("ForValue", function() {
|
||||
return [$1];
|
||||
}), o("Identifier , Identifier", function() {
|
||||
}), o("ForValue , ForValue", function() {
|
||||
return [$1, $3];
|
||||
})
|
||||
],
|
||||
// The source of a comprehension is an array or object with an optional filter
|
||||
// The source of a comprehension is an array or object with an optional guard
|
||||
// clause. If it's an array comprehension, you can also choose to step through
|
||||
// in fixed-size increments.
|
||||
ForSource: [o("IN Expression", function() {
|
||||
ForSource: [
|
||||
o("IN Expression", function() {
|
||||
return {
|
||||
source: $2
|
||||
};
|
||||
@@ -488,12 +539,12 @@
|
||||
}), o("IN Expression WHEN Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
filter: $4
|
||||
guard: $4
|
||||
};
|
||||
}), o("OF Expression WHEN Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
filter: $4,
|
||||
guard: $4,
|
||||
object: true
|
||||
};
|
||||
}), o("IN Expression BY Expression", function() {
|
||||
@@ -504,38 +555,45 @@
|
||||
}), o("IN Expression WHEN Expression BY Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
filter: $4,
|
||||
guard: $4,
|
||||
step: $6
|
||||
};
|
||||
}), o("IN Expression BY Expression WHEN Expression", function() {
|
||||
return {
|
||||
source: $2,
|
||||
step: $4,
|
||||
filter: $6
|
||||
guard: $6
|
||||
};
|
||||
})
|
||||
],
|
||||
// The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
// switch/case/default by compiling into an if-else chain.
|
||||
Switch: [o("SWITCH Expression INDENT Whens OUTDENT", function() {
|
||||
return $4.rewrite_condition($2);
|
||||
Switch: [
|
||||
o("SWITCH Expression INDENT Whens OUTDENT", function() {
|
||||
return $4.switches_over($2);
|
||||
}), o("SWITCH Expression INDENT Whens ELSE Block OUTDENT", function() {
|
||||
return $4.rewrite_condition($2).add_else($6, true);
|
||||
return $4.switches_over($2).add_else($6, true);
|
||||
}), o("SWITCH INDENT Whens OUTDENT", function() {
|
||||
return $3;
|
||||
}), o("SWITCH INDENT Whens ELSE Block OUTDENT", function() {
|
||||
return $3.add_else($5, true);
|
||||
})
|
||||
],
|
||||
// The inner list of whens is left recursive. At code-generation time, the
|
||||
// IfNode will rewrite them into a proper chain.
|
||||
Whens: [o("When"), o("Whens When", function() {
|
||||
return $1.push($2);
|
||||
Whens: [
|
||||
o("When"), o("Whens When", function() {
|
||||
return $1.add_else($2);
|
||||
})
|
||||
],
|
||||
// An individual **When** clause, with action.
|
||||
When: [o("LEADING_WHEN SimpleArgs Block", function() {
|
||||
return new IfNode($2, $3, null, {
|
||||
When: [
|
||||
o("LEADING_WHEN SimpleArgs Block", function() {
|
||||
return new IfNode($2, $3, {
|
||||
statement: true
|
||||
});
|
||||
}), o("LEADING_WHEN SimpleArgs Block TERMINATOR", function() {
|
||||
return new IfNode($2, $3, null, {
|
||||
return new IfNode($2, $3, {
|
||||
statement: true
|
||||
});
|
||||
}), o("Comment TERMINATOR When", function() {
|
||||
@@ -546,39 +604,47 @@
|
||||
// The most basic form of *if* is a condition and an action. The following
|
||||
// if-related rules are broken up along these lines in order to avoid
|
||||
// ambiguity.
|
||||
IfStart: [o("IF Expression Block", function() {
|
||||
IfStart: [
|
||||
o("IF Expression Block", function() {
|
||||
return new IfNode($2, $3);
|
||||
}), o("UNLESS Expression Block", function() {
|
||||
return new IfNode($2, $3, {
|
||||
invert: true
|
||||
});
|
||||
}), o("IfStart ElsIf", function() {
|
||||
return $1.add_else($2);
|
||||
})
|
||||
],
|
||||
// An **IfStart** can optionally be followed by an else block.
|
||||
IfBlock: [o("IfStart"), o("IfStart ELSE Block", function() {
|
||||
IfBlock: [
|
||||
o("IfStart"), o("IfStart ELSE Block", function() {
|
||||
return $1.add_else($3);
|
||||
})
|
||||
],
|
||||
// An *else if* continuation of the *if* expression.
|
||||
ElsIf: [o("ELSE IF Expression Block", function() {
|
||||
ElsIf: [
|
||||
o("ELSE IF Expression Block", function() {
|
||||
return (new IfNode($3, $4)).force_statement();
|
||||
})
|
||||
],
|
||||
// The full complement of *if* expressions, including postfix one-liner
|
||||
// *if* and *unless*.
|
||||
If: [o("IfBlock"), o("Statement IF Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), null, {
|
||||
If: [
|
||||
o("IfBlock"), o("Statement IF Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true
|
||||
});
|
||||
}), o("Expression IF Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), null, {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true
|
||||
});
|
||||
}), o("Statement UNLESS Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), null, {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true,
|
||||
invert: true
|
||||
});
|
||||
}), o("Expression UNLESS Expression", function() {
|
||||
return new IfNode($3, Expressions.wrap([$1]), null, {
|
||||
return new IfNode($3, Expressions.wrap([$1]), {
|
||||
statement: true,
|
||||
invert: true
|
||||
});
|
||||
@@ -590,7 +656,8 @@
|
||||
// combine most of these rules into a single generic *Operand OpSymbol Operand*
|
||||
// -type rule, but in order to make the precedence binding possible, separate
|
||||
// rules are necessary.
|
||||
Operation: [o("! Expression", function() {
|
||||
Operation: [
|
||||
o("! Expression", function() {
|
||||
return new OpNode('!', $2);
|
||||
}), o("!! Expression", function() {
|
||||
return new OpNode('!!', $2);
|
||||
@@ -686,7 +753,7 @@
|
||||
// 2 + (3 * 4)
|
||||
// And not:
|
||||
// (2 + 3) * 4
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']];
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'WHILE', 'UNTIL', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE']];
|
||||
// Wrapping Up
|
||||
// -----------
|
||||
// Finally, now what we have our **grammar** and our **operators**, we can create
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var balanced_string, compact, count, del, extend, flatten, helpers, include, merge, starts;
|
||||
var balanced_string, compact, count, del, extend, flatten, helpers, include, index_of, merge, starts;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// This file contains the common helper functions that we'd like to share among
|
||||
// the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
||||
@@ -9,16 +9,31 @@
|
||||
this.exports = this;
|
||||
}
|
||||
helpers = (exports.helpers = {});
|
||||
// Cross-browser indexOf, so that IE can join the party.
|
||||
helpers.index_of = (index_of = function(array, item, from) {
|
||||
var _a, _b, index, other;
|
||||
if (array.indexOf) {
|
||||
return array.indexOf(item, from);
|
||||
}
|
||||
_a = array;
|
||||
for (index = 0, _b = _a.length; index < _b; index++) {
|
||||
other = _a[index];
|
||||
if (other === item && (!from || (from <= index))) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
// Does a list include a value?
|
||||
helpers.include = (include = function include(list, value) {
|
||||
return list.indexOf(value) >= 0;
|
||||
helpers.include = (include = function(list, value) {
|
||||
return index_of(list, value) >= 0;
|
||||
});
|
||||
// Peek at the beginning of a given string to see if it matches a sequence.
|
||||
helpers.starts = (starts = function starts(string, literal, start) {
|
||||
helpers.starts = (starts = function(string, literal, start) {
|
||||
return string.substring(start, (start || 0) + literal.length) === literal;
|
||||
});
|
||||
// Trim out all falsy values from an array.
|
||||
helpers.compact = (compact = function compact(array) {
|
||||
helpers.compact = (compact = function(array) {
|
||||
var _a, _b, _c, _d, item;
|
||||
_a = []; _c = array;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
@@ -28,20 +43,20 @@
|
||||
return _a;
|
||||
});
|
||||
// Count the number of occurences of a character in a string.
|
||||
helpers.count = (count = function count(string, letter) {
|
||||
helpers.count = (count = function(string, letter) {
|
||||
var num, pos;
|
||||
num = 0;
|
||||
pos = string.indexOf(letter);
|
||||
pos = index_of(string, letter);
|
||||
while (pos !== -1) {
|
||||
num += 1;
|
||||
pos = string.indexOf(letter, pos + 1);
|
||||
pos = index_of(string, letter, pos + 1);
|
||||
}
|
||||
return num;
|
||||
});
|
||||
// Merge objects, returning a fresh copy with attributes from both sides.
|
||||
// Used every time `BaseNode#compile` is called, to allow properties in the
|
||||
// options hash to propagate down the tree without polluting other branches.
|
||||
helpers.merge = (merge = function merge(options, overrides) {
|
||||
helpers.merge = (merge = function(options, overrides) {
|
||||
var _a, _b, fresh, key, val;
|
||||
fresh = {};
|
||||
_a = options;
|
||||
@@ -60,7 +75,7 @@
|
||||
});
|
||||
// Extend a source object with the properties of another object (shallow copy).
|
||||
// We use this to simulate Node's deprecated `process.mixin`
|
||||
helpers.extend = (extend = function extend(object, properties) {
|
||||
helpers.extend = (extend = function(object, properties) {
|
||||
var _a, _b, key, val;
|
||||
_a = []; _b = properties;
|
||||
for (key in _b) { if (__hasProp.call(_b, key)) {
|
||||
@@ -71,7 +86,7 @@
|
||||
});
|
||||
// Return a completely flattened version of an array. Handy for getting a
|
||||
// list of `children` from the nodes.
|
||||
helpers.flatten = (flatten = function flatten(array) {
|
||||
helpers.flatten = (flatten = function(array) {
|
||||
var _a, _b, _c, item, memo;
|
||||
memo = [];
|
||||
_b = array;
|
||||
@@ -83,7 +98,7 @@
|
||||
});
|
||||
// Delete a key from an object, returning the value. Useful when a node is
|
||||
// looking for a particular method in an options hash.
|
||||
helpers.del = (del = function del(obj, key) {
|
||||
helpers.del = (del = function(obj, key) {
|
||||
var val;
|
||||
val = obj[key];
|
||||
delete obj[key];
|
||||
@@ -93,7 +108,7 @@
|
||||
// a series of delimiters, all of which must be nested correctly within the
|
||||
// contents of the string. This method allows us to have strings within
|
||||
// interpolations within strings, ad infinitum.
|
||||
helpers.balanced_string = (balanced_string = function balanced_string(str, delimited, options) {
|
||||
helpers.balanced_string = (balanced_string = function(str, delimited, options) {
|
||||
var _a, _b, _c, _d, close, i, levels, open, pair, slash;
|
||||
options = options || {};
|
||||
slash = delimited[0][0] === '/';
|
||||
|
||||
10
lib/index.js
Normal file
10
lib/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
(function(){
|
||||
var _a, key, val;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
// Loader for CoffeeScript as a Node.js library.
|
||||
_a = require('./coffee-script');
|
||||
for (key in _a) { if (__hasProp.call(_a, key)) {
|
||||
val = _a[key];
|
||||
(exports[key] = val);
|
||||
}}
|
||||
})();
|
||||
225
lib/lexer.js
225
lib/lexer.js
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var ACCESSORS, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_ESCAPE, REGEX_FLAGS, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, balanced_string, compact, count, helpers, include, starts;
|
||||
var ACCESSORS, ASSIGNMENT, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, CONVERSIONS, HALF_ASSIGNMENTS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, LINE_BREAK, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, _a, _b, _c, balanced_string, compact, count, helpers, include, starts;
|
||||
var __slice = Array.prototype.slice;
|
||||
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
|
||||
// matches against the beginning of the source code. When a match is found,
|
||||
@@ -9,26 +9,29 @@
|
||||
// Which is a format that can be fed directly into [Jison](http://github.com/zaach/jison).
|
||||
// Set up the Lexer for both Node.js and the browser, depending on where we are.
|
||||
if ((typeof process !== "undefined" && process !== null)) {
|
||||
Rewriter = require('./rewriter').Rewriter;
|
||||
helpers = require('./helpers').helpers;
|
||||
_a = require('./rewriter');
|
||||
Rewriter = _a.Rewriter;
|
||||
_b = require('./helpers');
|
||||
helpers = _b.helpers;
|
||||
} else {
|
||||
this.exports = this;
|
||||
Rewriter = this.Rewriter;
|
||||
helpers = this.helpers;
|
||||
}
|
||||
// Import the helpers we need.
|
||||
include = helpers.include;
|
||||
count = helpers.count;
|
||||
starts = helpers.starts;
|
||||
compact = helpers.compact;
|
||||
balanced_string = helpers.balanced_string;
|
||||
_c = helpers;
|
||||
include = _c.include;
|
||||
count = _c.count;
|
||||
starts = _c.starts;
|
||||
compact = _c.compact;
|
||||
balanced_string = _c.balanced_string;
|
||||
// The Lexer Class
|
||||
// ---------------
|
||||
// The Lexer class reads a stream of CoffeeScript and divvys it up into tagged
|
||||
// tokens. Some potential ambiguity in the grammar has been avoided by
|
||||
// pushing some extra smarts into the Lexer.
|
||||
exports.Lexer = (function() {
|
||||
Lexer = function Lexer() { };
|
||||
Lexer = function() { };
|
||||
// **tokenize** is the Lexer's main method. Scan by attempting to match tokens
|
||||
// one at a time, using a regular expression anchored at the start of the
|
||||
// remaining code, or a custom recursive token-matching method
|
||||
@@ -39,7 +42,7 @@
|
||||
// of source.
|
||||
// Before returning the token stream, run it through the [Rewriter](rewriter.html)
|
||||
// unless explicitly asked not to.
|
||||
Lexer.prototype.tokenize = function tokenize(code, options) {
|
||||
Lexer.prototype.tokenize = function(code, options) {
|
||||
var o;
|
||||
code = code.replace(/(\r|\s+$)/g, '');
|
||||
o = options || {};
|
||||
@@ -68,7 +71,7 @@
|
||||
// At every position, run through this list of attempted matches,
|
||||
// short-circuiting if any of them succeed. Their order determines precedence:
|
||||
// `@literal_token` is the fallback catch-all.
|
||||
Lexer.prototype.extract_next_token = function extract_next_token() {
|
||||
Lexer.prototype.extract_next_token = function() {
|
||||
if (this.extension_token()) {
|
||||
return null;
|
||||
}
|
||||
@@ -105,11 +108,11 @@
|
||||
// ----------
|
||||
// Language extensions get the highest priority, first chance to tag tokens
|
||||
// as something else.
|
||||
Lexer.prototype.extension_token = function extension_token() {
|
||||
var _a, _b, _c, extension;
|
||||
_b = Lexer.extensions;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
extension = _b[_a];
|
||||
Lexer.prototype.extension_token = function() {
|
||||
var _d, _e, _f, extension;
|
||||
_e = Lexer.extensions;
|
||||
for (_d = 0, _f = _e.length; _d < _f; _d++) {
|
||||
extension = _e[_d];
|
||||
if (extension.call(this)) {
|
||||
return true;
|
||||
}
|
||||
@@ -122,7 +125,7 @@
|
||||
// allowed in JavaScript, we're careful not to tag them as keywords when
|
||||
// referenced as property names here, so you can still do `jQuery.is()` even
|
||||
// though `is` means `===` otherwise.
|
||||
Lexer.prototype.identifier_token = function identifier_token() {
|
||||
Lexer.prototype.identifier_token = function() {
|
||||
var accessed, id, tag;
|
||||
if (!(id = this.match(IDENTIFIER, 1))) {
|
||||
return false;
|
||||
@@ -140,7 +143,7 @@
|
||||
tag = 'LEADING_WHEN';
|
||||
}
|
||||
this.i += id.length;
|
||||
if (!accessed) {
|
||||
if (!(accessed)) {
|
||||
if (include(COFFEE_ALIASES, id)) {
|
||||
tag = (id = CONVERSIONS[id]);
|
||||
}
|
||||
@@ -152,7 +155,7 @@
|
||||
return true;
|
||||
};
|
||||
// Matches numbers, including decimals, hex, and exponential notation.
|
||||
Lexer.prototype.number_token = function number_token() {
|
||||
Lexer.prototype.number_token = function() {
|
||||
var number;
|
||||
if (!(number = this.match(NUMBER, 1))) {
|
||||
return false;
|
||||
@@ -163,7 +166,7 @@
|
||||
};
|
||||
// Matches strings, including multi-line strings. Ensures that quotation marks
|
||||
// are balanced within the string's contents, and within nested interpolations.
|
||||
Lexer.prototype.string_token = function string_token() {
|
||||
Lexer.prototype.string_token = function() {
|
||||
var string;
|
||||
if (!(starts(this.chunk, '"') || starts(this.chunk, "'"))) {
|
||||
return false;
|
||||
@@ -178,20 +181,48 @@
|
||||
};
|
||||
// Matches heredocs, adjusting indentation to the correct level, as heredocs
|
||||
// preserve whitespace, but ignore indentation to the left.
|
||||
Lexer.prototype.heredoc_token = function heredoc_token() {
|
||||
Lexer.prototype.heredoc_token = function() {
|
||||
var doc, match, quote;
|
||||
if (!(match = this.chunk.match(HEREDOC))) {
|
||||
return false;
|
||||
}
|
||||
quote = match[1].substr(0, 1);
|
||||
doc = this.sanitize_heredoc(match[2] || match[4], quote);
|
||||
doc = this.sanitize_heredoc(match[2] || match[4], {
|
||||
quote: quote
|
||||
});
|
||||
this.interpolate_string(("" + quote + doc + quote));
|
||||
this.line += count(match[1], "\n");
|
||||
this.i += match[1].length;
|
||||
return true;
|
||||
};
|
||||
// Matches and conumes comments. We pass through comments into JavaScript,
|
||||
// so they're treated as real tokens, like any other part of the language.
|
||||
Lexer.prototype.comment_token = function() {
|
||||
var comment, i, lines, match;
|
||||
if (!(match = this.chunk.match(COMMENT))) {
|
||||
return false;
|
||||
}
|
||||
if (match[3]) {
|
||||
comment = this.sanitize_heredoc(match[3], {
|
||||
herecomment: true
|
||||
});
|
||||
this.token('HERECOMMENT', comment.split(MULTILINER));
|
||||
} else {
|
||||
lines = compact(match[1].replace(COMMENT_CLEANER, '').split(MULTILINER));
|
||||
i = this.tokens.length - 1;
|
||||
if (this.unfinished()) {
|
||||
while (this.tokens[i] && !include(LINE_BREAK, this.tokens[i][0])) {
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
this.tokens.splice(i + 1, 0, ['COMMENT', lines, this.line], ['TERMINATOR', '\n', this.line]);
|
||||
}
|
||||
this.line += count(match[1], "\n");
|
||||
this.i += match[1].length;
|
||||
return true;
|
||||
};
|
||||
// Matches JavaScript interpolated directly into the source via backticks.
|
||||
Lexer.prototype.js_token = function js_token() {
|
||||
Lexer.prototype.js_token = function() {
|
||||
var script;
|
||||
if (!(starts(this.chunk, '`'))) {
|
||||
return false;
|
||||
@@ -207,8 +238,8 @@
|
||||
// to distinguish from division, so we borrow some basic heuristics from
|
||||
// JavaScript and Ruby, borrow slash balancing from `@balanced_token`, and
|
||||
// borrow interpolation from `@interpolate_string`.
|
||||
Lexer.prototype.regex_token = function regex_token() {
|
||||
var flags, regex, str;
|
||||
Lexer.prototype.regex_token = function() {
|
||||
var end, flags, regex, str;
|
||||
if (!(this.chunk.match(REGEX_START))) {
|
||||
return false;
|
||||
}
|
||||
@@ -218,7 +249,12 @@
|
||||
if (!(regex = this.balanced_token(['/', '/']))) {
|
||||
return false;
|
||||
}
|
||||
regex += (flags = this.chunk.substr(regex.length).match(REGEX_FLAGS));
|
||||
if (!(end = this.chunk.substr(regex.length).match(REGEX_END))) {
|
||||
return false;
|
||||
}
|
||||
if (end[2]) {
|
||||
regex += (flags = end[2]);
|
||||
}
|
||||
if (regex.match(REGEX_INTERPOLATION)) {
|
||||
str = regex.substring(1).split('/')[0];
|
||||
str = str.replace(REGEX_ESCAPE, function(escaped) {
|
||||
@@ -235,30 +271,12 @@
|
||||
};
|
||||
// Matches a token in which which the passed delimiter pairs must be correctly
|
||||
// balanced (ie. strings, JS literals).
|
||||
Lexer.prototype.balanced_token = function balanced_token() {
|
||||
Lexer.prototype.balanced_token = function() {
|
||||
var delimited;
|
||||
delimited = __slice.call(arguments, 0, arguments.length - 0);
|
||||
var _d = arguments.length, _e = _d >= 1;
|
||||
delimited = __slice.call(arguments, 0, _d - 0);
|
||||
return balanced_string(this.chunk, delimited);
|
||||
};
|
||||
// Matches and conumes comments. We pass through comments into JavaScript,
|
||||
// so they're treated as real tokens, like any other part of the language.
|
||||
Lexer.prototype.comment_token = function comment_token() {
|
||||
var comment, i, lines;
|
||||
if (!(comment = this.match(COMMENT, 1))) {
|
||||
return false;
|
||||
}
|
||||
this.line += (comment.match(MULTILINER) || []).length;
|
||||
lines = compact(comment.replace(COMMENT_CLEANER, '').split(MULTILINER));
|
||||
i = this.tokens.length - 1;
|
||||
if (this.unfinished()) {
|
||||
while (this.tokens[i] && !include(LINE_BREAK, this.tokens[i][0])) {
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
this.tokens.splice(i + 1, 0, ['COMMENT', lines, this.line], ['TERMINATOR', '\n', this.line]);
|
||||
this.i += comment.length;
|
||||
return true;
|
||||
};
|
||||
// Matches newlines, indents, and outdents, and determines which is which.
|
||||
// If we can detect that the current line is continued onto the the next line,
|
||||
// then the newline is suppressed:
|
||||
@@ -267,12 +285,12 @@
|
||||
// .map( ... )
|
||||
// Keeps track of the level of indentation, because a single outdent token
|
||||
// can close multiple indents, so we need to know how far in we happen to be.
|
||||
Lexer.prototype.line_token = function line_token() {
|
||||
Lexer.prototype.line_token = function() {
|
||||
var diff, indent, next_character, no_newlines, prev, size;
|
||||
if (!(indent = this.match(MULTI_DENT, 1))) {
|
||||
return false;
|
||||
}
|
||||
this.line += indent.match(MULTILINER).length;
|
||||
this.line += count(indent, "\n");
|
||||
this.i += indent.length;
|
||||
prev = this.prev(2);
|
||||
size = indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length;
|
||||
@@ -298,7 +316,7 @@
|
||||
};
|
||||
// Record an outdent token or multiple tokens, if we happen to be moving back
|
||||
// inwards past several recorded indents.
|
||||
Lexer.prototype.outdent_token = function outdent_token(move_out, no_newlines) {
|
||||
Lexer.prototype.outdent_token = function(move_out, no_newlines) {
|
||||
var last_indent;
|
||||
while (move_out > 0 && this.indents.length) {
|
||||
last_indent = this.indents.pop();
|
||||
@@ -312,7 +330,7 @@
|
||||
};
|
||||
// Matches and consumes non-meaningful whitespace. Tag the previous token
|
||||
// as being "spaced", because there are some cases where it makes a difference.
|
||||
Lexer.prototype.whitespace_token = function whitespace_token() {
|
||||
Lexer.prototype.whitespace_token = function() {
|
||||
var prev, space;
|
||||
if (!(space = this.match(WHITESPACE, 1))) {
|
||||
return false;
|
||||
@@ -325,7 +343,7 @@
|
||||
return true;
|
||||
};
|
||||
// Generate a newline token. Consecutive newlines get merged together.
|
||||
Lexer.prototype.newline_token = function newline_token(newlines) {
|
||||
Lexer.prototype.newline_token = function(newlines) {
|
||||
if (!(this.tag() === 'TERMINATOR')) {
|
||||
this.token('TERMINATOR', "\n");
|
||||
}
|
||||
@@ -333,7 +351,7 @@
|
||||
};
|
||||
// Use a `\` at a line-ending to suppress the newline.
|
||||
// The slash is removed here once its job is done.
|
||||
Lexer.prototype.suppress_newlines = function suppress_newlines() {
|
||||
Lexer.prototype.suppress_newlines = function() {
|
||||
if (this.value() === "\\") {
|
||||
this.tokens.pop();
|
||||
}
|
||||
@@ -344,7 +362,7 @@
|
||||
// the proper order of operations. There are some symbols that we tag specially
|
||||
// here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish
|
||||
// parentheses that indicate a method call from regular parentheses, and so on.
|
||||
Lexer.prototype.literal_token = function literal_token() {
|
||||
Lexer.prototype.literal_token = function() {
|
||||
var match, prev_spaced, space, tag, value;
|
||||
match = this.chunk.match(OPERATOR);
|
||||
value = match && match[1];
|
||||
@@ -388,7 +406,7 @@
|
||||
// ------------------
|
||||
// As we consume a new `IDENTIFIER`, look at the previous token to determine
|
||||
// if it's a special kind of accessor.
|
||||
Lexer.prototype.name_access_type = function name_access_type() {
|
||||
Lexer.prototype.name_access_type = function() {
|
||||
if (this.value() === '::') {
|
||||
this.tag(1, 'PROTOTYPE_ACCESS');
|
||||
}
|
||||
@@ -401,15 +419,24 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
// Sanitize a heredoc by escaping internal double quotes and erasing all
|
||||
// external indentation on the left-hand side.
|
||||
Lexer.prototype.sanitize_heredoc = function sanitize_heredoc(doc, quote) {
|
||||
var indent;
|
||||
indent = (doc.match(HEREDOC_INDENT) || ['']).sort()[0];
|
||||
return doc.replace(new RegExp("^" + indent, 'gm'), '').replace(MULTILINER, "\\n").replace(new RegExp(quote, 'g'), '\\"');
|
||||
// Sanitize a heredoc or herecomment by escaping internal double quotes and
|
||||
// erasing all external indentation on the left-hand side.
|
||||
Lexer.prototype.sanitize_heredoc = function(doc, options) {
|
||||
var _d, attempt, indent, match;
|
||||
while (match = HEREDOC_INDENT.exec(doc)) {
|
||||
attempt = (typeof (_d = match[2]) !== "undefined" && _d !== null) ? match[2] : match[3];
|
||||
if (!indent || attempt.length < indent.length) {
|
||||
indent = attempt;
|
||||
}
|
||||
}
|
||||
doc = doc.replace(new RegExp("^" + indent, 'gm'), '');
|
||||
if (options.herecomment) {
|
||||
return doc;
|
||||
}
|
||||
return doc.replace(MULTILINER, "\\n").replace(new RegExp(options.quote, 'g'), '\\"');
|
||||
};
|
||||
// Tag a half assignment.
|
||||
Lexer.prototype.tag_half_assignment = function tag_half_assignment(tag) {
|
||||
Lexer.prototype.tag_half_assignment = function(tag) {
|
||||
var last;
|
||||
last = this.tokens.pop();
|
||||
this.tokens.push([("" + tag + "="), ("" + tag + "="), last[2]]);
|
||||
@@ -418,8 +445,8 @@
|
||||
// A source of ambiguity in our grammar used to be parameter lists in function
|
||||
// definitions versus argument lists in function calls. Walk backwards, tagging
|
||||
// parameters specially in order to make things easier for the parser.
|
||||
Lexer.prototype.tag_parameters = function tag_parameters() {
|
||||
var _a, i, tok;
|
||||
Lexer.prototype.tag_parameters = function() {
|
||||
var _d, i, tok;
|
||||
if (this.tag() !== ')') {
|
||||
return null;
|
||||
}
|
||||
@@ -430,11 +457,11 @@
|
||||
if (!tok) {
|
||||
return null;
|
||||
}
|
||||
if ((_a = tok[0]) === 'IDENTIFIER') {
|
||||
if ((_d = tok[0]) === 'IDENTIFIER') {
|
||||
tok[0] = 'PARAM';
|
||||
} else if (_a === ')') {
|
||||
} else if (_d === ')') {
|
||||
tok[0] = 'PARAM_END';
|
||||
} else if (_a === '(') {
|
||||
} else if (_d === '(' || _d === 'CALL_START') {
|
||||
tok[0] = 'PARAM_START';
|
||||
return tok[0];
|
||||
}
|
||||
@@ -442,17 +469,17 @@
|
||||
return true;
|
||||
};
|
||||
// Close up all remaining open blocks at the end of the file.
|
||||
Lexer.prototype.close_indentation = function close_indentation() {
|
||||
Lexer.prototype.close_indentation = function() {
|
||||
return this.outdent_token(this.indent);
|
||||
};
|
||||
// The error for when you try to use a forbidden word in JavaScript as
|
||||
// an identifier.
|
||||
Lexer.prototype.identifier_error = function identifier_error(word) {
|
||||
Lexer.prototype.identifier_error = function(word) {
|
||||
throw new Error(("SyntaxError: Reserved word \"" + word + "\" on line " + (this.line + 1)));
|
||||
};
|
||||
// The error for when you try to assign to a reserved word in JavaScript,
|
||||
// like "function" or "default".
|
||||
Lexer.prototype.assignment_error = function assignment_error() {
|
||||
Lexer.prototype.assignment_error = function() {
|
||||
throw new Error(("SyntaxError: Reserved word \"" + (this.value()) + "\" on line " + (this.line + 1) + " can't be assigned"));
|
||||
};
|
||||
// Expand variables and expressions inside double-quoted strings using
|
||||
@@ -463,24 +490,24 @@
|
||||
// If it encounters an interpolation, this method will recursively create a
|
||||
// new Lexer, tokenize the interpolated contents, and merge them into the
|
||||
// token stream.
|
||||
Lexer.prototype.interpolate_string = function interpolate_string(str, escape_quotes) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, escaped, expr, group, i, idx, inner, interp, interpolated, lexer, match, nested, pi, quote, tag, tok, token, tokens, value;
|
||||
Lexer.prototype.interpolate_string = function(str, escape_quotes) {
|
||||
var _d, _e, _f, _g, _h, _i, _j, escaped, expr, group, i, idx, inner, interp, interpolated, lexer, match, nested, pi, quote, tag, tok, token, tokens, value;
|
||||
if (str.length < 3 || !starts(str, '"')) {
|
||||
return this.token('STRING', str);
|
||||
} else {
|
||||
lexer = new Lexer();
|
||||
tokens = [];
|
||||
quote = str.substring(0, 1);
|
||||
_a = [1, 1];
|
||||
i = _a[0];
|
||||
pi = _a[1];
|
||||
_d = [1, 1];
|
||||
i = _d[0];
|
||||
pi = _d[1];
|
||||
while (i < str.length - 1) {
|
||||
if (starts(str, '\\', i)) {
|
||||
i += 1;
|
||||
} else if ((match = str.substring(i).match(INTERPOLATION))) {
|
||||
_b = match;
|
||||
group = _b[0];
|
||||
interp = _b[1];
|
||||
_e = match;
|
||||
group = _e[0];
|
||||
interp = _e[1];
|
||||
if (starts(interp, '@')) {
|
||||
interp = ("this." + (interp.substring(1)));
|
||||
}
|
||||
@@ -499,9 +526,9 @@
|
||||
nested = lexer.tokenize(("(" + inner + ")"), {
|
||||
line: this.line
|
||||
});
|
||||
_c = nested;
|
||||
for (idx = 0, _d = _c.length; idx < _d; idx++) {
|
||||
tok = _c[idx];
|
||||
_f = nested;
|
||||
for (idx = 0, _g = _f.length; idx < _g; idx++) {
|
||||
tok = _f[idx];
|
||||
tok[0] === 'CALL_END' ? (tok[0] = ')') : null;
|
||||
}
|
||||
nested.pop();
|
||||
@@ -524,12 +551,12 @@
|
||||
if (interpolated) {
|
||||
this.token('(', '(');
|
||||
}
|
||||
_e = tokens;
|
||||
for (i = 0, _f = _e.length; i < _f; i++) {
|
||||
token = _e[i];
|
||||
_g = token;
|
||||
tag = _g[0];
|
||||
value = _g[1];
|
||||
_h = tokens;
|
||||
for (i = 0, _i = _h.length; i < _i; i++) {
|
||||
token = _h[i];
|
||||
_j = token;
|
||||
tag = _j[0];
|
||||
value = _j[1];
|
||||
if (tag === 'TOKENS') {
|
||||
this.tokens = this.tokens.concat(value);
|
||||
} else if (tag === 'STRING' && escape_quotes) {
|
||||
@@ -551,11 +578,11 @@
|
||||
// Helpers
|
||||
// -------
|
||||
// Add a token to the results, taking note of the line number.
|
||||
Lexer.prototype.token = function token(tag, value) {
|
||||
Lexer.prototype.token = function(tag, value) {
|
||||
return this.tokens.push([tag, value, this.line]);
|
||||
};
|
||||
// Peek at a tag in the current token stream.
|
||||
Lexer.prototype.tag = function tag(index, new_tag) {
|
||||
Lexer.prototype.tag = function(index, new_tag) {
|
||||
var tok;
|
||||
if (!(tok = this.prev(index))) {
|
||||
return null;
|
||||
@@ -567,7 +594,7 @@
|
||||
return tok[0];
|
||||
};
|
||||
// Peek at a value in the current token stream.
|
||||
Lexer.prototype.value = function value(index, val) {
|
||||
Lexer.prototype.value = function(index, val) {
|
||||
var tok;
|
||||
if (!(tok = this.prev(index))) {
|
||||
return null;
|
||||
@@ -579,12 +606,12 @@
|
||||
return tok[1];
|
||||
};
|
||||
// Peek at a previous token, entire.
|
||||
Lexer.prototype.prev = function prev(index) {
|
||||
Lexer.prototype.prev = function(index) {
|
||||
return this.tokens[this.tokens.length - (index || 1)];
|
||||
};
|
||||
// Attempt to match a string against the current chunk, returning the indexed
|
||||
// match if successful, and `false` otherwise.
|
||||
Lexer.prototype.match = function match(regex, index) {
|
||||
Lexer.prototype.match = function(regex, index) {
|
||||
var m;
|
||||
if (!(m = this.chunk.match(regex))) {
|
||||
return false;
|
||||
@@ -596,7 +623,7 @@
|
||||
}
|
||||
};
|
||||
// Are we in the midst of an unfinished expression?
|
||||
Lexer.prototype.unfinished = function unfinished() {
|
||||
Lexer.prototype.unfinished = function() {
|
||||
var prev;
|
||||
prev = this.prev(2);
|
||||
return this.value() && this.value().match && this.value().match(NO_NEWLINE) && prev && (prev[0] !== '.') && !this.value().match(CODE);
|
||||
@@ -614,14 +641,14 @@
|
||||
// CoffeeScript-only keywords, which we're more relaxed about allowing. They can't
|
||||
// be used standalone, but you can reference them as an attached property.
|
||||
COFFEE_ALIASES = ["and", "or", "is", "isnt", "not"];
|
||||
COFFEE_KEYWORDS = COFFEE_ALIASES.concat(["then", "unless", "yes", "no", "on", "off", "of", "by", "where", "when"]);
|
||||
COFFEE_KEYWORDS = COFFEE_ALIASES.concat(["then", "unless", "until", "yes", "no", "on", "off", "of", "by", "where", "when"]);
|
||||
// The combined list of keywords is the superset that gets passed verbatim to
|
||||
// the parser.
|
||||
KEYWORDS = JS_KEYWORDS.concat(COFFEE_KEYWORDS);
|
||||
// The list of keywords that are reserved by JavaScript, but not used, or are
|
||||
// used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
// to avoid having a JavaScript error at runtime.
|
||||
RESERVED = ["case", "default", "do", "function", "var", "void", "with", "const", "let", "debugger", "enum", "export", "import", "native"];
|
||||
RESERVED = ["case", "default", "do", "function", "var", "void", "with", "const", "let", "enum", "export", "import", "native"];
|
||||
// The superset of both JavaScript keywords and reserved words, none of which may
|
||||
// be used as identifiers or properties.
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
@@ -632,7 +659,7 @@
|
||||
INTERPOLATION = /^\$([a-zA-Z_@]\w*(\.\w+)*)/;
|
||||
OPERATOR = /^([+\*&|\/\-%=<>:!?]+)([ \t]*)/;
|
||||
WHITESPACE = /^([ \t]+)/;
|
||||
COMMENT = /^(((\n?[ \t]*)?#[^\n]*)+)/;
|
||||
COMMENT = /^((\n?[ \t]*)?#{3}(?!#)\n*([\s\S]*?)\n*([ \t]*)#{3}|((\n?[ \t]*)?#[^\n]*)+)/;
|
||||
CODE = /^((-|=)>)/;
|
||||
MULTI_DENT = /^((\n([ \t]*))+)(\.)?/;
|
||||
LAST_DENTS = /\n([ \t]*)/g;
|
||||
@@ -641,7 +668,7 @@
|
||||
// Regex-matching-regexes.
|
||||
REGEX_START = /^\/[^\/ ]/;
|
||||
REGEX_INTERPOLATION = /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/;
|
||||
REGEX_FLAGS = /^[imgy]{0,4}/;
|
||||
REGEX_END = /^(([imgy]{1,4})\b|\W)/;
|
||||
REGEX_ESCAPE = /\\[^\$]/g;
|
||||
// Token cleaning regexes.
|
||||
JS_CLEANER = /(^`|`$)/g;
|
||||
@@ -649,12 +676,12 @@
|
||||
STRING_NEWLINES = /\n[ \t]*/g;
|
||||
COMMENT_CLEANER = /(^[ \t]*#|\n[ \t]*$)/mg;
|
||||
NO_NEWLINE = /^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/;
|
||||
HEREDOC_INDENT = /^[ \t]+/mg;
|
||||
HEREDOC_INDENT = /(\n+([ \t]*)|^([ \t]+))/g;
|
||||
// Tokens which a regular expression will never immediately follow, but which
|
||||
// a division operator might.
|
||||
// See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
|
||||
// Our list is shorter, due to sans-parentheses method calls.
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE'];
|
||||
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'];
|
||||
// Tokens which could legitimately be invoked or indexed. A opening
|
||||
// parentheses or bracket following these tokens will be recorded as the start
|
||||
// of a function invocation or indexing operation.
|
||||
|
||||
1030
lib/nodes.js
1030
lib/nodes.js
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
// parser: new OptionParser switches, help_banner
|
||||
// options: parser.parse process.argv
|
||||
exports.OptionParser = (function() {
|
||||
OptionParser = function OptionParser(rules, banner) {
|
||||
OptionParser = function(rules, banner) {
|
||||
this.banner = banner;
|
||||
this.rules = build_rules(rules);
|
||||
return this;
|
||||
@@ -18,7 +18,7 @@
|
||||
// containing the remaning non-option arguments. This is a simpler API than
|
||||
// many option parsers that allow you to attach callback actions for every
|
||||
// flag. Instead, you're responsible for interpreting the options object.
|
||||
OptionParser.prototype.parse = function parse(args) {
|
||||
OptionParser.prototype.parse = function(args) {
|
||||
var _a, _b, _c, arg, is_option, matched_rule, options, rule;
|
||||
options = {
|
||||
arguments: []
|
||||
@@ -47,8 +47,8 @@
|
||||
};
|
||||
// Return the help text for this **OptionParser**, listing and describing all
|
||||
// of the valid options, for `--help` and such.
|
||||
OptionParser.prototype.help = function help() {
|
||||
var _a, _b, _c, _d, _e, _f, _g, i, let_part, lines, rule, spaces;
|
||||
OptionParser.prototype.help = function() {
|
||||
var _a, _b, _c, _d, _e, _f, i, let_part, lines, rule, spaces;
|
||||
lines = ['Available options:'];
|
||||
if (this.banner) {
|
||||
lines.unshift(("" + this.banner + "\n"));
|
||||
@@ -58,8 +58,8 @@
|
||||
rule = _b[_a];
|
||||
spaces = 15 - rule.long_flag.length;
|
||||
spaces = spaces > 0 ? (function() {
|
||||
_d = []; _f = 0; _g = spaces;
|
||||
for (_e = 0, i = _f; (_f <= _g ? i <= _g : i >= _g); (_f <= _g ? i += 1 : i -= 1), _e++) {
|
||||
_d = []; _e = 0; _f = spaces;
|
||||
for (i = _e; (_e <= _f ? i <= _f : i >= _f); (_e <= _f ? i += 1 : i -= 1)) {
|
||||
_d.push(' ');
|
||||
}
|
||||
return _d;
|
||||
@@ -80,7 +80,7 @@
|
||||
OPTIONAL = /\[(.+)\]/;
|
||||
// Build and return the list of option rules. If the optional *short-flag* is
|
||||
// unspecified, leave it out by padding with `null`.
|
||||
build_rules = function build_rules(rules) {
|
||||
build_rules = function(rules) {
|
||||
var _a, _b, _c, _d, tuple;
|
||||
_a = []; _c = rules;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
@@ -96,7 +96,7 @@
|
||||
};
|
||||
// Build a rule from a `-o` short flag, a `--output [DIR]` long flag, and the
|
||||
// description of what the option does.
|
||||
build_rule = function build_rule(short_flag, long_flag, description) {
|
||||
build_rule = function(short_flag, long_flag, description) {
|
||||
var match;
|
||||
match = long_flag.match(OPTIONAL);
|
||||
long_flag = long_flag.match(LONG_FLAG)[1];
|
||||
@@ -110,7 +110,7 @@
|
||||
};
|
||||
// Normalize arguments by expanding merged flags into multiple flags. This allows
|
||||
// you to have `-wl` be the same as `--watch --lint`.
|
||||
normalize_arguments = function normalize_arguments(args) {
|
||||
normalize_arguments = function(args) {
|
||||
var _a, _b, _c, _d, _e, _f, arg, l, match, result;
|
||||
args = args.slice(0);
|
||||
result = [];
|
||||
|
||||
466
lib/parser.js
466
lib/parser.js
File diff suppressed because one or more lines are too long
@@ -11,14 +11,14 @@
|
||||
prompt = 'coffee> ';
|
||||
// Quick alias for quitting the REPL.
|
||||
helpers.extend(global, {
|
||||
quit: function quit() {
|
||||
quit: function() {
|
||||
return process.exit(0);
|
||||
}
|
||||
});
|
||||
// The main REPL function. **run** is called every time a line of code is entered.
|
||||
// Attempt to evaluate the command. If there's an exception, print it out instead
|
||||
// of exiting.
|
||||
run = function run(buffer) {
|
||||
run = function(buffer) {
|
||||
var val;
|
||||
try {
|
||||
val = CoffeeScript.run(buffer.toString(), {
|
||||
|
||||
228
lib/rewriter.js
228
lib/rewriter.js
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, helpers, include, pair;
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, helpers, include, pair;
|
||||
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
|
||||
return function() {
|
||||
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
||||
@@ -13,23 +13,25 @@
|
||||
// parentheses, balance incorrect nestings, and generally clean things up.
|
||||
// Set up exported variables for both Node.js and the browser.
|
||||
if ((typeof process !== "undefined" && process !== null)) {
|
||||
helpers = require('./helpers').helpers;
|
||||
_a = require('./helpers');
|
||||
helpers = _a.helpers;
|
||||
} else {
|
||||
this.exports = this;
|
||||
helpers = this.helpers;
|
||||
}
|
||||
// Import the helpers we need.
|
||||
include = helpers.include;
|
||||
_b = helpers;
|
||||
include = _b.include;
|
||||
// The **Rewriter** class is used by the [Lexer](lexer.html), directly against
|
||||
// its internal array of tokens.
|
||||
exports.Rewriter = (function() {
|
||||
Rewriter = function Rewriter() { };
|
||||
Rewriter = function() { };
|
||||
// Rewrite the token stream in multiple passes, one logical filter at
|
||||
// a time. This could certainly be changed into a single pass through the
|
||||
// stream, with a big ol' efficient switch, but it's much nicer to work with
|
||||
// like this. The order of these passes matters -- indentation must be
|
||||
// corrected before implicit parentheses can be wrapped around blocks of code.
|
||||
Rewriter.prototype.rewrite = function rewrite(tokens) {
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
this.tokens = tokens;
|
||||
this.adjust_comments();
|
||||
this.remove_leading_newlines();
|
||||
@@ -46,7 +48,7 @@
|
||||
// forwards (or backwards) in the stream, to make sure we don't miss anything
|
||||
// as tokens are inserted and removed, and the stream changes length under
|
||||
// our feet.
|
||||
Rewriter.prototype.scan_tokens = function scan_tokens(block) {
|
||||
Rewriter.prototype.scan_tokens = function(block) {
|
||||
var i, move;
|
||||
i = 0;
|
||||
while (true) {
|
||||
@@ -60,16 +62,18 @@
|
||||
};
|
||||
// Massage newlines and indentations so that comments don't have to be
|
||||
// correctly indented, or appear on a line of their own.
|
||||
Rewriter.prototype.adjust_comments = function adjust_comments() {
|
||||
Rewriter.prototype.adjust_comments = function() {
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var after;
|
||||
var _c, after, before;
|
||||
if (!(token[0] === 'COMMENT')) {
|
||||
return 1;
|
||||
}
|
||||
after = this.tokens[i + 2];
|
||||
_c = [this.tokens[i - 2], this.tokens[i + 2]];
|
||||
before = _c[0];
|
||||
after = _c[1];
|
||||
if (after && after[0] === 'INDENT') {
|
||||
this.tokens.splice(i + 2, 1);
|
||||
this.tokens.splice(i, 0, after);
|
||||
before && before[0] === 'OUTDENT' && post && (prev[0] === post[0]) && (post[0] === 'TERMINATOR') ? this.tokens.splice(i - 2, 1) : this.tokens.splice(i, 0, after);
|
||||
return 1;
|
||||
} else if (prev && prev[0] !== 'TERMINATOR' && prev[0] !== 'INDENT' && prev[0] !== 'OUTDENT') {
|
||||
this.tokens.splice(i, 0, ['TERMINATOR', "\n", prev[2]]);
|
||||
@@ -81,17 +85,17 @@
|
||||
};
|
||||
// Leading newlines would introduce an ambiguity in the grammar, so we
|
||||
// dispatch them here.
|
||||
Rewriter.prototype.remove_leading_newlines = function remove_leading_newlines() {
|
||||
var _a;
|
||||
_a = [];
|
||||
Rewriter.prototype.remove_leading_newlines = function() {
|
||||
var _c;
|
||||
_c = [];
|
||||
while (this.tokens[0] && this.tokens[0][0] === 'TERMINATOR') {
|
||||
_a.push(this.tokens.shift());
|
||||
_c.push(this.tokens.shift());
|
||||
}
|
||||
return _a;
|
||||
return _c;
|
||||
};
|
||||
// Some blocks occur in the middle of expressions -- when we're expecting
|
||||
// this, remove their trailing newlines.
|
||||
Rewriter.prototype.remove_mid_expression_newlines = function remove_mid_expression_newlines() {
|
||||
Rewriter.prototype.remove_mid_expression_newlines = function() {
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
if (!(post && include(EXPRESSION_CLOSE, post[0]) && token[0] === 'TERMINATOR')) {
|
||||
return 1;
|
||||
@@ -103,28 +107,28 @@
|
||||
// The lexer has tagged the opening parenthesis of a method call, and the
|
||||
// opening bracket of an indexing operation. Match them with their paired
|
||||
// close.
|
||||
Rewriter.prototype.close_open_calls_and_indexes = function close_open_calls_and_indexes() {
|
||||
Rewriter.prototype.close_open_calls_and_indexes = function() {
|
||||
var brackets, parens;
|
||||
parens = [0];
|
||||
brackets = [0];
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var _a;
|
||||
if ((_a = token[0]) === 'CALL_START') {
|
||||
var _c;
|
||||
if ((_c = token[0]) === 'CALL_START') {
|
||||
parens.push(0);
|
||||
} else if (_a === 'INDEX_START') {
|
||||
} else if (_c === 'INDEX_START') {
|
||||
brackets.push(0);
|
||||
} else if (_a === '(') {
|
||||
} else if (_c === '(') {
|
||||
parens[parens.length - 1] += 1;
|
||||
} else if (_a === '[') {
|
||||
} else if (_c === '[') {
|
||||
brackets[brackets.length - 1] += 1;
|
||||
} else if (_a === ')') {
|
||||
} else if (_c === ')') {
|
||||
if (parens[parens.length - 1] === 0) {
|
||||
parens.pop();
|
||||
token[0] = 'CALL_END';
|
||||
} else {
|
||||
parens[parens.length - 1] -= 1;
|
||||
}
|
||||
} else if (_a === ']') {
|
||||
} else if (_c === ']') {
|
||||
if (brackets[brackets.length - 1] === 0) {
|
||||
brackets.pop();
|
||||
token[0] = 'INDEX_END';
|
||||
@@ -138,71 +142,81 @@
|
||||
// Methods may be optionally called without parentheses, for simple cases.
|
||||
// Insert the implicit parentheses here, so that the parser doesn't have to
|
||||
// deal with them.
|
||||
Rewriter.prototype.add_implicit_parentheses = function add_implicit_parentheses() {
|
||||
var calls, parens, stack, start_parens;
|
||||
Rewriter.prototype.add_implicit_parentheses = function() {
|
||||
var close_calls, stack;
|
||||
stack = [0];
|
||||
calls = 0;
|
||||
parens = 0;
|
||||
start_parens = 0;
|
||||
close_calls = __bind(function(i) {
|
||||
var _c, _d, size, tmp;
|
||||
_c = 0; _d = stack[stack.length - 1];
|
||||
for (tmp = _c; (_c <= _d ? tmp < _d : tmp > _d); (_c <= _d ? tmp += 1 : tmp -= 1)) {
|
||||
this.tokens.splice(i, 0, ['CALL_END', ')', this.tokens[i][2]]);
|
||||
}
|
||||
size = stack[stack.length - 1] + 1;
|
||||
stack[stack.length - 1] = 0;
|
||||
return size;
|
||||
}, this);
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var _a, _b, _c, idx, last, open, size, stack_pointer, tag, tmp;
|
||||
var j, nx, open, size, tag;
|
||||
tag = token[0];
|
||||
if (tag === 'CALL_START') {
|
||||
calls += 1;
|
||||
} else if (tag === 'CALL_END') {
|
||||
calls -= 1;
|
||||
} else if (tag === '(') {
|
||||
parens += 1;
|
||||
} else if (tag === ')') {
|
||||
parens -= 1;
|
||||
} else if (tag === 'INDENT') {
|
||||
stack.push(0);
|
||||
} else if (tag === 'OUTDENT') {
|
||||
last = stack.pop();
|
||||
stack[stack.length - 1] += last;
|
||||
if (tag === 'OUTDENT') {
|
||||
stack[stack.length - 2] += stack.pop();
|
||||
}
|
||||
open = stack[stack.length - 1] > 0;
|
||||
if (!(typeof post !== "undefined" && post !== null) || (start_parens > parens) || (start_parens === parens && include(IMPLICIT_END, tag))) {
|
||||
if (tag === 'INDENT' && prev && include(IMPLICIT_BLOCK, prev[0])) {
|
||||
return 1;
|
||||
if (prev && prev.spaced && include(IMPLICIT_FUNC, prev[0]) && include(IMPLICIT_CALL, tag)) {
|
||||
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
stack[stack.length - 1] += 1;
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
stack.push(0);
|
||||
}
|
||||
if (tag === 'OUTDENT' && token.generated) {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
if (tag === 'INDENT' && !token.generated && open && !(prev && include(IMPLICIT_BLOCK, prev[0]))) {
|
||||
size = close_calls(i);
|
||||
stack.push(0);
|
||||
return size;
|
||||
}
|
||||
if (open || tag === 'INDENT') {
|
||||
idx = tag === 'OUTDENT' ? i + 1 : i;
|
||||
stack_pointer = tag === 'INDENT' ? 2 : 1;
|
||||
_b = 0; _c = stack[stack.length - stack_pointer];
|
||||
for (_a = 0, tmp = _b; (_b <= _c ? tmp < _c : tmp > _c); (_b <= _c ? tmp += 1 : tmp -= 1), _a++) {
|
||||
this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
|
||||
stack.push(0);
|
||||
return 1;
|
||||
}
|
||||
if (open && !token.generated && (!post || include(IMPLICIT_END, tag))) {
|
||||
j = 1;
|
||||
while ((typeof (nx = this.tokens[i + j]) !== "undefined" && (nx = this.tokens[i + j]) !== null) && include(IMPLICIT_END, nx[0])) {
|
||||
j++;
|
||||
}
|
||||
if ((typeof nx !== "undefined" && nx !== null) && nx[0] === ',') {
|
||||
if (tag === 'TERMINATOR') {
|
||||
this.tokens.splice(i, 1);
|
||||
}
|
||||
} else {
|
||||
size = close_calls(i);
|
||||
if (tag !== 'OUTDENT' && include(EXPRESSION_END, tag)) {
|
||||
stack.pop();
|
||||
}
|
||||
size = stack[stack.length - stack_pointer] + 1;
|
||||
stack[stack.length - stack_pointer] = 0;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
if (!(prev && include(IMPLICIT_FUNC, prev[0]) && include(IMPLICIT_CALL, tag))) {
|
||||
if (tag !== 'OUTDENT' && include(EXPRESSION_END, tag)) {
|
||||
stack[stack.length - 2] += stack.pop();
|
||||
return 1;
|
||||
}
|
||||
calls = 0;
|
||||
start_parens = tag === '(' ? parens - 1 : parens;
|
||||
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
stack[stack.length - 1] += 1;
|
||||
return 2;
|
||||
return 1;
|
||||
}, this));
|
||||
};
|
||||
// Because our grammar is LALR(1), it can't handle some single-line
|
||||
// expressions that lack ending delimiters. The **Rewriter** adds the implicit
|
||||
// blocks, so it doesn't need to. ')' can close a single-line block,
|
||||
// but we need to make sure it's balanced.
|
||||
Rewriter.prototype.add_implicit_indentation = function add_implicit_indentation() {
|
||||
Rewriter.prototype.add_implicit_indentation = function() {
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var idx, insertion, outdent, parens, pre, starter, tok;
|
||||
var idx, indent, insertion, outdent, parens, pre, starter, tok;
|
||||
if (!(include(SINGLE_LINERS, token[0]) && post[0] !== 'INDENT' && !(token[0] === 'ELSE' && post[0] === 'IF'))) {
|
||||
return 1;
|
||||
}
|
||||
starter = token[0];
|
||||
this.tokens.splice(i + 1, 0, ['INDENT', 2, token[2]]);
|
||||
indent = ['INDENT', 2, token[2]];
|
||||
indent.generated = true;
|
||||
this.tokens.splice(i + 1, 0, indent);
|
||||
idx = i + 1;
|
||||
parens = 0;
|
||||
while (true) {
|
||||
@@ -232,18 +246,18 @@
|
||||
};
|
||||
// Ensure that all listed pairs of tokens are correctly balanced throughout
|
||||
// the course of the token stream.
|
||||
Rewriter.prototype.ensure_balance = function ensure_balance(pairs) {
|
||||
var _a, _b, key, levels, line, open, open_line, unclosed, value;
|
||||
Rewriter.prototype.ensure_balance = function(pairs) {
|
||||
var _c, _d, key, levels, line, open, open_line, unclosed, value;
|
||||
levels = {};
|
||||
open_line = {};
|
||||
this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var _a, _b, _c, _d, close, open, pair;
|
||||
_b = pairs;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
pair = _b[_a];
|
||||
_d = pair;
|
||||
open = _d[0];
|
||||
close = _d[1];
|
||||
var _c, _d, _e, _f, close, open, pair;
|
||||
_d = pairs;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
pair = _d[_c];
|
||||
_f = pair;
|
||||
open = _f[0];
|
||||
close = _f[1];
|
||||
levels[open] = levels[open] || 0;
|
||||
if (token[0] === open) {
|
||||
if (levels[open] === 0) {
|
||||
@@ -261,12 +275,12 @@
|
||||
return 1;
|
||||
}, this));
|
||||
unclosed = (function() {
|
||||
_a = []; _b = levels;
|
||||
for (key in _b) { if (__hasProp.call(_b, key)) {
|
||||
value = _b[key];
|
||||
value > 0 ? _a.push(key) : null;
|
||||
_c = []; _d = levels;
|
||||
for (key in _d) { if (__hasProp.call(_d, key)) {
|
||||
value = _d[key];
|
||||
value > 0 ? _c.push(key) : null;
|
||||
}}
|
||||
return _a;
|
||||
return _c;
|
||||
})();
|
||||
if (unclosed.length) {
|
||||
open = unclosed[0];
|
||||
@@ -285,17 +299,19 @@
|
||||
// it with the inverse of what we've just popped.
|
||||
// 3. Keep track of "debt" for tokens that we manufacture, to make sure we end
|
||||
// up balanced in the end.
|
||||
Rewriter.prototype.rewrite_closing_parens = function rewrite_closing_parens() {
|
||||
var _a, debt, key, stack, val;
|
||||
// 4. Be careful not to alter array or parentheses delimiters with overzealous
|
||||
// rewriting.
|
||||
Rewriter.prototype.rewrite_closing_parens = function() {
|
||||
var _c, debt, key, stack, val;
|
||||
stack = [];
|
||||
debt = {};
|
||||
_a = INVERSES;
|
||||
for (key in _a) { if (__hasProp.call(_a, key)) {
|
||||
val = _a[key];
|
||||
_c = INVERSES;
|
||||
for (key in _c) { if (__hasProp.call(_c, key)) {
|
||||
val = _c[key];
|
||||
(debt[key] = 0);
|
||||
}}
|
||||
return this.scan_tokens(__bind(function(prev, token, post, i) {
|
||||
var inv, match, mtag, tag;
|
||||
var inv, match, mtag, oppos, tag;
|
||||
tag = token[0];
|
||||
inv = INVERSES[token[0]];
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
@@ -309,12 +325,18 @@
|
||||
} else {
|
||||
match = stack.pop();
|
||||
mtag = match[0];
|
||||
if (tag === INVERSES[mtag]) {
|
||||
oppos = INVERSES[mtag];
|
||||
if (tag === oppos) {
|
||||
return 1;
|
||||
}
|
||||
debt[mtag] += 1;
|
||||
val = mtag === 'INDENT' ? match[1] : INVERSES[mtag];
|
||||
this.tokens.splice(i, 0, [INVERSES[mtag], val]);
|
||||
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
|
||||
if ((this.tokens[i + 2] == undefined ? undefined : this.tokens[i + 2][0]) === mtag) {
|
||||
this.tokens.splice(i + 3, 0, val);
|
||||
stack.push(match);
|
||||
} else {
|
||||
this.tokens.splice(i, 0, val);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
@@ -331,40 +353,40 @@
|
||||
// The inverse mappings of `BALANCED_PAIRS` we're trying to fix up, so we can
|
||||
// look things up from either end.
|
||||
INVERSES = {};
|
||||
_b = BALANCED_PAIRS;
|
||||
for (_a = 0, _c = _b.length; _a < _c; _a++) {
|
||||
pair = _b[_a];
|
||||
_d = BALANCED_PAIRS;
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
pair = _d[_c];
|
||||
INVERSES[pair[0]] = pair[1];
|
||||
INVERSES[pair[1]] = pair[0];
|
||||
}
|
||||
// The tokens that signal the start of a balanced pair.
|
||||
EXPRESSION_START = (function() {
|
||||
_d = []; _f = BALANCED_PAIRS;
|
||||
for (_e = 0, _g = _f.length; _e < _g; _e++) {
|
||||
pair = _f[_e];
|
||||
_d.push(pair[0]);
|
||||
_f = []; _h = BALANCED_PAIRS;
|
||||
for (_g = 0, _i = _h.length; _g < _i; _g++) {
|
||||
pair = _h[_g];
|
||||
_f.push(pair[0]);
|
||||
}
|
||||
return _d;
|
||||
return _f;
|
||||
})();
|
||||
// The tokens that signal the end of a balanced pair.
|
||||
EXPRESSION_END = (function() {
|
||||
_h = []; _j = BALANCED_PAIRS;
|
||||
for (_i = 0, _k = _j.length; _i < _k; _i++) {
|
||||
pair = _j[_i];
|
||||
_h.push(pair[1]);
|
||||
_j = []; _l = BALANCED_PAIRS;
|
||||
for (_k = 0, _m = _l.length; _k < _m; _k++) {
|
||||
pair = _l[_k];
|
||||
_j.push(pair[1]);
|
||||
}
|
||||
return _h;
|
||||
return _j;
|
||||
})();
|
||||
// Tokens that indicate the close of a clause of an expression.
|
||||
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
|
||||
// Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-'];
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-', '@'];
|
||||
// If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT', 'THIS', 'NULL', '@', '->', '=>', '[', '(', '{'];
|
||||
// Tokens indicating that the implicit call must enclose a block of expressions.
|
||||
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
|
||||
// Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT'];
|
||||
IMPLICIT_END = ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'TERMINATOR', 'INDENT'].concat(EXPRESSION_END);
|
||||
// Single-line flavors of block expressions that have unclosed endings.
|
||||
// The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
SINGLE_LINERS = ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN'];
|
||||
|
||||
26
lib/scope.js
26
lib/scope.js
@@ -12,7 +12,7 @@
|
||||
this.exports = this;
|
||||
}
|
||||
exports.Scope = (function() {
|
||||
Scope = function Scope(parent, expressions, method) {
|
||||
Scope = function(parent, expressions, method) {
|
||||
var _a;
|
||||
_a = [parent, expressions, method];
|
||||
this.parent = _a[0];
|
||||
@@ -35,7 +35,7 @@
|
||||
// it wraps.
|
||||
// Look up a variable name in lexical scope, and declare it if it does not
|
||||
// already exist.
|
||||
Scope.prototype.find = function find(name) {
|
||||
Scope.prototype.find = function(name) {
|
||||
if (this.check(name)) {
|
||||
return true;
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
return false;
|
||||
};
|
||||
// Test variables and return true the first time fn(v, k) returns true
|
||||
Scope.prototype.any = function any(fn) {
|
||||
Scope.prototype.any = function(fn) {
|
||||
var _a, k, v;
|
||||
_a = this.variables;
|
||||
for (v in _a) { if (__hasProp.call(_a, v)) {
|
||||
@@ -56,12 +56,12 @@
|
||||
};
|
||||
// Reserve a variable name as originating from a function parameter for this
|
||||
// scope. No `var` required for internal references.
|
||||
Scope.prototype.parameter = function parameter(name) {
|
||||
Scope.prototype.parameter = function(name) {
|
||||
this.variables[name] = 'param';
|
||||
return this.variables[name];
|
||||
};
|
||||
// Just check to see if a variable has already been declared, without reserving.
|
||||
Scope.prototype.check = function check(name) {
|
||||
Scope.prototype.check = function(name) {
|
||||
if (this.variables[name]) {
|
||||
return true;
|
||||
}
|
||||
@@ -69,7 +69,7 @@
|
||||
};
|
||||
// If we need to store an intermediate result, find an available name for a
|
||||
// compiler-generated variable. `_a`, `_b`, and so on...
|
||||
Scope.prototype.free_variable = function free_variable() {
|
||||
Scope.prototype.free_variable = function() {
|
||||
var ordinal;
|
||||
while (this.check(this.temp_var)) {
|
||||
ordinal = 1 + parseInt(this.temp_var.substr(1), 36);
|
||||
@@ -80,7 +80,7 @@
|
||||
};
|
||||
// Ensure that an assignment is made at the top of this scope
|
||||
// (or at the top-level scope, if requested).
|
||||
Scope.prototype.assign = function assign(name, value) {
|
||||
Scope.prototype.assign = function(name, value) {
|
||||
this.variables[name] = {
|
||||
value: value,
|
||||
assigned: true
|
||||
@@ -89,20 +89,20 @@
|
||||
};
|
||||
// Does this scope reference any variables that need to be declared in the
|
||||
// given function body?
|
||||
Scope.prototype.has_declarations = function has_declarations(body) {
|
||||
Scope.prototype.has_declarations = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return val === 'var';
|
||||
});
|
||||
};
|
||||
// Does this scope reference any assignments that need to be declared at the
|
||||
// top of the given function body?
|
||||
Scope.prototype.has_assignments = function has_assignments(body) {
|
||||
Scope.prototype.has_assignments = function(body) {
|
||||
return body === this.expressions && this.any(function(k, val) {
|
||||
return val.assigned;
|
||||
});
|
||||
};
|
||||
// Return the list of variables first declared in this scope.
|
||||
Scope.prototype.declared_variables = function declared_variables() {
|
||||
Scope.prototype.declared_variables = function() {
|
||||
var _a, _b, key, val;
|
||||
return (function() {
|
||||
_a = []; _b = this.variables;
|
||||
@@ -115,7 +115,7 @@
|
||||
};
|
||||
// Return the list of assignments that are supposed to be made at the top
|
||||
// of this scope.
|
||||
Scope.prototype.assigned_variables = function assigned_variables() {
|
||||
Scope.prototype.assigned_variables = function() {
|
||||
var _a, _b, key, val;
|
||||
_a = []; _b = this.variables;
|
||||
for (key in _b) { if (__hasProp.call(_b, key)) {
|
||||
@@ -125,11 +125,11 @@
|
||||
return _a;
|
||||
};
|
||||
// Compile the JavaScript for all of the variable declarations in this scope.
|
||||
Scope.prototype.compiled_declarations = function compiled_declarations() {
|
||||
Scope.prototype.compiled_declarations = function() {
|
||||
return this.declared_variables().join(', ');
|
||||
};
|
||||
// Compile the JavaScript for all of the variable assignments in this scope.
|
||||
Scope.prototype.compiled_assignments = function compiled_assignments() {
|
||||
Scope.prototype.compiled_assignments = function() {
|
||||
return this.assigned_variables().join(', ');
|
||||
};
|
||||
return Scope;
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"description": "Unfancy JavaScript",
|
||||
"keywords": ["javascript", "language"],
|
||||
"author": "Jeremy Ashkenas",
|
||||
"version": "0.6.1"
|
||||
"version": "0.6.2"
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ exports.run: ->
|
||||
path.exists 'Cakefile', (exists) ->
|
||||
throw new Error("Cakefile not found in ${process.cwd()}") unless exists
|
||||
args: process.argv[2...process.argv.length]
|
||||
CoffeeScript.run fs.readFileSync('Cakefile'), {source: 'Cakefile'}
|
||||
CoffeeScript.run fs.readFileSync('Cakefile').toString(), {source: 'Cakefile'}
|
||||
oparse: new optparse.OptionParser switches
|
||||
return print_tasks() unless args.length
|
||||
options: oparse.parse(args)
|
||||
@@ -66,5 +66,5 @@ print_tasks: ->
|
||||
|
||||
# Print an error and exit when attempting to all an undefined task.
|
||||
no_such_task: (task) ->
|
||||
puts "No such task: \"$task\"\n"
|
||||
puts "No such task: \"$task\""
|
||||
process.exit 1
|
||||
|
||||
@@ -22,7 +22,7 @@ else
|
||||
helpers: this.helpers
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
exports.VERSION: '0.6.1'
|
||||
exports.VERSION: '0.6.2'
|
||||
|
||||
# Instantiate a Lexer for our use here.
|
||||
lexer: new Lexer()
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
# interactive REPL.
|
||||
|
||||
# External dependencies.
|
||||
fs: require 'fs'
|
||||
path: require 'path'
|
||||
optparse: require './optparse'
|
||||
CoffeeScript: require './coffee-script'
|
||||
{spawn: spawn, exec: exec}: require('child_process')
|
||||
fs: require 'fs'
|
||||
path: require 'path'
|
||||
optparse: require './optparse'
|
||||
CoffeeScript: require './coffee-script'
|
||||
{spawn, exec}: require('child_process')
|
||||
|
||||
# The help banner that is printed when `coffee` is called without arguments.
|
||||
BANNER: '''
|
||||
@@ -58,25 +58,31 @@ exports.run: ->
|
||||
flags: sources[(separator + 1)...sources.length]
|
||||
sources: sources[0...separator]
|
||||
process.ARGV: process.argv: flags
|
||||
watch_scripts() if options.watch
|
||||
compile_scripts()
|
||||
|
||||
# Asynchronously read in each CoffeeScript in a list of source files and
|
||||
# compile them.
|
||||
# compile them. If a directory is passed, recursively compile all source
|
||||
# files in it and all subdirectories.
|
||||
compile_scripts: ->
|
||||
compile: (source) ->
|
||||
path.exists source, (exists) ->
|
||||
throw new Error "File not found: $source" unless exists
|
||||
fs.readFile source, (err, code) -> compile_script(source, code)
|
||||
run: -> compile(source) for source in sources
|
||||
return run() unless options.output and options.compile
|
||||
exec "mkdir -p $options.output", run
|
||||
for source in sources
|
||||
base: source
|
||||
compile: (source) ->
|
||||
path.exists source, (exists) ->
|
||||
throw new Error "File not found: $source" unless exists
|
||||
fs.stat source, (err, stats) ->
|
||||
if stats.isDirectory()
|
||||
fs.readdir source, (err, files) ->
|
||||
for file in files
|
||||
compile path.join(source, file)
|
||||
else if path.extname(source) is '.coffee'
|
||||
fs.readFile source, (err, code) -> compile_script(source, code.toString(), base)
|
||||
watch source, base if options.watch
|
||||
compile source
|
||||
|
||||
# Compile a single source script, containing the given code, according to the
|
||||
# requested options. Both compile_scripts and watch_scripts share this method
|
||||
# in common. If evaluating the script directly sets `__filename`, `__dirname`
|
||||
# and `module.filename` to be correct relative to the script's path.
|
||||
compile_script: (source, code) ->
|
||||
# requested options. If evaluating the script directly sets `__filename`,
|
||||
# `__dirname` and `module.filename` to be correct relative to the script's path.
|
||||
compile_script: (source, code, base) ->
|
||||
o: options
|
||||
code_opts: compile_options source
|
||||
try
|
||||
@@ -86,7 +92,7 @@ compile_script: (source, code) ->
|
||||
else
|
||||
js: CoffeeScript.compile code, code_opts
|
||||
if o.print then print js
|
||||
else if o.compile then write_js source, js
|
||||
else if o.compile then write_js source, js, base
|
||||
else if o.lint then lint js
|
||||
catch err
|
||||
if o.watch then puts err.message else throw err
|
||||
@@ -101,29 +107,32 @@ compile_stdio: ->
|
||||
stdin.addListener 'end', ->
|
||||
compile_script 'stdio', code
|
||||
|
||||
# Watch a list of source CoffeeScript files using `fs.watchFile`, recompiling
|
||||
# them every time the files are updated. May be used in combination with other
|
||||
# options, such as `--lint` or `--print`.
|
||||
watch_scripts: ->
|
||||
watch: (source) ->
|
||||
fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
|
||||
return if curr.mtime.getTime() is prev.mtime.getTime()
|
||||
fs.readFile source, (err, code) -> compile_script(source, code)
|
||||
watch(source) for source in sources
|
||||
# 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`.
|
||||
watch: (source, base) ->
|
||||
fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
|
||||
return if curr.mtime.getTime() is prev.mtime.getTime()
|
||||
puts "Compiled $source" if options.compile
|
||||
fs.readFile source, (err, code) -> compile_script(source, code.toString(), base)
|
||||
|
||||
# Write out a JavaScript source file with the compiled code. By default, files
|
||||
# are written out in `cwd` as `.js` files with the same name, but the output
|
||||
# directory can be customized with `--output`.
|
||||
write_js: (source, js) ->
|
||||
write_js: (source, js, base) ->
|
||||
filename: path.basename(source, path.extname(source)) + '.js'
|
||||
dir: options.output or path.dirname(source)
|
||||
src_dir: path.dirname source
|
||||
base_dir: src_dir.substring base.length
|
||||
dir: if options.output then path.join options.output, base_dir else src_dir
|
||||
js_path: path.join dir, filename
|
||||
fs.writeFile js_path, js
|
||||
compile: -> fs.writeFile js_path, js
|
||||
path.exists dir, (exists) ->
|
||||
if exists then compile() else exec "mkdir -p $dir", compile
|
||||
|
||||
# Pipe compiled JS through JSLint (requires a working `jsl` command), printing
|
||||
# any errors or warnings that arise.
|
||||
lint: (js) ->
|
||||
print_it: (buffer) -> puts buffer.toString()
|
||||
print_it: (buffer) -> print buffer.toString()
|
||||
jsl: spawn 'jsl', ['-nologo', '-stdin']
|
||||
jsl.stdout.addListener 'data', print_it
|
||||
jsl.stderr.addListener 'data', print_it
|
||||
|
||||
@@ -65,19 +65,19 @@ grammar: {
|
||||
o "Body TERMINATOR Line", -> $1.push $3
|
||||
o "Body TERMINATOR"
|
||||
]
|
||||
|
||||
|
||||
# Expressions and statements, which make up a line in a body.
|
||||
Line: [
|
||||
o "Expression"
|
||||
o "Statement"
|
||||
]
|
||||
|
||||
|
||||
# Pure statements which cannot be expressions.
|
||||
Statement: [
|
||||
o "Return"
|
||||
o "Throw"
|
||||
o "BREAK", -> new LiteralNode yytext
|
||||
o "CONTINUE", -> new LiteralNode yytext
|
||||
o "BREAK", -> new LiteralNode $1
|
||||
o "CONTINUE", -> new LiteralNode $1
|
||||
]
|
||||
|
||||
# All the different types of expressions in our language. The basic unit of
|
||||
@@ -115,22 +115,22 @@ grammar: {
|
||||
|
||||
# A literal identifier, a variable name or property.
|
||||
Identifier: [
|
||||
o "IDENTIFIER", -> new LiteralNode yytext
|
||||
o "IDENTIFIER", -> new LiteralNode $1
|
||||
]
|
||||
|
||||
# Alphanumerics are separated from the other **Literal** matchers because
|
||||
# they can also serve as keys in object literals.
|
||||
AlphaNumeric: [
|
||||
o "NUMBER", -> new LiteralNode yytext
|
||||
o "STRING", -> new LiteralNode yytext
|
||||
o "NUMBER", -> new LiteralNode $1
|
||||
o "STRING", -> new LiteralNode $1
|
||||
]
|
||||
|
||||
# All of our immediate values. These can (in general), be passed straight
|
||||
# through and printed to JavaScript.
|
||||
Literal: [
|
||||
o "AlphaNumeric"
|
||||
o "JS", -> new LiteralNode yytext
|
||||
o "REGEX", -> new LiteralNode yytext
|
||||
o "JS", -> new LiteralNode $1
|
||||
o "REGEX", -> new LiteralNode $1
|
||||
o "TRUE", -> new LiteralNode true
|
||||
o "FALSE", -> new LiteralNode false
|
||||
o "YES", -> new LiteralNode true
|
||||
@@ -147,6 +147,8 @@ grammar: {
|
||||
# Assignment when it happens within an object literal. The difference from
|
||||
# the ordinary **Assign** is that these allow numbers and strings as keys.
|
||||
AssignObj: [
|
||||
o "Identifier", -> new ValueNode $1
|
||||
o "AlphaNumeric"
|
||||
o "Identifier ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "AlphaNumeric ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
|
||||
o "Comment"
|
||||
@@ -162,7 +164,8 @@ grammar: {
|
||||
# have to parse comments like any other construct, and identify all of the
|
||||
# positions in which they can occur in the grammar.
|
||||
Comment: [
|
||||
o "COMMENT", -> new CommentNode yytext
|
||||
o "COMMENT", -> new CommentNode $1
|
||||
o "HERECOMMENT", -> new CommentNode $1, 'herecomment'
|
||||
]
|
||||
|
||||
# [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
|
||||
@@ -185,6 +188,12 @@ grammar: {
|
||||
o "=>", -> 'boundfunc'
|
||||
]
|
||||
|
||||
# An optional, trailing comma.
|
||||
OptComma: [
|
||||
o ''
|
||||
o ','
|
||||
]
|
||||
|
||||
# The list of parameters that a function accepts can be of any length.
|
||||
ParamList: [
|
||||
o "", -> []
|
||||
@@ -195,7 +204,7 @@ grammar: {
|
||||
# A single parameter in a function definition can be ordinary, or a splat
|
||||
# that hoovers up the remaining arguments.
|
||||
Param: [
|
||||
o "PARAM", -> new LiteralNode yytext
|
||||
o "PARAM", -> new LiteralNode $1
|
||||
o "Param . . .", -> new SplatNode $1
|
||||
]
|
||||
|
||||
@@ -249,10 +258,7 @@ grammar: {
|
||||
|
||||
# In CoffeeScript, an object literal is simply a list of assignments.
|
||||
Object: [
|
||||
o "{ AssignList }", -> new ObjectNode $2
|
||||
o "{ IndentedAssignList }", -> new ObjectNode $2
|
||||
o "{ AssignList , }", -> new ObjectNode $2
|
||||
o "{ IndentedAssignList , }", -> new ObjectNode $2
|
||||
o "{ AssignList OptComma }", -> new ObjectNode $2
|
||||
]
|
||||
|
||||
# Assignment of properties within an object literal can be separated by
|
||||
@@ -261,14 +267,8 @@ grammar: {
|
||||
o "", -> []
|
||||
o "AssignObj", -> [$1]
|
||||
o "AssignList , AssignObj", -> $1.concat [$3]
|
||||
o "AssignList TERMINATOR AssignObj", -> $1.concat [$3]
|
||||
o "AssignList , TERMINATOR AssignObj", -> $1.concat [$4]
|
||||
]
|
||||
|
||||
# An **AssignList** within a block indentation.
|
||||
IndentedAssignList: [
|
||||
o "INDENT AssignList OUTDENT", -> $2
|
||||
o "INDENT AssignList , OUTDENT", -> $2
|
||||
o "AssignList OptComma TERMINATOR AssignObj", -> $1.concat [$4]
|
||||
o "AssignList OptComma INDENT AssignList OptComma OUTDENT", -> $1.concat $4
|
||||
]
|
||||
|
||||
# Class definitions have optional bodies of prototype property assignments,
|
||||
@@ -320,14 +320,12 @@ grammar: {
|
||||
|
||||
# The list of arguments to a function call.
|
||||
Arguments: [
|
||||
o "CALL_START ArgList CALL_END", -> $2
|
||||
o "CALL_START ArgList , CALL_END", -> $2
|
||||
o "CALL_START ArgList OptComma CALL_END", -> $2
|
||||
]
|
||||
|
||||
# Calling super.
|
||||
Super: [
|
||||
o "SUPER CALL_START ArgList CALL_END", -> new CallNode 'super', $3
|
||||
o "SUPER CALL_START ArgList , CALL_END", -> new CallNode 'super', $3
|
||||
o "SUPER CALL_START ArgList OptComma CALL_END", -> new CallNode 'super', $3
|
||||
]
|
||||
|
||||
# A reference to the *this* current object.
|
||||
@@ -355,8 +353,7 @@ grammar: {
|
||||
|
||||
# The array literal.
|
||||
Array: [
|
||||
o "[ ArgList ]", -> new ArrayNode $2
|
||||
o "[ ArgList , ]", -> new ArrayNode $2
|
||||
o "[ ArgList OptComma ]", -> new ArrayNode $2
|
||||
]
|
||||
|
||||
# The **ArgList** is both the list of objects passed into a function call,
|
||||
@@ -370,8 +367,7 @@ grammar: {
|
||||
o "ArgList TERMINATOR Expression", -> $1.concat [$3]
|
||||
o "ArgList , TERMINATOR Expression", -> $1.concat [$4]
|
||||
o "ArgList , INDENT Expression", -> $1.concat [$4]
|
||||
o "ArgList OUTDENT"
|
||||
o "ArgList , OUTDENT"
|
||||
o "ArgList OptComma OUTDENT"
|
||||
]
|
||||
|
||||
# Just simple, comma-separated, required arguments (no fancy syntax). We need
|
||||
@@ -411,13 +407,15 @@ grammar: {
|
||||
# A language extension to CoffeeScript from the outside. We simply pass
|
||||
# it through unaltered.
|
||||
Extension: [
|
||||
o "EXTENSION", -> yytext
|
||||
o "EXTENSION"
|
||||
]
|
||||
|
||||
# The condition portion of a while loop.
|
||||
WhileSource: [
|
||||
o "WHILE Expression", -> new WhileNode $2
|
||||
o "WHILE Expression WHEN Expression", -> new WhileNode $2, {filter : $4}
|
||||
o "WHILE Expression WHEN Expression", -> new WhileNode $2, {guard : $4}
|
||||
o "UNTIL Expression", -> new WhileNode $2, {invert: true}
|
||||
o "UNTIL Expression WHEN Expression", -> new WhileNode $2, {invert: true, guard: $4}
|
||||
]
|
||||
|
||||
# The while loop can either be normal, with a block of expressions to execute,
|
||||
@@ -437,45 +435,55 @@ grammar: {
|
||||
o "FOR ForVariables ForSource Block", -> new ForNode $4, $3, $2[0], $2[1]
|
||||
]
|
||||
|
||||
# An array of all accepted values for a variable inside the loop. This
|
||||
# enables support for pattern matching.
|
||||
ForValue: [
|
||||
o "Identifier"
|
||||
o "Array", -> new ValueNode $1
|
||||
o "Object", -> new ValueNode $1
|
||||
]
|
||||
|
||||
# An array or range comprehension has variables for the current element and
|
||||
# (optional) reference to the current index. Or, *key, value*, in the case
|
||||
# of object comprehensions.
|
||||
ForVariables: [
|
||||
o "Identifier", -> [$1]
|
||||
o "Identifier , Identifier", -> [$1, $3]
|
||||
o "ForValue", -> [$1]
|
||||
o "ForValue , ForValue", -> [$1, $3]
|
||||
]
|
||||
|
||||
# The source of a comprehension is an array or object with an optional filter
|
||||
# The source of a comprehension is an array or object with an optional guard
|
||||
# clause. If it's an array comprehension, you can also choose to step through
|
||||
# in fixed-size increments.
|
||||
ForSource: [
|
||||
o "IN Expression", -> {source: $2}
|
||||
o "OF Expression", -> {source: $2, object: true}
|
||||
o "IN Expression WHEN Expression", -> {source: $2, filter: $4}
|
||||
o "OF Expression WHEN Expression", -> {source: $2, filter: $4, object: true}
|
||||
o "IN Expression WHEN Expression", -> {source: $2, guard: $4}
|
||||
o "OF Expression WHEN Expression", -> {source: $2, guard: $4, object: true}
|
||||
o "IN Expression BY Expression", -> {source: $2, step: $4}
|
||||
o "IN Expression WHEN Expression BY Expression", -> {source: $2, filter: $4; step: $6}
|
||||
o "IN Expression BY Expression WHEN Expression", -> {source: $2, step: $4, filter: $6}
|
||||
o "IN Expression WHEN Expression BY Expression", -> {source: $2, guard: $4, step: $6}
|
||||
o "IN Expression BY Expression WHEN Expression", -> {source: $2, step: $4, guard: $6}
|
||||
]
|
||||
|
||||
# The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
# switch/case/default by compiling into an if-else chain.
|
||||
Switch: [
|
||||
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition $2
|
||||
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else $6, true
|
||||
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.switches_over $2
|
||||
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.switches_over($2).add_else $6, true
|
||||
o "SWITCH INDENT Whens OUTDENT", -> $3
|
||||
o "SWITCH INDENT Whens ELSE Block OUTDENT", -> $3.add_else $5, true
|
||||
]
|
||||
|
||||
# The inner list of whens is left recursive. At code-generation time, the
|
||||
# IfNode will rewrite them into a proper chain.
|
||||
Whens: [
|
||||
o "When"
|
||||
o "Whens When", -> $1.push $2
|
||||
o "Whens When", -> $1.add_else $2
|
||||
]
|
||||
|
||||
# An individual **When** clause, with action.
|
||||
When: [
|
||||
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, null, {statement: true}
|
||||
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, null, {statement: true}
|
||||
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, {statement: true}
|
||||
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, {statement: true}
|
||||
o "Comment TERMINATOR When", -> $3.comment: $1; $3
|
||||
]
|
||||
|
||||
@@ -484,6 +492,7 @@ grammar: {
|
||||
# ambiguity.
|
||||
IfStart: [
|
||||
o "IF Expression Block", -> new IfNode $2, $3
|
||||
o "UNLESS Expression Block", -> new IfNode $2, $3, {invert: true}
|
||||
o "IfStart ElsIf", -> $1.add_else $2
|
||||
]
|
||||
|
||||
@@ -502,10 +511,10 @@ grammar: {
|
||||
# *if* and *unless*.
|
||||
If: [
|
||||
o "IfBlock"
|
||||
o "Statement IF Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true}
|
||||
o "Expression IF Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true}
|
||||
o "Statement UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true, invert: true}
|
||||
o "Expression UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true, invert: true}
|
||||
o "Statement IF Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true}
|
||||
o "Expression IF Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true}
|
||||
o "Statement UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true, invert: true}
|
||||
o "Expression UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), {statement: true, invert: true}
|
||||
]
|
||||
|
||||
# Arithmetic and logical operators, working on one or more operands.
|
||||
@@ -595,10 +604,10 @@ operators: [
|
||||
["right", 'INDENT']
|
||||
["left", 'OUTDENT']
|
||||
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
|
||||
["right", 'FOR', 'NEW', 'SUPER', 'CLASS']
|
||||
["right", 'FOR', 'WHILE', 'UNTIL', 'NEW', 'SUPER', 'CLASS']
|
||||
["left", 'EXTENDS']
|
||||
["right", 'ASSIGN', 'RETURN']
|
||||
["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']
|
||||
["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE']
|
||||
]
|
||||
|
||||
# Wrapping Up
|
||||
|
||||
@@ -6,9 +6,17 @@
|
||||
this.exports: this unless process?
|
||||
helpers: exports.helpers: {}
|
||||
|
||||
# Cross-browser indexOf, so that IE can join the party.
|
||||
helpers.index_of: index_of: (array, item, from) ->
|
||||
return array.indexOf item, from if array.indexOf
|
||||
for other, index in array
|
||||
if other is item and (not from or (from <= index))
|
||||
return index
|
||||
-1
|
||||
|
||||
# Does a list include a value?
|
||||
helpers.include: include: (list, value) ->
|
||||
list.indexOf(value) >= 0
|
||||
index_of(list, value) >= 0
|
||||
|
||||
# Peek at the beginning of a given string to see if it matches a sequence.
|
||||
helpers.starts: starts: (string, literal, start) ->
|
||||
@@ -20,10 +28,10 @@ helpers.compact: compact: (array) -> item for item in array when item
|
||||
# Count the number of occurences of a character in a string.
|
||||
helpers.count: count: (string, letter) ->
|
||||
num: 0
|
||||
pos: string.indexOf(letter)
|
||||
pos: index_of string, letter
|
||||
while pos isnt -1
|
||||
num: + 1
|
||||
pos: string.indexOf(letter, pos + 1)
|
||||
pos: index_of string, letter, pos + 1
|
||||
num
|
||||
|
||||
# Merge objects, returning a fresh copy with attributes from both sides.
|
||||
|
||||
2
src/index.coffee
Normal file
2
src/index.coffee
Normal file
@@ -0,0 +1,2 @@
|
||||
# Loader for CoffeeScript as a Node.js library.
|
||||
(exports[key]: val) for key, val of require './coffee-script'
|
||||
@@ -9,19 +9,15 @@
|
||||
|
||||
# Set up the Lexer for both Node.js and the browser, depending on where we are.
|
||||
if process?
|
||||
Rewriter: require('./rewriter').Rewriter
|
||||
helpers: require('./helpers').helpers
|
||||
{Rewriter}: require('./rewriter')
|
||||
{helpers}: require('./helpers')
|
||||
else
|
||||
this.exports: this
|
||||
Rewriter: this.Rewriter
|
||||
helpers: this.helpers
|
||||
|
||||
# Import the helpers we need.
|
||||
include: helpers.include
|
||||
count: helpers.count
|
||||
starts: helpers.starts
|
||||
compact: helpers.compact
|
||||
balanced_string: helpers.balanced_string
|
||||
{include, count, starts, compact, balanced_string}: helpers
|
||||
|
||||
# The Lexer Class
|
||||
# ---------------
|
||||
@@ -100,7 +96,7 @@ exports.Lexer: class Lexer
|
||||
@identifier_error id if include RESERVED, id
|
||||
tag: 'LEADING_WHEN' if tag is 'WHEN' and include LINE_BREAK, @tag()
|
||||
@i: + id.length
|
||||
if not accessed
|
||||
unless accessed
|
||||
tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id
|
||||
return @tag_half_assignment tag if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
@token tag, id
|
||||
@@ -130,12 +126,29 @@ exports.Lexer: class Lexer
|
||||
heredoc_token: ->
|
||||
return false unless match: @chunk.match(HEREDOC)
|
||||
quote: match[1].substr 0, 1
|
||||
doc: @sanitize_heredoc match[2] or match[4], quote
|
||||
doc: @sanitize_heredoc match[2] or match[4], {quote}
|
||||
@interpolate_string "$quote$doc$quote"
|
||||
@line: + count match[1], "\n"
|
||||
@i: + match[1].length
|
||||
true
|
||||
|
||||
# Matches and conumes comments. We pass through comments into JavaScript,
|
||||
# so they're treated as real tokens, like any other part of the language.
|
||||
comment_token: ->
|
||||
return false unless match: @chunk.match(COMMENT)
|
||||
if match[3]
|
||||
comment: @sanitize_heredoc match[3], {herecomment: true}
|
||||
@token 'HERECOMMENT', comment.split MULTILINER
|
||||
else
|
||||
lines: compact match[1].replace(COMMENT_CLEANER, '').split MULTILINER
|
||||
i: @tokens.length - 1
|
||||
if @unfinished()
|
||||
i: - 1 while @tokens[i] and not include LINE_BREAK, @tokens[i][0]
|
||||
@tokens.splice(i + 1, 0, ['COMMENT', lines, @line], ['TERMINATOR', '\n', @line])
|
||||
@line: + count match[1], "\n"
|
||||
@i: + match[1].length
|
||||
true
|
||||
|
||||
# Matches JavaScript interpolated directly into the source via backticks.
|
||||
js_token: ->
|
||||
return false unless starts @chunk, '`'
|
||||
@@ -152,7 +165,8 @@ exports.Lexer: class Lexer
|
||||
return false unless @chunk.match REGEX_START
|
||||
return false if include NOT_REGEX, @tag()
|
||||
return false unless regex: @balanced_token ['/', '/']
|
||||
regex: + (flags: @chunk.substr(regex.length).match REGEX_FLAGS)
|
||||
return false unless end: @chunk.substr(regex.length).match REGEX_END
|
||||
regex: + flags: end[2] if end[2]
|
||||
if regex.match REGEX_INTERPOLATION
|
||||
str: regex.substring(1).split('/')[0]
|
||||
str: str.replace REGEX_ESCAPE, (escaped) -> '\\' + escaped
|
||||
@@ -169,19 +183,6 @@ exports.Lexer: class Lexer
|
||||
balanced_token: (delimited...) ->
|
||||
balanced_string @chunk, delimited
|
||||
|
||||
# Matches and conumes comments. We pass through comments into JavaScript,
|
||||
# so they're treated as real tokens, like any other part of the language.
|
||||
comment_token: ->
|
||||
return false unless comment: @match COMMENT, 1
|
||||
@line: + (comment.match(MULTILINER) or []).length
|
||||
lines: compact comment.replace(COMMENT_CLEANER, '').split MULTILINER
|
||||
i: @tokens.length - 1
|
||||
if @unfinished()
|
||||
i: - 1 while @tokens[i] and not include LINE_BREAK, @tokens[i][0]
|
||||
@tokens.splice(i + 1, 0, ['COMMENT', lines, @line], ['TERMINATOR', '\n', @line])
|
||||
@i: + comment.length
|
||||
true
|
||||
|
||||
# Matches newlines, indents, and outdents, and determines which is which.
|
||||
# If we can detect that the current line is continued onto the the next line,
|
||||
# then the newline is suppressed:
|
||||
@@ -194,7 +195,7 @@ exports.Lexer: class Lexer
|
||||
# can close multiple indents, so we need to know how far in we happen to be.
|
||||
line_token: ->
|
||||
return false unless indent: @match MULTI_DENT, 1
|
||||
@line: + indent.match(MULTILINER).length
|
||||
@line: + count indent, "\n"
|
||||
@i : + indent.length
|
||||
prev: @prev(2)
|
||||
size: indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length
|
||||
@@ -290,13 +291,16 @@ exports.Lexer: class Lexer
|
||||
else
|
||||
@tag 1, 'PROPERTY_ACCESS'
|
||||
|
||||
# Sanitize a heredoc by escaping internal double quotes and erasing all
|
||||
# external indentation on the left-hand side.
|
||||
sanitize_heredoc: (doc, quote) ->
|
||||
indent: (doc.match(HEREDOC_INDENT) or ['']).sort()[0]
|
||||
doc.replace(new RegExp("^" +indent, 'gm'), '')
|
||||
.replace(MULTILINER, "\\n")
|
||||
.replace(new RegExp(quote, 'g'), '\\"')
|
||||
# Sanitize a heredoc or herecomment by escaping internal double quotes and
|
||||
# erasing all external indentation on the left-hand side.
|
||||
sanitize_heredoc: (doc, options) ->
|
||||
while match: HEREDOC_INDENT.exec doc
|
||||
attempt: if match[2]? then match[2] else match[3]
|
||||
indent: attempt if not indent or attempt.length < indent.length
|
||||
doc: doc.replace(new RegExp("^" +indent, 'gm'), '')
|
||||
return doc if options.herecomment
|
||||
doc.replace(MULTILINER, "\\n")
|
||||
.replace(new RegExp(options.quote, 'g'), '\\"')
|
||||
|
||||
# Tag a half assignment.
|
||||
tag_half_assignment: (tag) ->
|
||||
@@ -315,9 +319,9 @@ exports.Lexer: class Lexer
|
||||
tok: @prev i
|
||||
return if not tok
|
||||
switch tok[0]
|
||||
when 'IDENTIFIER' then tok[0]: 'PARAM'
|
||||
when ')' then tok[0]: 'PARAM_END'
|
||||
when '(' then return tok[0]: 'PARAM_START'
|
||||
when 'IDENTIFIER' then tok[0]: 'PARAM'
|
||||
when ')' then tok[0]: 'PARAM_END'
|
||||
when '(', 'CALL_START' then return tok[0]: 'PARAM_START'
|
||||
true
|
||||
|
||||
# Close up all remaining open blocks at the end of the file.
|
||||
@@ -453,7 +457,7 @@ JS_KEYWORDS: [
|
||||
# be used standalone, but you can reference them as an attached property.
|
||||
COFFEE_ALIASES: ["and", "or", "is", "isnt", "not"]
|
||||
COFFEE_KEYWORDS: COFFEE_ALIASES.concat [
|
||||
"then", "unless",
|
||||
"then", "unless", "until",
|
||||
"yes", "no", "on", "off",
|
||||
"of", "by", "where", "when"
|
||||
]
|
||||
@@ -467,7 +471,7 @@ KEYWORDS: JS_KEYWORDS.concat COFFEE_KEYWORDS
|
||||
# to avoid having a JavaScript error at runtime.
|
||||
RESERVED: [
|
||||
"case", "default", "do", "function", "var", "void", "with"
|
||||
"const", "let", "debugger", "enum", "export", "import", "native"
|
||||
"const", "let", "enum", "export", "import", "native"
|
||||
]
|
||||
|
||||
# The superset of both JavaScript keywords and reserved words, none of which may
|
||||
@@ -481,7 +485,7 @@ HEREDOC : /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\
|
||||
INTERPOLATION : /^\$([a-zA-Z_@]\w*(\.\w+)*)/
|
||||
OPERATOR : /^([+\*&|\/\-%=<>:!?]+)([ \t]*)/
|
||||
WHITESPACE : /^([ \t]+)/
|
||||
COMMENT : /^(((\n?[ \t]*)?#[^\n]*)+)/
|
||||
COMMENT : /^((\n?[ \t]*)?#{3}(?!#)\n*([\s\S]*?)\n*([ \t]*)#{3}|((\n?[ \t]*)?#[^\n]*)+)/
|
||||
CODE : /^((-|=)>)/
|
||||
MULTI_DENT : /^((\n([ \t]*))+)(\.)?/
|
||||
LAST_DENTS : /\n([ \t]*)/g
|
||||
@@ -491,7 +495,7 @@ ASSIGNMENT : /^(:|=)$/
|
||||
# Regex-matching-regexes.
|
||||
REGEX_START : /^\/[^\/ ]/
|
||||
REGEX_INTERPOLATION: /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/
|
||||
REGEX_FLAGS : /^[imgy]{0,4}/
|
||||
REGEX_END : /^(([imgy]{1,4})\b|\W)/
|
||||
REGEX_ESCAPE : /\\[^\$]/g
|
||||
|
||||
# Token cleaning regexes.
|
||||
@@ -500,7 +504,7 @@ MULTILINER : /\n/g
|
||||
STRING_NEWLINES : /\n[ \t]*/g
|
||||
COMMENT_CLEANER : /(^[ \t]*#|\n[ \t]*$)/mg
|
||||
NO_NEWLINE : /^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/
|
||||
HEREDOC_INDENT : /^[ \t]+/mg
|
||||
HEREDOC_INDENT : /(\n+([ \t]*)|^([ \t]+))/g
|
||||
|
||||
# Tokens which a regular expression will never immediately follow, but which
|
||||
# a division operator might.
|
||||
@@ -509,7 +513,7 @@ HEREDOC_INDENT : /^[ \t]+/mg
|
||||
#
|
||||
# Our list is shorter, due to sans-parentheses method calls.
|
||||
NOT_REGEX: [
|
||||
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE'
|
||||
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'
|
||||
]
|
||||
|
||||
# Tokens which could legitimately be invoked or indexed. A opening
|
||||
|
||||
419
src/nodes.coffee
419
src/nodes.coffee
@@ -14,10 +14,7 @@ else
|
||||
Scope: this.Scope
|
||||
|
||||
# Import the helpers we plan to use.
|
||||
compact: helpers.compact
|
||||
flatten: helpers.flatten
|
||||
merge: helpers.merge
|
||||
del: helpers.del
|
||||
{compact, flatten, merge, del, index_of}: helpers
|
||||
|
||||
# Helper function that marks a node as a JavaScript *statement*, or as a
|
||||
# *pure_statement*. Statements must be wrapped in a closure when used as an
|
||||
@@ -27,6 +24,9 @@ statement: (klass, only) ->
|
||||
klass::is_statement: -> true
|
||||
(klass::is_pure_statement: -> true) if only
|
||||
|
||||
children: (klass, child_attrs...) ->
|
||||
klass::children_attributes: child_attrs
|
||||
|
||||
#### BaseNode
|
||||
|
||||
# The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
||||
@@ -53,7 +53,9 @@ exports.BaseNode: class BaseNode
|
||||
compile: (o) ->
|
||||
@options: merge o or {}
|
||||
@tab: o.indent
|
||||
del @options, 'operation' unless this instanceof ValueNode
|
||||
unless this instanceof ValueNode or this instanceof CallNode
|
||||
del @options, 'operation'
|
||||
del @options, 'chain_root' unless this instanceof AccessorNode or this instanceof IndexNode
|
||||
top: if @top_sensitive() then @options.top else del @options, 'top'
|
||||
closure: @is_statement() and not @is_pure_statement() and not top and
|
||||
not @options.as_statement and not (this instanceof CommentNode) and
|
||||
@@ -93,10 +95,12 @@ exports.BaseNode: class BaseNode
|
||||
# and returning true when the block finds a match. `contains` does not cross
|
||||
# scope boundaries.
|
||||
contains: (block) ->
|
||||
for node in @children
|
||||
return true if block(node)
|
||||
return true if node.contains and node.contains block
|
||||
false
|
||||
contains: false
|
||||
@traverse_children false, (node) ->
|
||||
if block(node)
|
||||
contains: true
|
||||
return false
|
||||
contains
|
||||
|
||||
# Is this node of a certain type, or does it contain the type?
|
||||
contains_type: (type) ->
|
||||
@@ -108,21 +112,33 @@ exports.BaseNode: class BaseNode
|
||||
@is_pure_statement() or @contains (n) -> n.is_pure_statement()
|
||||
|
||||
# Perform an in-order traversal of the AST. Crosses scope boundaries.
|
||||
traverse: (block) ->
|
||||
for node in @children
|
||||
block node
|
||||
node.traverse block if node.traverse
|
||||
traverse: (block) -> @traverse_children true, block
|
||||
|
||||
# `toString` representation of the node, for inspecting the parse tree.
|
||||
# This is what `coffee --nodes` prints out.
|
||||
toString: (idt) ->
|
||||
idt: or ''
|
||||
'\n' + idt + @constructor.name + (child.toString(idt + TAB) for child in @children).join('')
|
||||
'\n' + idt + @constructor.name + (child.toString(idt + TAB) for child in @children()).join('')
|
||||
|
||||
children: ->
|
||||
nodes: []
|
||||
@each_child (node) -> nodes.push node
|
||||
nodes
|
||||
|
||||
each_child: (func) ->
|
||||
for attr in @children_attributes when this[attr]
|
||||
for child in flatten [this[attr]]
|
||||
return if func(child) is false
|
||||
|
||||
traverse_children: (cross_scope, func) ->
|
||||
return unless @children_attributes
|
||||
@each_child (child) ->
|
||||
func.apply(this, arguments)
|
||||
child.traverse_children(cross_scope, func) if child instanceof BaseNode
|
||||
|
||||
# Default implementations of the common node identification methods. Nodes
|
||||
# will override these with custom logic, if needed.
|
||||
unwrap: -> this
|
||||
children: []
|
||||
is_statement: -> false
|
||||
is_pure_statement: -> false
|
||||
top_sensitive: -> false
|
||||
@@ -135,7 +151,7 @@ exports.BaseNode: class BaseNode
|
||||
exports.Expressions: class Expressions extends BaseNode
|
||||
|
||||
constructor: (nodes) ->
|
||||
@children: @expressions: compact flatten nodes or []
|
||||
@expressions: compact flatten nodes or []
|
||||
|
||||
# Tack an expression on to the end of this expression list.
|
||||
push: (node) ->
|
||||
@@ -156,10 +172,6 @@ exports.Expressions: class Expressions extends BaseNode
|
||||
empty: ->
|
||||
@expressions.length is 0
|
||||
|
||||
# Make a copy of this node.
|
||||
copy: ->
|
||||
new Expressions @children.slice()
|
||||
|
||||
# An Expressions node does not return its entire body, rather it
|
||||
# ensures that the final expression is returned.
|
||||
make_return: ->
|
||||
@@ -209,6 +221,7 @@ Expressions.wrap: (nodes) ->
|
||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
|
||||
new Expressions(nodes)
|
||||
|
||||
children Expressions, 'expressions'
|
||||
statement Expressions
|
||||
|
||||
#### LiteralNode
|
||||
@@ -242,7 +255,7 @@ exports.LiteralNode: class LiteralNode extends BaseNode
|
||||
exports.ReturnNode: class ReturnNode extends BaseNode
|
||||
|
||||
constructor: (expression) ->
|
||||
@children: [@expression: expression]
|
||||
@expression: expression
|
||||
|
||||
top_sensitive: ->
|
||||
true
|
||||
@@ -255,6 +268,7 @@ exports.ReturnNode: class ReturnNode extends BaseNode
|
||||
"${@tab}return ${@expression.compile(o)};"
|
||||
|
||||
statement ReturnNode, true
|
||||
children ReturnNode, 'expression'
|
||||
|
||||
#### ValueNode
|
||||
|
||||
@@ -266,12 +280,12 @@ exports.ValueNode: class ValueNode extends BaseNode
|
||||
|
||||
# A **ValueNode** has a base and a list of property accesses.
|
||||
constructor: (base, properties) ->
|
||||
@children: flatten [@base: base, @properties: (properties or [])]
|
||||
@base: base
|
||||
@properties: (properties or [])
|
||||
|
||||
# Add a property access to the list.
|
||||
push: (prop) ->
|
||||
@properties.push(prop)
|
||||
@children.push(prop)
|
||||
this
|
||||
|
||||
has_properties: ->
|
||||
@@ -300,35 +314,43 @@ exports.ValueNode: class ValueNode extends BaseNode
|
||||
is_statement: ->
|
||||
@base.is_statement and @base.is_statement() and not @has_properties()
|
||||
|
||||
# Works out if the value is the start of a chain.
|
||||
is_start: (o) ->
|
||||
return true if this is o.chain_root and @properties[0] instanceof AccessorNode
|
||||
node: o.chain_root.base or o.chain_root.variable
|
||||
while node instanceof CallNode then node: node.variable
|
||||
node is this
|
||||
|
||||
# We compile a value to JavaScript by compiling and joining each property.
|
||||
# Things get much more insteresting if the chain of properties has *soak*
|
||||
# operators `?.` interspersed. Then we have to take care not to accidentally
|
||||
# evaluate a anything twice when building the soak chain.
|
||||
compile_node: (o) ->
|
||||
soaked: false
|
||||
only: del(o, 'only_first')
|
||||
op: del(o, 'operation')
|
||||
props: if only then @properties[0...@properties.length - 1] else @properties
|
||||
baseline: @base.compile o
|
||||
baseline: "($baseline)" if @base instanceof ObjectNode and @has_properties()
|
||||
complete: @last: baseline
|
||||
only: del(o, 'only_first')
|
||||
op: del(o, 'operation')
|
||||
props: if only then @properties[0...@properties.length - 1] else @properties
|
||||
o.chain_root: or this
|
||||
baseline: @base.compile o
|
||||
baseline: "($baseline)" if @base instanceof ObjectNode and @has_properties()
|
||||
complete: @last: baseline
|
||||
|
||||
for prop in props
|
||||
for prop, i in props
|
||||
@source: baseline
|
||||
if prop.soak_node
|
||||
soaked: true
|
||||
if @base instanceof CallNode and prop is props[0]
|
||||
if @base instanceof CallNode and i is 0
|
||||
temp: o.scope.free_variable()
|
||||
complete: "($temp = $complete)$@SOAK" + (baseline: temp + prop.compile(o))
|
||||
else
|
||||
complete: complete + @SOAK + (baseline: + prop.compile(o))
|
||||
complete: "(${ baseline: temp } = ($complete))"
|
||||
complete: "typeof $complete === \"undefined\" || $baseline" if i is 0 and @is_start(o)
|
||||
complete: + @SOAK + (baseline: + prop.compile(o))
|
||||
else
|
||||
part: prop.compile(o)
|
||||
baseline: + part
|
||||
complete: + part
|
||||
@last: part
|
||||
|
||||
if op and soaked then "($complete)" else complete
|
||||
if op and @wrapped then "($complete)" else complete
|
||||
|
||||
children ValueNode, 'base', 'properties'
|
||||
|
||||
#### CommentNode
|
||||
|
||||
@@ -336,15 +358,20 @@ exports.ValueNode: class ValueNode extends BaseNode
|
||||
# same position.
|
||||
exports.CommentNode: class CommentNode extends BaseNode
|
||||
|
||||
constructor: (lines) ->
|
||||
constructor: (lines, type) ->
|
||||
@lines: lines
|
||||
@type: type
|
||||
this
|
||||
|
||||
make_return: ->
|
||||
this
|
||||
|
||||
compile_node: (o) ->
|
||||
"$@tab//" + @lines.join("\n$@tab//")
|
||||
if @type is 'herecomment'
|
||||
sep: '\n' + @tab
|
||||
"$@tab/*$sep${ @lines.join(sep) }\n$@tab*/"
|
||||
else
|
||||
"$@tab//" + @lines.join("\n$@tab//")
|
||||
|
||||
statement CommentNode
|
||||
|
||||
@@ -358,7 +385,7 @@ exports.CallNode: class CallNode extends BaseNode
|
||||
@is_new: false
|
||||
@is_super: variable is 'super'
|
||||
@variable: if @is_super then null else variable
|
||||
@children: compact flatten [@variable, @args: (args or [])]
|
||||
@args: (args or [])
|
||||
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
|
||||
|
||||
# Tag this invocation as creating a new instance.
|
||||
@@ -369,35 +396,44 @@ exports.CallNode: class CallNode extends BaseNode
|
||||
prefix: ->
|
||||
if @is_new then 'new ' else ''
|
||||
|
||||
# Grab the reference to the superclass' implementation of the current method.
|
||||
super_reference: (o) ->
|
||||
methname: o.scope.method.name
|
||||
meth: if o.scope.method.proto
|
||||
"${o.scope.method.proto}.__superClass__.$methname"
|
||||
else if methname
|
||||
"${methname}.__superClass__.constructor"
|
||||
else throw new Error "cannot call super on an anonymous function."
|
||||
|
||||
# Compile a vanilla function call.
|
||||
compile_node: (o) ->
|
||||
for arg in @args
|
||||
return @compile_splat(o) if arg instanceof SplatNode
|
||||
args: (arg.compile(o) for arg in @args).join(', ')
|
||||
return @compile_super(args, o) if @is_super
|
||||
"${@prefix()}${@variable.compile(o)}($args)"
|
||||
o.chain_root: this unless o.chain_root
|
||||
for arg in @args when arg instanceof SplatNode
|
||||
compilation: @compile_splat(o)
|
||||
unless compilation
|
||||
args: (arg.compile(o) for arg in @args).join(', ')
|
||||
compilation: if @is_super then @compile_super(args, o)
|
||||
else "${@prefix()}${@variable.compile(o)}($args)"
|
||||
if o.operation and @wrapped then "($compilation)" else compilation
|
||||
|
||||
# `super()` is converted into a call against the superclass's implementation
|
||||
# of the current function.
|
||||
compile_super: (args, o) ->
|
||||
methname: o.scope.method.name
|
||||
meth: if o.scope.method.proto
|
||||
"${o.scope.method.proto}.__superClass__.$methname"
|
||||
else
|
||||
"${methname}.__superClass__.constructor"
|
||||
"${meth}.call(this${ if args.length then ', ' else '' }$args)"
|
||||
"${@super_reference(o)}.call(this${ if args.length then ', ' else '' }$args)"
|
||||
|
||||
# If you call a function with a splat, it's converted into a JavaScript
|
||||
# `.apply()` call to allow an array of arguments to be passed.
|
||||
compile_splat: (o) ->
|
||||
meth: @variable.compile o
|
||||
obj: @variable.source or 'this'
|
||||
meth: if @variable then @variable.compile(o) else @super_reference(o)
|
||||
obj: @variable and @variable.source or 'this'
|
||||
if obj.match(/\(/)
|
||||
temp: o.scope.free_variable()
|
||||
obj: temp
|
||||
meth: "($temp = ${ @variable.source })${ @variable.last }"
|
||||
"${@prefix()}${meth}.apply($obj, ${ @compile_splat_arguments(o) })"
|
||||
|
||||
children CallNode, 'variable', 'args'
|
||||
|
||||
#### CurryNode
|
||||
|
||||
# Binds a context object and a list of arguments to a function,
|
||||
@@ -406,7 +442,9 @@ exports.CallNode: class CallNode extends BaseNode
|
||||
exports.CurryNode: class CurryNode extends CallNode
|
||||
|
||||
constructor: (meth, args) ->
|
||||
@children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])]
|
||||
@meth: meth
|
||||
@context: args[0]
|
||||
@args: (args.slice(1) or [])
|
||||
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
|
||||
|
||||
arguments: (o) ->
|
||||
@@ -419,6 +457,7 @@ exports.CurryNode: class CurryNode extends CallNode
|
||||
ref: new ValueNode literal utility 'bind'
|
||||
(new CallNode(ref, [@meth, @context, literal(@arguments(o))])).compile o
|
||||
|
||||
children CurryNode, 'meth', 'context', 'args'
|
||||
|
||||
#### ExtendsNode
|
||||
|
||||
@@ -428,13 +467,16 @@ exports.CurryNode: class CurryNode extends CallNode
|
||||
exports.ExtendsNode: class ExtendsNode extends BaseNode
|
||||
|
||||
constructor: (child, parent) ->
|
||||
@children: [@child: child, @parent: parent]
|
||||
@child: child
|
||||
@parent: parent
|
||||
|
||||
# Hooks one constructor into another's prototype chain.
|
||||
compile_node: (o) ->
|
||||
ref: new ValueNode literal utility 'extends'
|
||||
(new CallNode ref, [@child, @parent]).compile o
|
||||
|
||||
children ExtendsNode, 'child', 'parent'
|
||||
|
||||
#### AccessorNode
|
||||
|
||||
# A `.` accessor into a property of a value, or the `::` shorthand for
|
||||
@@ -442,28 +484,34 @@ exports.ExtendsNode: class ExtendsNode extends BaseNode
|
||||
exports.AccessorNode: class AccessorNode extends BaseNode
|
||||
|
||||
constructor: (name, tag) ->
|
||||
@children: [@name: name]
|
||||
@prototype:tag is 'prototype'
|
||||
@name: name
|
||||
@prototype: tag is 'prototype'
|
||||
@soak_node: tag is 'soak'
|
||||
this
|
||||
|
||||
compile_node: (o) ->
|
||||
o.chain_root.wrapped: or @soak_node
|
||||
proto_part: if @prototype then 'prototype.' else ''
|
||||
".$proto_part${@name.compile(o)}"
|
||||
|
||||
children AccessorNode, 'name'
|
||||
|
||||
#### IndexNode
|
||||
|
||||
# A `[ ... ]` indexed accessor into an array or object.
|
||||
exports.IndexNode: class IndexNode extends BaseNode
|
||||
|
||||
constructor: (index, tag) ->
|
||||
@children: [@index: index]
|
||||
@index: index
|
||||
@soak_node: tag is 'soak'
|
||||
|
||||
compile_node: (o) ->
|
||||
o.chain_root.wrapped: or @soak_node
|
||||
idx: @index.compile o
|
||||
"[$idx]"
|
||||
|
||||
children IndexNode, 'index'
|
||||
|
||||
#### RangeNode
|
||||
|
||||
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||
@@ -472,7 +520,8 @@ exports.IndexNode: class IndexNode extends BaseNode
|
||||
exports.RangeNode: class RangeNode extends BaseNode
|
||||
|
||||
constructor: (from, to, exclusive) ->
|
||||
@children: [@from: from, @to: to]
|
||||
@from: from
|
||||
@to: to
|
||||
@exclusive: !!exclusive
|
||||
|
||||
# Compiles the range's source variables -- where it starts and where it ends.
|
||||
@@ -505,6 +554,9 @@ exports.RangeNode: class RangeNode extends BaseNode
|
||||
arr: Expressions.wrap([new ForNode(body, {source: (new ValueNode(this))}, literal(name))])
|
||||
(new ParentheticalNode(new CallNode(new CodeNode([], arr.make_return())))).compile(o)
|
||||
|
||||
children RangeNode, 'from', 'to'
|
||||
|
||||
|
||||
#### SliceNode
|
||||
|
||||
# An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter
|
||||
@@ -513,7 +565,7 @@ exports.RangeNode: class RangeNode extends BaseNode
|
||||
exports.SliceNode: class SliceNode extends BaseNode
|
||||
|
||||
constructor: (range) ->
|
||||
@children: [@range: range]
|
||||
@range: range
|
||||
this
|
||||
|
||||
compile_node: (o) ->
|
||||
@@ -522,13 +574,15 @@ exports.SliceNode: class SliceNode extends BaseNode
|
||||
plus_part: if @range.exclusive then '' else ' + 1'
|
||||
".slice($from, $to$plus_part)"
|
||||
|
||||
children SliceNode, 'range'
|
||||
|
||||
#### ObjectNode
|
||||
|
||||
# An object literal, nothing fancy.
|
||||
exports.ObjectNode: class ObjectNode extends BaseNode
|
||||
|
||||
constructor: (props) ->
|
||||
@children: @objects: @properties: props or []
|
||||
@objects: @properties: props or []
|
||||
|
||||
# All the mucking about with commas is to make sure that CommentNodes and
|
||||
# AssignNodes get interleaved correctly, with no trailing commas or
|
||||
@@ -542,18 +596,21 @@ exports.ObjectNode: class ObjectNode extends BaseNode
|
||||
join: "\n" if (prop is last_noncom) or (prop instanceof CommentNode)
|
||||
join: '' if i is @properties.length - 1
|
||||
indent: if prop instanceof CommentNode then '' else @idt 1
|
||||
prop: new AssignNode prop, prop, 'object' unless prop instanceof AssignNode or prop instanceof CommentNode
|
||||
indent + prop.compile(o) + join
|
||||
props: props.join('')
|
||||
inner: if props then '\n' + props + '\n' + @idt() else ''
|
||||
"{$inner}"
|
||||
|
||||
children ObjectNode, 'properties'
|
||||
|
||||
#### ArrayNode
|
||||
|
||||
# An array literal.
|
||||
exports.ArrayNode: class ArrayNode extends BaseNode
|
||||
|
||||
constructor: (objects) ->
|
||||
@children: @objects: objects or []
|
||||
@objects: objects or []
|
||||
@compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects
|
||||
|
||||
compile_node: (o) ->
|
||||
@@ -570,8 +627,12 @@ exports.ArrayNode: class ArrayNode extends BaseNode
|
||||
else
|
||||
objects.push "$code, "
|
||||
objects: objects.join('')
|
||||
ending: if objects.indexOf('\n') >= 0 then "\n$@tab]" else ']'
|
||||
"[$objects$ending"
|
||||
if index_of(objects, '\n') >= 0
|
||||
"[\n${@idt(1)}$objects\n$@tab]"
|
||||
else
|
||||
"[$objects]"
|
||||
|
||||
children ArrayNode, 'objects'
|
||||
|
||||
#### ClassNode
|
||||
|
||||
@@ -581,7 +642,9 @@ exports.ClassNode: class ClassNode extends BaseNode
|
||||
# Initialize a **ClassNode** with its name, an optional superclass, and a
|
||||
# list of prototype property assignments.
|
||||
constructor: (variable, parent, props) ->
|
||||
@children: compact flatten [@variable: variable, @parent: parent, @properties: props or []]
|
||||
@variable: variable
|
||||
@parent: parent
|
||||
@properties: props or []
|
||||
@returns: false
|
||||
|
||||
make_return: ->
|
||||
@@ -609,7 +672,7 @@ exports.ClassNode: class ClassNode extends BaseNode
|
||||
prop: new AssignNode(val, func)
|
||||
props.push prop
|
||||
|
||||
if not constructor
|
||||
unless constructor
|
||||
if @parent
|
||||
applied: new ValueNode(@parent, [new AccessorNode(literal('apply'))])
|
||||
constructor: new AssignNode(@variable, new CodeNode([], new Expressions([
|
||||
@@ -625,6 +688,7 @@ exports.ClassNode: class ClassNode extends BaseNode
|
||||
"$construct$extension$props$returns"
|
||||
|
||||
statement ClassNode
|
||||
children ClassNode, 'variable', 'parent', 'properties'
|
||||
|
||||
#### AssignNode
|
||||
|
||||
@@ -637,7 +701,8 @@ exports.AssignNode: class AssignNode extends BaseNode
|
||||
LEADING_DOT: /^\.(prototype\.)?/
|
||||
|
||||
constructor: (variable, value, context) ->
|
||||
@children: [@variable: variable, @value: value]
|
||||
@variable: variable
|
||||
@value: value
|
||||
@context: context
|
||||
|
||||
top_sensitive: ->
|
||||
@@ -687,12 +752,22 @@ exports.AssignNode: class AssignNode extends BaseNode
|
||||
o.as_statement: true
|
||||
splat: false
|
||||
for obj, i in @variable.base.objects
|
||||
# A regular array pattern-match.
|
||||
idx: i
|
||||
[obj, idx]: [obj.value, obj.variable.base] if @variable.is_object()
|
||||
access_class: if @variable.is_array() then IndexNode else AccessorNode
|
||||
if @variable.is_object()
|
||||
if obj instanceof AssignNode
|
||||
# A regular object pattern-match.
|
||||
[obj, idx]: [obj.value, obj.variable.base]
|
||||
else
|
||||
# A shorthand `{a, b, c}: val` pattern-match.
|
||||
idx: obj
|
||||
if not (obj instanceof ValueNode or obj instanceof SplatNode)
|
||||
throw new Error 'pattern matching must use only identifiers on the left-hand side.'
|
||||
is_string: idx.value and idx.value.match IS_STRING
|
||||
access_class: if is_string or @variable.is_array() then IndexNode else AccessorNode
|
||||
if obj instanceof SplatNode and not splat
|
||||
val: literal(obj.compile_value(o, val_var,
|
||||
(oindex: @variable.base.objects.indexOf(obj)),
|
||||
(oindex: index_of(@variable.base.objects, obj)),
|
||||
(olength: @variable.base.objects.length) - oindex - 1))
|
||||
splat: true
|
||||
else
|
||||
@@ -714,6 +789,8 @@ exports.AssignNode: class AssignNode extends BaseNode
|
||||
val: @value.compile(o)
|
||||
"${name}.splice.apply($name, [$from, $to].concat($val))"
|
||||
|
||||
children AssignNode, 'variable', 'value'
|
||||
|
||||
#### CodeNode
|
||||
|
||||
# A function definition. This is the only node that creates a new Scope.
|
||||
@@ -746,8 +823,9 @@ exports.CodeNode: class CodeNode extends BaseNode
|
||||
if param instanceof SplatNode and not splat?
|
||||
splat: param
|
||||
splat.index: i
|
||||
@body.unshift(splat)
|
||||
splat.trailings: []
|
||||
splat.arglength: @params.length
|
||||
@body.unshift(splat)
|
||||
else if splat?
|
||||
splat.trailings.push(param)
|
||||
else
|
||||
@@ -757,8 +835,7 @@ exports.CodeNode: class CodeNode extends BaseNode
|
||||
@body.make_return()
|
||||
(o.scope.parameter(param)) for param in params
|
||||
code: if @body.expressions.length then "\n${ @body.compile_with_declarations(o) }\n" else ''
|
||||
name_part: if @name then ' ' + @name else ''
|
||||
func: "function${ if @bound then '' else name_part }(${ params.join(', ') }) {$code${@idt(if @bound then 1 else 0)}}"
|
||||
func: "function(${ params.join(', ') }) {$code${@idt(if @bound then 1 else 0)}}"
|
||||
func: "($func)" if top and not @bound
|
||||
return func unless @bound
|
||||
utility 'slice'
|
||||
@@ -768,21 +845,17 @@ exports.CodeNode: class CodeNode extends BaseNode
|
||||
top_sensitive: ->
|
||||
true
|
||||
|
||||
# When traversing (for printing or inspecting), return the real children of
|
||||
# the function -- the parameters and body of expressions.
|
||||
real_children: ->
|
||||
flatten [@params, @body.expressions]
|
||||
|
||||
# Custom `traverse` implementation that uses the `real_children`.
|
||||
traverse: (block) ->
|
||||
block this
|
||||
child.traverse block for child in @real_children()
|
||||
# Short-circuit traverse_children method to prevent it from crossing scope boundaries
|
||||
# unless cross_scope is true
|
||||
traverse_children: (cross_scope, func) -> super(cross_scope, func) if cross_scope
|
||||
|
||||
toString: (idt) ->
|
||||
idt: or ''
|
||||
children: (child.toString(idt + TAB) for child in @real_children()).join('')
|
||||
children: (child.toString(idt + TAB) for child in @children()).join('')
|
||||
"\n$idt$children"
|
||||
|
||||
children CodeNode, 'params', 'body'
|
||||
|
||||
#### SplatNode
|
||||
|
||||
# A splat, either as a parameter to a function, an argument to a call,
|
||||
@@ -791,7 +864,7 @@ exports.SplatNode: class SplatNode extends BaseNode
|
||||
|
||||
constructor: (name) ->
|
||||
name: literal(name) unless name.compile
|
||||
@children: [@name: name]
|
||||
@name: name
|
||||
|
||||
compile_node: (o) ->
|
||||
if @index? then @compile_param(o) else @name.compile(o)
|
||||
@@ -801,11 +874,14 @@ exports.SplatNode: class SplatNode extends BaseNode
|
||||
compile_param: (o) ->
|
||||
name: @name.compile(o)
|
||||
o.scope.find name
|
||||
i: 0
|
||||
for trailing in @trailings
|
||||
o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]")
|
||||
i: + 1
|
||||
"$name = ${utility('slice')}.call(arguments, $@index, arguments.length - ${@trailings.length})"
|
||||
len: o.scope.free_variable()
|
||||
o.scope.assign len, "arguments.length"
|
||||
variadic: o.scope.free_variable()
|
||||
o.scope.assign variadic, "$len >= $@arglength"
|
||||
for trailing, idx in @trailings
|
||||
pos: @trailings.length - idx
|
||||
o.scope.assign(trailing.compile(o), "arguments[$variadic ? $len - $pos : ${@index + idx}]")
|
||||
"$name = ${utility('slice')}.call(arguments, $@index, $len - ${@trailings.length})"
|
||||
|
||||
# A compiling a splat as a destructuring assignment means slicing arguments
|
||||
# from the right-hand-side's corresponding array.
|
||||
@@ -834,6 +910,8 @@ exports.SplatNode: class SplatNode extends BaseNode
|
||||
i: + 1
|
||||
args.join('')
|
||||
|
||||
children SplatNode, 'name'
|
||||
|
||||
#### WhileNode
|
||||
|
||||
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
||||
@@ -842,11 +920,14 @@ exports.SplatNode: class SplatNode extends BaseNode
|
||||
exports.WhileNode: class WhileNode extends BaseNode
|
||||
|
||||
constructor: (condition, opts) ->
|
||||
@children:[@condition: condition]
|
||||
@filter: opts and opts.filter
|
||||
if opts and opts.invert
|
||||
condition: new ParentheticalNode condition if condition instanceof OpNode
|
||||
condition: new OpNode('!', condition)
|
||||
@condition: condition
|
||||
@guard: opts and opts.guard
|
||||
|
||||
add_body: (body) ->
|
||||
@children.push @body: body
|
||||
@body: body
|
||||
this
|
||||
|
||||
make_return: ->
|
||||
@@ -865,20 +946,20 @@ exports.WhileNode: class WhileNode extends BaseNode
|
||||
o.top: true
|
||||
cond: @condition.compile(o)
|
||||
set: ''
|
||||
if not top
|
||||
unless top
|
||||
rvar: o.scope.free_variable()
|
||||
set: "$@tab$rvar = [];\n"
|
||||
@body: PushNode.wrap(rvar, @body) if @body
|
||||
pre: "$set${@tab}while ($cond)"
|
||||
return "$pre null;$post" if not @body
|
||||
@body: Expressions.wrap([new IfNode(@filter, @body)]) if @filter
|
||||
@body: Expressions.wrap([new IfNode(@guard, @body)]) if @guard
|
||||
if @returns
|
||||
post: new ReturnNode(literal(rvar)).compile(merge(o, {indent: @idt()}))
|
||||
post: '\n' + new ReturnNode(literal(rvar)).compile(merge(o, {indent: @idt()}))
|
||||
else
|
||||
post: ''
|
||||
"$pre {\n${ @body.compile(o) }\n$@tab}\n$post"
|
||||
"$pre {\n${ @body.compile(o) }\n$@tab}$post"
|
||||
|
||||
statement WhileNode
|
||||
children WhileNode, 'condition', 'guard', 'body'
|
||||
|
||||
#### OpNode
|
||||
|
||||
@@ -904,7 +985,8 @@ exports.OpNode: class OpNode extends BaseNode
|
||||
|
||||
constructor: (operator, first, second, flip) ->
|
||||
@constructor.name: + ' ' + operator
|
||||
@children: compact [@first: first, @second: second]
|
||||
@first: first
|
||||
@second: second
|
||||
@operator: @CONVERSIONS[operator] or operator
|
||||
@flip: !!flip
|
||||
|
||||
@@ -912,12 +994,12 @@ exports.OpNode: class OpNode extends BaseNode
|
||||
not @second
|
||||
|
||||
is_chainable: ->
|
||||
@CHAINABLE.indexOf(@operator) >= 0
|
||||
index_of(@CHAINABLE, @operator) >= 0
|
||||
|
||||
compile_node: (o) ->
|
||||
o.operation: true
|
||||
return @compile_chain(o) if @is_chainable() and @first.unwrap() instanceof OpNode and @first.unwrap().is_chainable()
|
||||
return @compile_assignment(o) if @ASSIGNMENT.indexOf(@operator) >= 0
|
||||
return @compile_assignment(o) if index_of(@ASSIGNMENT, @operator) >= 0
|
||||
return @compile_unary(o) if @is_unary()
|
||||
return @compile_existence(o) if @operator is '?'
|
||||
[@first.compile(o), @operator, @second.compile(o)].join ' '
|
||||
@@ -951,18 +1033,22 @@ exports.OpNode: class OpNode extends BaseNode
|
||||
|
||||
# Compile a unary **OpNode**.
|
||||
compile_unary: (o) ->
|
||||
space: if @PREFIX_OPERATORS.indexOf(@operator) >= 0 then ' ' else ''
|
||||
space: if index_of(@PREFIX_OPERATORS, @operator) >= 0 then ' ' else ''
|
||||
parts: [@operator, space, @first.compile(o)]
|
||||
parts: parts.reverse() if @flip
|
||||
parts.join('')
|
||||
|
||||
children OpNode, 'first', 'second'
|
||||
|
||||
#### TryNode
|
||||
|
||||
# A classic *try/catch/finally* block.
|
||||
exports.TryNode: class TryNode extends BaseNode
|
||||
|
||||
constructor: (attempt, error, recovery, ensure) ->
|
||||
@children: compact [@attempt: attempt, @recovery: recovery, @ensure: ensure]
|
||||
@attempt: attempt
|
||||
@recovery: recovery
|
||||
@ensure: ensure
|
||||
@error: error
|
||||
this
|
||||
|
||||
@@ -983,6 +1069,7 @@ exports.TryNode: class TryNode extends BaseNode
|
||||
"${@tab}try {\n$attempt_part\n$@tab}$catch_part$finally_part"
|
||||
|
||||
statement TryNode
|
||||
children TryNode, 'attempt', 'recovery', 'ensure'
|
||||
|
||||
#### ThrowNode
|
||||
|
||||
@@ -990,7 +1077,7 @@ statement TryNode
|
||||
exports.ThrowNode: class ThrowNode extends BaseNode
|
||||
|
||||
constructor: (expression) ->
|
||||
@children: [@expression: expression]
|
||||
@expression: expression
|
||||
|
||||
# A **ThrowNode** is already a return, of sorts...
|
||||
make_return: ->
|
||||
@@ -1000,6 +1087,7 @@ exports.ThrowNode: class ThrowNode extends BaseNode
|
||||
"${@tab}throw ${@expression.compile(o)};"
|
||||
|
||||
statement ThrowNode
|
||||
children ThrowNode, 'expression'
|
||||
|
||||
#### ExistenceNode
|
||||
|
||||
@@ -1009,7 +1097,7 @@ statement ThrowNode
|
||||
exports.ExistenceNode: class ExistenceNode extends BaseNode
|
||||
|
||||
constructor: (expression) ->
|
||||
@children: [@expression: expression]
|
||||
@expression: expression
|
||||
|
||||
compile_node: (o) ->
|
||||
ExistenceNode.compile_test(o, @expression)
|
||||
@@ -1024,6 +1112,8 @@ exports.ExistenceNode: class ExistenceNode extends BaseNode
|
||||
[first, second]: [first.compile(o), second.compile(o)]
|
||||
"(typeof $first !== \"undefined\" && $second !== null)"
|
||||
|
||||
children ExistenceNode, 'expression'
|
||||
|
||||
#### ParentheticalNode
|
||||
|
||||
# An extra set of parentheses, specified explicitly in the source. At one time
|
||||
@@ -1034,7 +1124,7 @@ exports.ExistenceNode: class ExistenceNode extends BaseNode
|
||||
exports.ParentheticalNode: class ParentheticalNode extends BaseNode
|
||||
|
||||
constructor: (expression) ->
|
||||
@children: [@expression: expression]
|
||||
@expression: expression
|
||||
|
||||
is_statement: ->
|
||||
@expression.is_statement()
|
||||
@@ -1049,6 +1139,8 @@ exports.ParentheticalNode: class ParentheticalNode extends BaseNode
|
||||
code: code.substr(o, l-1) if code.substr(l-1, 1) is ';'
|
||||
if @expression instanceof AssignNode then code else "($code)"
|
||||
|
||||
children ParentheticalNode, 'expression'
|
||||
|
||||
#### ForNode
|
||||
|
||||
# CoffeeScript's replacement for the *for* loop is our array and object
|
||||
@@ -1065,11 +1157,12 @@ exports.ForNode: class ForNode extends BaseNode
|
||||
@name: name
|
||||
@index: index or null
|
||||
@source: source.source
|
||||
@filter: source.filter
|
||||
@guard: source.guard
|
||||
@step: source.step
|
||||
@object: !!source.object
|
||||
[@name, @index]: [@index, @name] if @object
|
||||
@children: compact [@body, @source, @filter]
|
||||
@pattern: @name instanceof ValueNode
|
||||
throw new Error('index cannot be a pattern matching expression') if @index instanceof ValueNode
|
||||
@returns: false
|
||||
|
||||
top_sensitive: ->
|
||||
@@ -1080,8 +1173,9 @@ exports.ForNode: class ForNode extends BaseNode
|
||||
this
|
||||
|
||||
compile_return_value: (val, o) ->
|
||||
return new ReturnNode(literal(val)).compile(o) if @returns
|
||||
val or ''
|
||||
return '\n' + new ReturnNode(literal(val)).compile(o) if @returns
|
||||
return '\n' + val if val
|
||||
''
|
||||
|
||||
# Welcome to the hairiest method in all of CoffeeScript. Handles the inner
|
||||
# loop, filtering, stepping, and result saving for array, object, and range
|
||||
@@ -1094,7 +1188,7 @@ exports.ForNode: class ForNode extends BaseNode
|
||||
scope: o.scope
|
||||
name: @name and @name.compile o
|
||||
index: @index and @index.compile o
|
||||
scope.find name if name
|
||||
scope.find name if name and not @pattern
|
||||
scope.find index if index
|
||||
body_dent: @idt 1
|
||||
rvar: scope.free_variable() unless top_level
|
||||
@@ -1102,16 +1196,16 @@ exports.ForNode: class ForNode extends BaseNode
|
||||
var_part: ''
|
||||
body: Expressions.wrap([@body])
|
||||
if range
|
||||
index_var: scope.free_variable()
|
||||
source_part: source.compile_variables o
|
||||
for_part: source.compile merge o, {index: ivar, step: @step}
|
||||
for_part: "$index_var = 0, $for_part, $index_var++"
|
||||
else
|
||||
svar: scope.free_variable()
|
||||
index_var: null
|
||||
source_part: "$svar = ${ @source.compile(o) };\n$@tab"
|
||||
var_part: "$body_dent$name = $svar[$ivar];\n" if name
|
||||
if not @object
|
||||
if @pattern
|
||||
var_part: new AssignNode(@name, literal("$svar[$ivar]")).compile(merge o, {indent: @idt(1), top: true}) + "\n"
|
||||
else
|
||||
var_part: "$body_dent$name = $svar[$ivar];\n" if name
|
||||
unless @object
|
||||
lvar: scope.free_variable()
|
||||
step_part: if @step then "$ivar += ${ @step.compile(o) }" else "$ivar++"
|
||||
for_part: "$ivar = 0, $lvar = ${svar}.length; $ivar < $lvar; $step_part"
|
||||
@@ -1120,16 +1214,17 @@ exports.ForNode: class ForNode extends BaseNode
|
||||
|
||||
body: ClosureNode.wrap(body, true) if top_level and body.contains (n) -> n instanceof CodeNode
|
||||
body: PushNode.wrap(rvar, body) unless top_level
|
||||
if @filter
|
||||
body: Expressions.wrap([new IfNode(@filter, body)])
|
||||
if @guard
|
||||
body: Expressions.wrap([new IfNode(@guard, body)])
|
||||
if @object
|
||||
for_part: "$ivar in $svar) { if (${utility('hasProp')}.call($svar, $ivar)"
|
||||
body: body.compile(merge(o, {indent: body_dent, top: true}))
|
||||
vars: if range then name else "$name, $ivar"
|
||||
close: if @object then '}}\n' else '}\n'
|
||||
close: if @object then '}}' else '}'
|
||||
"$set_result${source_part}for ($for_part) {\n$var_part$body\n$@tab$close$return_result"
|
||||
|
||||
statement ForNode
|
||||
children ForNode, 'body', 'source', 'guard'
|
||||
|
||||
#### IfNode
|
||||
|
||||
@@ -1140,21 +1235,16 @@ statement ForNode
|
||||
# because ternaries are already proper expressions, and don't need conversion.
|
||||
exports.IfNode: class IfNode extends BaseNode
|
||||
|
||||
constructor: (condition, body, else_body, tags) ->
|
||||
constructor: (condition, body, tags) ->
|
||||
@condition: condition
|
||||
@body: body and body.unwrap()
|
||||
@else_body: else_body and else_body.unwrap()
|
||||
@children: compact flatten [@condition, @body, @else_body]
|
||||
@body: body
|
||||
@else_body: null
|
||||
@tags: tags or {}
|
||||
@multiple: true if @condition instanceof Array
|
||||
@condition: new OpNode('!', new ParentheticalNode(@condition)) if @tags.invert
|
||||
@is_chain: false
|
||||
|
||||
# Add a new *else* clause to this **IfNode**, or push it down to the bottom
|
||||
# of the chain recursively.
|
||||
push: (else_body) ->
|
||||
eb: else_body.unwrap()
|
||||
if @else_body then @else_body.push(eb) else @else_body: eb
|
||||
this
|
||||
body_node: -> @body?.unwrap()
|
||||
else_body_node: -> @else_body?.unwrap()
|
||||
|
||||
force_statement: ->
|
||||
@tags.statement: true
|
||||
@@ -1162,43 +1252,39 @@ exports.IfNode: class IfNode extends BaseNode
|
||||
|
||||
# Tag a chain of **IfNodes** with their object(s) to switch on for equality
|
||||
# tests. `rewrite_switch` will perform the actual change at compile time.
|
||||
rewrite_condition: (expression) ->
|
||||
@switcher: expression
|
||||
switches_over: (expression) ->
|
||||
@switch_subject: expression
|
||||
this
|
||||
|
||||
# Rewrite a chain of **IfNodes** with their switch condition for equality.
|
||||
# Ensure that the switch expression isn't evaluated more than once.
|
||||
rewrite_switch: (o) ->
|
||||
assigner: @switcher
|
||||
if not (@switcher.unwrap() instanceof LiteralNode)
|
||||
@assigner: @switch_subject
|
||||
unless (@switch_subject.unwrap() instanceof LiteralNode)
|
||||
variable: literal(o.scope.free_variable())
|
||||
assigner: new AssignNode(variable, @switcher)
|
||||
@switcher: variable
|
||||
@condition: if @multiple
|
||||
for cond, i in @condition
|
||||
new OpNode('==', (if i is 0 then assigner else @switcher), cond)
|
||||
else
|
||||
new OpNode('==', assigner, @condition)
|
||||
@else_body.rewrite_condition(@switcher) if @is_chain()
|
||||
@assigner: new AssignNode(variable, @switch_subject)
|
||||
@switch_subject: variable
|
||||
@condition: for cond, i in flatten [@condition]
|
||||
cond: new ParentheticalNode(cond) if cond instanceof OpNode
|
||||
new OpNode('==', (if i is 0 then @assigner else @switch_subject), cond)
|
||||
@else_body_node().switches_over(@switch_subject) if @is_chain
|
||||
# prevent this rewrite from happening again
|
||||
@switch_subject: undefined
|
||||
this
|
||||
|
||||
# Rewrite a chain of **IfNodes** to add a default case as the final *else*.
|
||||
add_else: (exprs, statement) ->
|
||||
if @is_chain()
|
||||
@else_body.add_else exprs, statement
|
||||
add_else: (else_body, statement) ->
|
||||
if @is_chain
|
||||
@else_body_node().add_else else_body, statement
|
||||
else
|
||||
exprs: exprs.unwrap() unless statement
|
||||
@children.push @else_body: exprs
|
||||
@is_chain: else_body instanceof IfNode
|
||||
@else_body: @ensure_expressions else_body
|
||||
this
|
||||
|
||||
# If the `else_body` is an **IfNode** itself, then we've got an *if-else* chain.
|
||||
is_chain: ->
|
||||
@chain: or @else_body and @else_body instanceof IfNode
|
||||
|
||||
# The **IfNode** only compiles into a statement if either of its bodies needs
|
||||
# to be a statement. Otherwise a ternary is safe.
|
||||
is_statement: ->
|
||||
@statement: or !!(@comment or @tags.statement or @body.is_statement() or (@else_body and @else_body.is_statement()))
|
||||
@statement: or !!(@comment or @tags.statement or @body_node().is_statement() or (@else_body and @else_body_node().is_statement()))
|
||||
|
||||
compile_condition: (o) ->
|
||||
(cond.compile(o) for cond in flatten([@condition])).join(' || ')
|
||||
@@ -1207,14 +1293,18 @@ exports.IfNode: class IfNode extends BaseNode
|
||||
if @is_statement() then @compile_statement(o) else @compile_ternary(o)
|
||||
|
||||
make_return: ->
|
||||
@body: and @body.make_return()
|
||||
@else_body: and @else_body.make_return()
|
||||
@body: and @ensure_expressions(@body.make_return())
|
||||
@else_body: and @ensure_expressions(@else_body.make_return())
|
||||
this
|
||||
|
||||
ensure_expressions: (node) ->
|
||||
node: new Expressions([node]) unless node instanceof Expressions
|
||||
node
|
||||
|
||||
# Compile the **IfNode** as a regular *if-else* statement. Flattened chains
|
||||
# force inner *else* bodies into statement form.
|
||||
compile_statement: (o) ->
|
||||
@rewrite_switch(o) if @switcher
|
||||
@rewrite_switch(o) if @switch_subject
|
||||
child: del o, 'chain_child'
|
||||
cond_o: merge o
|
||||
o.indent: @idt 1
|
||||
@@ -1222,21 +1312,25 @@ exports.IfNode: class IfNode extends BaseNode
|
||||
if_dent: if child then '' else @idt()
|
||||
com_dent: if child then @idt() else ''
|
||||
prefix: if @comment then "${ @comment.compile(cond_o) }\n$com_dent" else ''
|
||||
body: Expressions.wrap([@body]).compile(o)
|
||||
body: @body.compile(o)
|
||||
if_part: "$prefix${if_dent}if (${ @compile_condition(cond_o) }) {\n$body\n$@tab}"
|
||||
return if_part unless @else_body
|
||||
else_part: if @is_chain()
|
||||
' else ' + @else_body.compile(merge(o, {indent: @idt(), chain_child: true}))
|
||||
else_part: if @is_chain
|
||||
' else ' + @else_body_node().compile(merge(o, {indent: @idt(), chain_child: true}))
|
||||
else
|
||||
" else {\n${ Expressions.wrap([@else_body]).compile(o) }\n$@tab}"
|
||||
" else {\n${ @else_body.compile(o) }\n$@tab}"
|
||||
"$if_part$else_part"
|
||||
|
||||
# Compile the IfNode as a ternary operator.
|
||||
compile_ternary: (o) ->
|
||||
if_part: @condition.compile(o) + ' ? ' + @body.compile(o)
|
||||
else_part: if @else_body then @else_body.compile(o) else 'null'
|
||||
if_part: @condition.compile(o) + ' ? ' + @body_node().compile(o)
|
||||
else_part: if @else_body then @else_body_node().compile(o) else 'null'
|
||||
"$if_part : $else_part"
|
||||
|
||||
|
||||
children IfNode, 'condition', 'body', 'else_body', 'assigner'
|
||||
|
||||
|
||||
# Faux-Nodes
|
||||
# ----------
|
||||
|
||||
@@ -1323,11 +1417,14 @@ TAB: ' '
|
||||
|
||||
# Trim out all trailing whitespace, so that the generated code plays nice
|
||||
# with Git.
|
||||
TRAILING_WHITESPACE: /\s+$/gm
|
||||
TRAILING_WHITESPACE: /[ \t]+$/gm
|
||||
|
||||
# Keep this identifier regex in sync with the Lexer.
|
||||
IDENTIFIER: /^[a-zA-Z\$_](\w|\$)*$/
|
||||
|
||||
# Is a literal value a string?
|
||||
IS_STRING: /^['"]/
|
||||
|
||||
# Utility Functions
|
||||
# -----------------
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
# Set up exported variables for both Node.js and the browser.
|
||||
if process?
|
||||
helpers: require('./helpers').helpers
|
||||
{helpers}: require('./helpers')
|
||||
else
|
||||
this.exports: this
|
||||
helpers: this.helpers
|
||||
|
||||
# Import the helpers we need.
|
||||
include: helpers.include
|
||||
{include}: helpers
|
||||
|
||||
# The **Rewriter** class is used by the [Lexer](lexer.html), directly against
|
||||
# its internal array of tokens.
|
||||
@@ -54,10 +54,13 @@ exports.Rewriter: class Rewriter
|
||||
adjust_comments: ->
|
||||
@scan_tokens (prev, token, post, i) =>
|
||||
return 1 unless token[0] is 'COMMENT'
|
||||
after: @tokens[i + 2]
|
||||
[before, after]: [@tokens[i - 2], @tokens[i + 2]]
|
||||
if after and after[0] is 'INDENT'
|
||||
@tokens.splice i + 2, 1
|
||||
@tokens.splice i, 0, after
|
||||
if before and before[0] is 'OUTDENT' and post and prev[0] is post[0] is 'TERMINATOR'
|
||||
@tokens.splice i - 2, 1
|
||||
else
|
||||
@tokens.splice i, 0, after
|
||||
return 1
|
||||
else if prev and prev[0] isnt 'TERMINATOR' and prev[0] isnt 'INDENT' and prev[0] isnt 'OUTDENT'
|
||||
@tokens.splice i, 0, ['TERMINATOR', "\n", prev[2]]
|
||||
@@ -109,38 +112,40 @@ exports.Rewriter: class Rewriter
|
||||
# deal with them.
|
||||
add_implicit_parentheses: ->
|
||||
stack: [0]
|
||||
calls: 0
|
||||
parens: 0
|
||||
start_parens: 0
|
||||
close_calls: (i) =>
|
||||
for tmp in [0...stack[stack.length - 1]]
|
||||
@tokens.splice(i, 0, ['CALL_END', ')', @tokens[i][2]])
|
||||
size: stack[stack.length - 1] + 1
|
||||
stack[stack.length - 1]: 0
|
||||
size
|
||||
@scan_tokens (prev, token, post, i) =>
|
||||
tag: token[0]
|
||||
switch tag
|
||||
when 'CALL_START' then calls: + 1
|
||||
when 'CALL_END' then calls: - 1
|
||||
when '(' then parens: + 1
|
||||
when ')' then parens: - 1
|
||||
when 'INDENT' then stack.push 0
|
||||
when 'OUTDENT'
|
||||
last: stack.pop()
|
||||
stack[stack.length - 1]: + last
|
||||
stack[stack.length - 2]: + stack.pop() if tag is 'OUTDENT'
|
||||
open: stack[stack.length - 1] > 0
|
||||
if !post? or (start_parens > parens) or (start_parens is parens and include IMPLICIT_END, tag)
|
||||
return 1 if tag is 'INDENT' and prev and include IMPLICIT_BLOCK, prev[0]
|
||||
return 1 if tag is 'OUTDENT' and token.generated
|
||||
if open or tag is 'INDENT'
|
||||
idx: if tag is 'OUTDENT' then i + 1 else i
|
||||
stack_pointer: if tag is 'INDENT' then 2 else 1
|
||||
for tmp in [0...stack[stack.length - stack_pointer]]
|
||||
@tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
|
||||
size: stack[stack.length - stack_pointer] + 1
|
||||
stack[stack.length - stack_pointer]: 0
|
||||
if prev and prev.spaced and include(IMPLICIT_FUNC, prev[0]) and include(IMPLICIT_CALL, tag)
|
||||
@tokens.splice i, 0, ['CALL_START', '(', token[2]]
|
||||
stack[stack.length - 1]: + 1
|
||||
stack.push 0 if include(EXPRESSION_START, tag)
|
||||
return 2
|
||||
if include(EXPRESSION_START, tag)
|
||||
if tag is 'INDENT' and !token.generated and open and not (prev and include(IMPLICIT_BLOCK, prev[0]))
|
||||
size: close_calls(i)
|
||||
stack.push 0
|
||||
return size
|
||||
return 1 unless prev and include(IMPLICIT_FUNC, prev[0]) and include(IMPLICIT_CALL, tag)
|
||||
calls: 0
|
||||
start_parens: if tag is '(' then parens - 1 else parens
|
||||
@tokens.splice i, 0, ['CALL_START', '(', token[2]]
|
||||
stack[stack.length - 1]: + 1
|
||||
return 2
|
||||
stack.push 0
|
||||
return 1
|
||||
if open and !token.generated and (!post or include(IMPLICIT_END, tag))
|
||||
j: 1; j++ while (nx: @tokens[i + j])? and include(IMPLICIT_END, nx[0])
|
||||
if nx? and nx[0] is ','
|
||||
@tokens.splice(i, 1) if tag is 'TERMINATOR'
|
||||
else
|
||||
size: close_calls(i)
|
||||
stack.pop() if tag isnt 'OUTDENT' and include EXPRESSION_END, tag
|
||||
return size
|
||||
if tag isnt 'OUTDENT' and include EXPRESSION_END, tag
|
||||
stack[stack.length - 2]: + stack.pop()
|
||||
return 1
|
||||
return 1
|
||||
|
||||
# Because our grammar is LALR(1), it can't handle some single-line
|
||||
# expressions that lack ending delimiters. The **Rewriter** adds the implicit
|
||||
@@ -152,7 +157,9 @@ exports.Rewriter: class Rewriter
|
||||
post[0] isnt 'INDENT' and
|
||||
not (token[0] is 'ELSE' and post[0] is 'IF')
|
||||
starter: token[0]
|
||||
@tokens.splice i + 1, 0, ['INDENT', 2, token[2]]
|
||||
indent: ['INDENT', 2, token[2]]
|
||||
indent.generated: true
|
||||
@tokens.splice i + 1, 0, indent
|
||||
idx: i + 1
|
||||
parens: 0
|
||||
while true
|
||||
@@ -209,7 +216,8 @@ exports.Rewriter: class Rewriter
|
||||
# it with the inverse of what we've just popped.
|
||||
# 3. Keep track of "debt" for tokens that we manufacture, to make sure we end
|
||||
# up balanced in the end.
|
||||
#
|
||||
# 4. Be careful not to alter array or parentheses delimiters with overzealous
|
||||
# rewriting.
|
||||
rewrite_closing_parens: ->
|
||||
stack: []
|
||||
debt: {}
|
||||
@@ -228,10 +236,15 @@ exports.Rewriter: class Rewriter
|
||||
else
|
||||
match: stack.pop()
|
||||
mtag: match[0]
|
||||
return 1 if tag is INVERSES[mtag]
|
||||
oppos: INVERSES[mtag]
|
||||
return 1 if tag is oppos
|
||||
debt[mtag]: + 1
|
||||
val: if mtag is 'INDENT' then match[1] else INVERSES[mtag]
|
||||
@tokens.splice i, 0, [INVERSES[mtag], val]
|
||||
val: [oppos, if mtag is 'INDENT' then match[1] else oppos]
|
||||
if @tokens[i + 2]?[0] is mtag
|
||||
@tokens.splice i + 3, 0, val
|
||||
stack.push(match)
|
||||
else
|
||||
@tokens.splice i, 0, val
|
||||
return 1
|
||||
else
|
||||
return 1
|
||||
@@ -261,7 +274,7 @@ EXPRESSION_END: pair[1] for pair in BALANCED_PAIRS
|
||||
EXPRESSION_CLOSE: ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END
|
||||
|
||||
# Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
|
||||
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-']
|
||||
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-', '@']
|
||||
|
||||
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
|
||||
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
|
||||
@@ -274,7 +287,7 @@ IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_
|
||||
IMPLICIT_BLOCK: ['->', '=>', '{', '[', ',']
|
||||
|
||||
# Tokens that always mark the end of an implicit call for single-liners.
|
||||
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT']
|
||||
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'UNTIL', 'TERMINATOR', 'INDENT'].concat EXPRESSION_END
|
||||
|
||||
# Single-line flavors of block expressions that have unclosed endings.
|
||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||
|
||||
@@ -23,7 +23,7 @@ ok x is 100
|
||||
|
||||
# This-assignment.
|
||||
tester: ->
|
||||
@example: -> puts 'example function'
|
||||
@example: -> 'example function'
|
||||
this
|
||||
|
||||
ok tester().example.name is 'example'
|
||||
ok tester().example() is 'example function'
|
||||
@@ -1,3 +1,5 @@
|
||||
helpers: require('../lib/helpers').helpers
|
||||
|
||||
f: (x,y,z) ->
|
||||
x * y * z * ((@num or 4) + 5)
|
||||
|
||||
|
||||
@@ -33,4 +33,15 @@ six:
|
||||
2 +
|
||||
3
|
||||
|
||||
ok six is 6
|
||||
ok six is 6
|
||||
|
||||
|
||||
# Ensure that indented array literals don't trigger whitespace rewriting.
|
||||
func: () ->
|
||||
ok arguments.length is 1
|
||||
|
||||
func(
|
||||
[[[[[],
|
||||
[]],
|
||||
[[]]]],
|
||||
[]])
|
||||
|
||||
@@ -4,6 +4,7 @@ func: ->
|
||||
false
|
||||
false # comment
|
||||
false
|
||||
|
||||
# comment
|
||||
true
|
||||
|
||||
@@ -53,3 +54,8 @@ test:
|
||||
'test'
|
||||
|
||||
ok test is 'test test test'
|
||||
|
||||
###
|
||||
This is a here-comment.
|
||||
Kind of like a heredoc.
|
||||
###
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Ensure that carriage returns don't break compilation on Windows.
|
||||
CoffeeScript: require('./../lib/coffee-script')
|
||||
Lexer: require('./../lib/lexer')
|
||||
|
||||
js: CoffeeScript.compile("one\r\ntwo", {no_wrap: on})
|
||||
|
||||
|
||||
@@ -74,3 +74,7 @@ ok result is '10'
|
||||
result: not value?.property?
|
||||
ok result
|
||||
|
||||
|
||||
# Safely calls values off of non-existent variables.
|
||||
result: nothing?.value
|
||||
ok result is undefined
|
||||
|
||||
@@ -6,7 +6,6 @@ ok x is 1
|
||||
ok typeof(y.x) is 'function'
|
||||
ok y.x instanceof Function
|
||||
ok y.x() is 3
|
||||
ok y.x.name is 'x'
|
||||
|
||||
|
||||
# The empty function should not cause a syntax error.
|
||||
@@ -76,6 +75,11 @@ fn: (arg) -> arg
|
||||
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
|
||||
# Function calls sans-spacing.
|
||||
ok((fn (x) ->
|
||||
3
|
||||
)() is 3)
|
||||
|
||||
|
||||
# Multi-blocks with optional parens.
|
||||
result: fn( ->
|
||||
@@ -138,3 +142,16 @@ result: ((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
|
||||
|
||||
@@ -33,3 +33,12 @@ else
|
||||
27
|
||||
|
||||
ok result is 27
|
||||
|
||||
|
||||
# Testing unless.
|
||||
result: unless true
|
||||
10
|
||||
else
|
||||
11
|
||||
|
||||
ok result is 11
|
||||
|
||||
@@ -38,6 +38,12 @@ trailing_comma: [
|
||||
trailing_comma: {k1: "v1", k2: 4, k3: (-> true),}
|
||||
ok trailing_comma.k3() and (trailing_comma.k2 is 4) and (trailing_comma.k1 is "v1")
|
||||
|
||||
multiline: {a: 15,
|
||||
b: 26}
|
||||
|
||||
ok multiline.b is 26
|
||||
|
||||
|
||||
money$: 'dollars'
|
||||
|
||||
ok money$ is 'dollars'
|
||||
|
||||
@@ -56,7 +56,7 @@ ok c is 30
|
||||
person: {
|
||||
name: "Moe"
|
||||
family: {
|
||||
brother: {
|
||||
'elder-brother': {
|
||||
addresses: [
|
||||
"first"
|
||||
{
|
||||
@@ -68,7 +68,7 @@ person: {
|
||||
}
|
||||
}
|
||||
|
||||
{name: a, family: {brother: {addresses: [one, {city: b}]}}}: person
|
||||
{name: a, family: {'elder-brother': {addresses: [one, {city: b}]}}}: person
|
||||
|
||||
ok a is "Moe"
|
||||
ok b is "Moquasset NY, 10021"
|
||||
@@ -89,8 +89,51 @@ test: {
|
||||
ok addr.join(', ') is "Street 101, Apt 101, City 101"
|
||||
|
||||
|
||||
# Destructuring against an expression.
|
||||
# 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
|
||||
|
||||
deepEqual join1, ["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
|
||||
|
||||
deepEqual join1, join2
|
||||
|
||||
persons: [['Bob', ['George']], ['Alice', ['Bob']], ['Stan', ['Christopher']]]
|
||||
join3: "$parent: $name" for [name, [parent]] in persons
|
||||
|
||||
deepEqual join2, join3
|
||||
|
||||
@@ -12,4 +12,12 @@ g: 1
|
||||
|
||||
ok y / x/g is 2
|
||||
|
||||
ok 'http://google.com'.match(/:\/\/goog/)
|
||||
ok 'http://google.com'.match(/:\/\/goog/)
|
||||
|
||||
obj: {
|
||||
width: -> 10
|
||||
height: -> 20
|
||||
}
|
||||
id: 2
|
||||
|
||||
ok (obj.width()/id - obj.height()/id) is -5
|
||||
|
||||
@@ -75,4 +75,33 @@ ok crowd[0] is contenders[0]
|
||||
ok crowd[10] is "Mighty Mouse"
|
||||
|
||||
ok bests[1] is contenders[0]
|
||||
ok bests[4] is contenders[3]
|
||||
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
|
||||
|
||||
@@ -62,3 +62,12 @@ switch "word"
|
||||
result: true unless false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to handle switches sans-condition.
|
||||
result: switch
|
||||
when null then 1
|
||||
when 'truthful string' then 2
|
||||
else 3
|
||||
|
||||
ok result is 2
|
||||
|
||||
@@ -28,3 +28,11 @@ results: while i -= 1 when i % 2 is 0
|
||||
|
||||
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
|
||||
|
||||
31
vendor/jison/Jakefile
vendored
31
vendor/jison/Jakefile
vendored
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env narwhal
|
||||
|
||||
var FILE = require("file"),
|
||||
OS = require("os"),
|
||||
jake = require("jake");
|
||||
|
||||
jake.task("build", ["build:bnf", "build:lex"]);
|
||||
|
||||
jake.task("build:bnf", function () {
|
||||
OS.system(['./bin/jison', 'src/bnf.jison', 'src/bnf.jisonlex']);
|
||||
OS.system(['mv', 'bnf.js', 'lib/jison/util/bnf-parser.js']);
|
||||
});
|
||||
|
||||
jake.task("build:lex", function () {
|
||||
OS.system(['./bin/jison', 'src/jisonlex.jison', 'src/jisonlex.jisonlex']);
|
||||
OS.system(['mv', 'jisonlex.js', 'lib/jison/util/lex-parser.js']);
|
||||
});
|
||||
|
||||
|
||||
jake.task("test", function () {
|
||||
OS.system(['narwhal', 'tests/all-tests.js']);
|
||||
});
|
||||
jake.task("test:parser", function () {
|
||||
OS.system(['narwhal', 'tests/parser/parser-tests.js']);
|
||||
});
|
||||
jake.task("test:lexer", function () {
|
||||
OS.system(['narwhal', 'tests/lexer/lexer-tests.js']);
|
||||
});
|
||||
jake.task("test:grammar", function () {
|
||||
OS.system(['narwhal', 'tests/grammar/grammar-tests.js']);
|
||||
});
|
||||
347
vendor/jison/README.md
vendored
347
vendor/jison/README.md
vendored
@@ -1,347 +0,0 @@
|
||||
Jison
|
||||
=====
|
||||
* [issues](http://github.com/zaach/jison/issues)
|
||||
* [discuss](mailto:jison@librelist.com)
|
||||
|
||||
An API for creating parsers in JavaScript
|
||||
-----------------------------------------
|
||||
|
||||
Jison generates bottom-up parsers in JavaScript. Its API is similar to Bison's, hence the name. It supports many of Bison's major features, plus some of its own. If you are new to parser generators such as Bison, and Context-free Grammars in general, a [good introduction][1] is found in the Bison manual. If you already know Bison, Jison should be easy to pickup.
|
||||
|
||||
A brief warning before proceeding: **the API is ridiculously unstable** right now. The goal is to mirror Bison where it makes sense, but we're not even there yet. Also, optimization has not been a main focus as of yet.
|
||||
|
||||
Briefly, Jison takes a JSON encoded grammar specification and outputs a JavaScript file capable of parsing the language described by that grammar specification. You can then use the generated script to parse inputs and accept, reject, or perform actions based on the input.
|
||||
|
||||
Installation
|
||||
------------
|
||||
**Prerequisite**: To run Jison from the command line, you'll need to have [Narwhal][2] installed and available from your `PATH`.
|
||||
|
||||
Clone the github repository:
|
||||
|
||||
git clone git://github.com/zaach/jison.git
|
||||
|
||||
Usage from the command line
|
||||
-----------------------
|
||||
|
||||
Now you're ready to generate some parsers:
|
||||
|
||||
cd jison
|
||||
narwhal bin/jison examples/calculator.jison examples/calculator.jisonlex
|
||||
|
||||
This will generate a `calculator.js` file in your current working directory. This file can be used to parse an input file, like so:
|
||||
|
||||
echo "2^32 / 1024" > testcalc
|
||||
narwhal calculator.js testcalc
|
||||
|
||||
This will print out `4194304`.
|
||||
|
||||
Usage from a CommonJS module
|
||||
--------------------------
|
||||
|
||||
You can generate parsers programatically from JavaScript as well. Assuming Jison is in your commonjs environment's load path:
|
||||
|
||||
// mygenerator.js
|
||||
var Parser = require("jison").Parser;
|
||||
|
||||
var grammar = {
|
||||
"lex": {
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["[a-f0-9]+", "return 'HEX';"]
|
||||
]
|
||||
},
|
||||
|
||||
"bnf": {
|
||||
"hex_strings" :[ "hex_strings HEX",
|
||||
"HEX" ]
|
||||
}
|
||||
};
|
||||
|
||||
var parser = new Parser(grammar);
|
||||
|
||||
// generate source, ready to be written to disk
|
||||
var parserSource = parser.generate();
|
||||
|
||||
// you can also use the parser directly from memory
|
||||
|
||||
// returns true
|
||||
parser.parse("adfe34bc e82a");
|
||||
|
||||
// throws lexical error
|
||||
parser.parse("adfe34bc zxg");
|
||||
|
||||
Using the generated parser
|
||||
--------------------------
|
||||
So, you have generated your parser through the command line or JavaScript API and have saved it to disk. Now it can be put to use.
|
||||
|
||||
As demonstrated before, the parser can be used from the command line:
|
||||
|
||||
narwhal calculator.js testcalc
|
||||
|
||||
Though, more ideally, the parser will be a dependency of another module. You can require it from another module like so:
|
||||
|
||||
// mymodule.js
|
||||
var parser = require("./calculator").parser;
|
||||
|
||||
function exec (input) {
|
||||
return parser.parse(input);
|
||||
}
|
||||
|
||||
var twenty = exec("4 * 5");
|
||||
|
||||
Or more succinctly:
|
||||
|
||||
// mymodule.js
|
||||
function exec (input) {
|
||||
return require("./calculator").parse(input);
|
||||
}
|
||||
|
||||
var twenty = exec("4 * 5");
|
||||
|
||||
Using the parser in a web page
|
||||
----------------------------
|
||||
|
||||
The generated parser script may be included in a web page without any need for a CommonJS loading environment. It's as simple as pointing to it via a scipt tag:
|
||||
|
||||
<script src="calc.js"></script>
|
||||
|
||||
When you generate the parser, you can specify the variable name it will be declared as:
|
||||
|
||||
// mygenerator.js
|
||||
var parserSource = generator.generate({moduleName: "calc"});
|
||||
// then write parserSource to a file called, say, calc.js
|
||||
|
||||
Whatever `moduleName` you specified will be the the variable you can access the parser from in your web page:
|
||||
|
||||
<!-- mypage.html -->
|
||||
...
|
||||
<script src="calc.js"></script>
|
||||
<script>
|
||||
calc.parse("42 / 0");
|
||||
</script>
|
||||
...
|
||||
|
||||
The moduleName you specify can also include a namespace, e.g:
|
||||
// mygenerator.js
|
||||
var parserSource = parser.generate({moduleName: "myCalculator.parser"});
|
||||
|
||||
And could be used like so:
|
||||
|
||||
<!-- mypage.html -->
|
||||
...
|
||||
<script>
|
||||
var myCalculator = {};
|
||||
</script>
|
||||
<script src="calc.js"></script>
|
||||
<script>
|
||||
myCalculator.parser.parse("42 / 0");
|
||||
</script>
|
||||
...
|
||||
|
||||
Or something like that -- you get the picture.
|
||||
|
||||
A demo of the calculator script used in a web page is [here](http://zaach.github.com/jison/demo/calc.html) and the source of the page and the narwhal script to generate the parser are [here](http://gist.github.com/265842).
|
||||
|
||||
Specifying a language
|
||||
---------------------
|
||||
The process of parsing a language involves two phases: **lexical analysis** (tokenizing) and **parsing**, which the Lex/Yacc and Flex/Bison combinations are famous for. Jison lets you specify a parser much like you would using Bison/Flex, with separate files for tokenization rules and for the language grammar.
|
||||
|
||||
For example, here is the calculator parser:
|
||||
|
||||
calc.jisonlex, tokenization rules
|
||||
|
||||
%%
|
||||
\s+ {/* skip whitespace */}
|
||||
[0-9]+("."[0-9]+)?\b {return 'NUMBER';}
|
||||
"*" {return '*';}
|
||||
"/" {return '/';}
|
||||
"-" {return '-';}
|
||||
"+" {return '+';}
|
||||
"^" {return '^';}
|
||||
"(" {return '(';}
|
||||
")" {return ')';}
|
||||
"PI" {return 'PI';}
|
||||
"E" {return 'E';}
|
||||
<<EOF>> {return 'EOF';}
|
||||
|
||||
and calc.jison, language grammar
|
||||
|
||||
/* description: Grammar for a parser that parses and executes mathematical expressions. */
|
||||
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
%left '^'
|
||||
%left UMINUS
|
||||
|
||||
%%
|
||||
|
||||
S
|
||||
: e EOF
|
||||
{print($1); return $1;}
|
||||
;
|
||||
|
||||
e
|
||||
: e '+' e
|
||||
{$$ = $1+$3;}
|
||||
| e '-' e
|
||||
{$$ = $1-$3;}
|
||||
| e '*' e
|
||||
{$$ = $1*$3;}
|
||||
| e '/' e
|
||||
{$$ = $1/$3;}
|
||||
| e '^' e
|
||||
{$$ = Math.pow($1, $3);}
|
||||
| '-' e %prec UMINUS
|
||||
{$$ = -$2;}
|
||||
| '(' e ')'
|
||||
{$$ = $2;}
|
||||
| NUMBER
|
||||
{$$ = Number(yytext);}
|
||||
| E
|
||||
{$$ = Math.E;}
|
||||
| PI
|
||||
{$$ = Math.PI;}
|
||||
;
|
||||
|
||||
which compiles down to this JSON:
|
||||
|
||||
{
|
||||
"lex": {
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["[0-9]+(?:\\.[0-9]+)?\\b", "return 'NUMBER';"],
|
||||
["\\*", "return '*';"],
|
||||
["\\/", "return '/';"],
|
||||
["-", "return '-';"],
|
||||
["\\+", "return '+';"],
|
||||
["\\^", "return '^';"],
|
||||
["\\(", "return '(';"],
|
||||
["\\)", "return ')';"],
|
||||
["PI\\b", "return 'PI';"],
|
||||
["E\\b", "return 'E';"],
|
||||
["$", "return 'EOF';"]
|
||||
]
|
||||
},
|
||||
|
||||
"operators": [
|
||||
["left", "+", "-"],
|
||||
["left", "*", "/"],
|
||||
["left", "^"],
|
||||
["left", "UMINUS"]
|
||||
],
|
||||
|
||||
"bnf": {
|
||||
"S" :[[ "e EOF", "print($1); return $1;" ]],
|
||||
|
||||
"e" :[[ "e + e", "$$ = $1+$3;" ],
|
||||
[ "e - e", "$$ = $1-$3;" ],
|
||||
[ "e * e", "$$ = $1*$3;" ],
|
||||
[ "e / e", "$$ = $1/$3;" ],
|
||||
[ "e ^ e", "$$ = Math.pow($1, $3);" ],
|
||||
[ "- e", "$$ = -$2;", {"prec": "UMINUS"} ],
|
||||
[ "( e )", "$$ = $2;" ],
|
||||
[ "NUMBER", "$$ = Number(yytext);" ],
|
||||
[ "E", "$$ = Math.E;" ],
|
||||
[ "PI", "$$ = Math.PI;" ]]
|
||||
}
|
||||
}
|
||||
|
||||
Jison accepts both the Bison/Flex style formats, or the raw JSON format, e.g:
|
||||
|
||||
narwhal bin/jison examples/calculator.jison examples/calculator.jisonlex
|
||||
or
|
||||
narwhal bin/jison examples/calculator.json
|
||||
|
||||
More examples can be found in the `examples/` and `tests/parser/` directories.
|
||||
|
||||
Sharing scope
|
||||
------------
|
||||
|
||||
In Bison, code is expected to be lexically defined within the scope of the semantic actions. E.g., chunks of code may be included in the generated parser source, which are available from semantic actions.
|
||||
|
||||
Jison is more modular. Instead of pulling code into the generated module, the generated module is expected to be required and used by other modules. This means that if you want to expose functionality to the semantic actions, you can't rely on it being available through lexical scoping. Instead, the parser has a `yy` property which is exposed to actions as the `yy` free variable. Any functionality attached to this property is available in both lexical and semantic actions through the `yy` free variable.
|
||||
|
||||
An example from orderly.js:
|
||||
|
||||
var parser = require("./orderly/parse").parser;
|
||||
|
||||
// set parser's shared scope
|
||||
parser.yy = require("./orderly/scope");
|
||||
|
||||
// returns the JSON object
|
||||
var parse = exports.parse = function (input) {
|
||||
return parser.parse(input);
|
||||
};
|
||||
...
|
||||
|
||||
The `scope` module contains logic for building data structures, which is used within the semantic actions.
|
||||
|
||||
*TODO: More on this.*
|
||||
|
||||
Lexical Analysis
|
||||
----------------
|
||||
Jison includes a rather rudimentary lexer, though **any module that supports the basic lexer API could be used** in its place. Jison's lexer uses the `lex` key of the JSON grammar spec, where the rules for matching a token are defined along with the action to execute on a match. Usually, the action will return the token which is used by the Jison parser. A custom lexer could be used instead with it's own methods of tokenizing.
|
||||
|
||||
*TODO: More on this.*
|
||||
|
||||
Parsing algorithms
|
||||
------------------
|
||||
Like Bison, Jison can recognize languages described by LALR(1) grammars, though it also has modes for LR(0), SLR(1), and LR(1). It also has a special mode for generating LL(1) parse tables (requested by my professor,) and could be extended to generate a recursive descent parser for LL(k) languages in the future. But, for now, Jison is geared toward bottom-up parsing.
|
||||
|
||||
**LR(1) mode is currently not practical for use with anything other than toy grammars, but that is entirely a consequence of the algorithm used, and may change in the future.*
|
||||
|
||||
Real world examples
|
||||
------------------
|
||||
|
||||
* [CoffeeScript](http://github.com/jashkenas/coffee-script) uses Jison in its self-compiler.
|
||||
* [Orderly.js][3] uses Jison for compilation.
|
||||
|
||||
|
||||
Contributors
|
||||
------------
|
||||
- Zach Carter
|
||||
- Jarred Ligatti
|
||||
- Manuel E. Bermúdez
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
> Copyright (c) 2009 Zachary Carter
|
||||
>
|
||||
> Permission is hereby granted, free of
|
||||
> charge, to any person obtaining a
|
||||
> copy of this software and associated
|
||||
> documentation files (the "Software"),
|
||||
> to deal in the Software without
|
||||
> restriction, including without
|
||||
> limitation the rights to use, copy,
|
||||
> modify, merge, publish, distribute,
|
||||
> sublicense, and/or sell copies of the
|
||||
> Software, and to permit persons to
|
||||
> whom the Software is furnished to do
|
||||
> so, subject to the following
|
||||
> conditions:
|
||||
>
|
||||
> The above copyright notice and this
|
||||
> permission notice shall be included
|
||||
> in all copies or substantial portions
|
||||
> of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS",
|
||||
> WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
> OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
> TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
> NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF
|
||||
> CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
> FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
> SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
> IN THE SOFTWARE.
|
||||
|
||||
|
||||
[1]: http://dinosaur.compilertools.net/bison/bison_4.html
|
||||
[2]: http://github.com/280north/narwhal
|
||||
[3]: http://github.com/zaach/orderly.js
|
||||
3
vendor/jison/bin/jison
vendored
3
vendor/jison/bin/jison
vendored
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env narwhal
|
||||
|
||||
require('jison').main(system.args);
|
||||
3
vendor/jison/bin/json2jison
vendored
3
vendor/jison/bin/json2jison
vendored
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env narwhal
|
||||
|
||||
require('jison/json2jison').main(system.args);
|
||||
415
vendor/jison/examples/ansic.jison
vendored
415
vendor/jison/examples/ansic.jison
vendored
@@ -1,415 +0,0 @@
|
||||
%token IDENTIFIER CONSTANT STRING_LITERAL SIZEOF
|
||||
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
|
||||
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
||||
%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
|
||||
%token XOR_ASSIGN OR_ASSIGN TYPE_NAME
|
||||
|
||||
%token TYPEDEF EXTERN STATIC AUTO REGISTER
|
||||
%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID
|
||||
%token STRUCT UNION ENUM ELLIPSIS
|
||||
|
||||
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
|
||||
|
||||
%start translation_unit
|
||||
%%
|
||||
|
||||
primary_expression
|
||||
: IDENTIFIER
|
||||
| CONSTANT
|
||||
| STRING_LITERAL
|
||||
| '(' expression ')'
|
||||
;
|
||||
|
||||
postfix_expression
|
||||
: primary_expression
|
||||
| postfix_expression '[' expression ']'
|
||||
| postfix_expression '(' ')'
|
||||
| postfix_expression '(' argument_expression_list ')'
|
||||
| postfix_expression '.' IDENTIFIER
|
||||
| postfix_expression PTR_OP IDENTIFIER
|
||||
| postfix_expression INC_OP
|
||||
| postfix_expression DEC_OP
|
||||
;
|
||||
|
||||
argument_expression_list
|
||||
: assignment_expression
|
||||
| argument_expression_list ',' assignment_expression
|
||||
;
|
||||
|
||||
unary_expression
|
||||
: postfix_expression
|
||||
| INC_OP unary_expression
|
||||
| DEC_OP unary_expression
|
||||
| unary_operator cast_expression
|
||||
| SIZEOF unary_expression
|
||||
| SIZEOF '(' type_name ')'
|
||||
;
|
||||
|
||||
unary_operator
|
||||
: '&'
|
||||
| '*'
|
||||
| '+'
|
||||
| '-'
|
||||
| '~'
|
||||
| '!'
|
||||
;
|
||||
|
||||
cast_expression
|
||||
: unary_expression
|
||||
| '(' type_name ')' cast_expression
|
||||
;
|
||||
|
||||
multiplicative_expression
|
||||
: cast_expression
|
||||
| multiplicative_expression '*' cast_expression
|
||||
| multiplicative_expression '/' cast_expression
|
||||
| multiplicative_expression '%' cast_expression
|
||||
;
|
||||
|
||||
additive_expression
|
||||
: multiplicative_expression
|
||||
| additive_expression '+' multiplicative_expression
|
||||
| additive_expression '-' multiplicative_expression
|
||||
;
|
||||
|
||||
shift_expression
|
||||
: additive_expression
|
||||
| shift_expression LEFT_OP additive_expression
|
||||
| shift_expression RIGHT_OP additive_expression
|
||||
;
|
||||
|
||||
relational_expression
|
||||
: shift_expression
|
||||
| relational_expression '<' shift_expression
|
||||
| relational_expression '>' shift_expression
|
||||
| relational_expression LE_OP shift_expression
|
||||
| relational_expression GE_OP shift_expression
|
||||
;
|
||||
|
||||
equality_expression
|
||||
: relational_expression
|
||||
| equality_expression EQ_OP relational_expression
|
||||
| equality_expression NE_OP relational_expression
|
||||
;
|
||||
|
||||
and_expression
|
||||
: equality_expression
|
||||
| and_expression '&' equality_expression
|
||||
;
|
||||
|
||||
exclusive_or_expression
|
||||
: and_expression
|
||||
| exclusive_or_expression '^' and_expression
|
||||
;
|
||||
|
||||
inclusive_or_expression
|
||||
: exclusive_or_expression
|
||||
| inclusive_or_expression '|' exclusive_or_expression
|
||||
;
|
||||
|
||||
logical_and_expression
|
||||
: inclusive_or_expression
|
||||
| logical_and_expression AND_OP inclusive_or_expression
|
||||
;
|
||||
|
||||
logical_or_expression
|
||||
: logical_and_expression
|
||||
| logical_or_expression OR_OP logical_and_expression
|
||||
;
|
||||
|
||||
conditional_expression
|
||||
: logical_or_expression
|
||||
| logical_or_expression '?' expression ':' conditional_expression
|
||||
;
|
||||
|
||||
assignment_expression
|
||||
: conditional_expression
|
||||
| unary_expression assignment_operator assignment_expression
|
||||
;
|
||||
|
||||
assignment_operator
|
||||
: '='
|
||||
| MUL_ASSIGN
|
||||
| DIV_ASSIGN
|
||||
| MOD_ASSIGN
|
||||
| ADD_ASSIGN
|
||||
| SUB_ASSIGN
|
||||
| LEFT_ASSIGN
|
||||
| RIGHT_ASSIGN
|
||||
| AND_ASSIGN
|
||||
| XOR_ASSIGN
|
||||
| OR_ASSIGN
|
||||
;
|
||||
|
||||
expression
|
||||
: assignment_expression
|
||||
| expression ',' assignment_expression
|
||||
;
|
||||
|
||||
constant_expression
|
||||
: conditional_expression
|
||||
;
|
||||
|
||||
declaration
|
||||
: declaration_specifiers ';'
|
||||
| declaration_specifiers init_declarator_list ';'
|
||||
;
|
||||
|
||||
declaration_specifiers
|
||||
: storage_class_specifier
|
||||
| storage_class_specifier declaration_specifiers
|
||||
| type_specifier
|
||||
| type_specifier declaration_specifiers
|
||||
| type_qualifier
|
||||
| type_qualifier declaration_specifiers
|
||||
;
|
||||
|
||||
init_declarator_list
|
||||
: init_declarator
|
||||
| init_declarator_list ',' init_declarator
|
||||
;
|
||||
|
||||
init_declarator
|
||||
: declarator
|
||||
| declarator '=' initializer
|
||||
;
|
||||
|
||||
storage_class_specifier
|
||||
: TYPEDEF
|
||||
| EXTERN
|
||||
| STATIC
|
||||
| AUTO
|
||||
| REGISTER
|
||||
;
|
||||
|
||||
type_specifier
|
||||
: VOID
|
||||
| CHAR
|
||||
| SHORT
|
||||
| INT
|
||||
| LONG
|
||||
| FLOAT
|
||||
| DOUBLE
|
||||
| SIGNED
|
||||
| UNSIGNED
|
||||
| struct_or_union_specifier
|
||||
| enum_specifier
|
||||
| TYPE_NAME
|
||||
;
|
||||
|
||||
struct_or_union_specifier
|
||||
: struct_or_union IDENTIFIER '{' struct_declaration_list '}'
|
||||
| struct_or_union '{' struct_declaration_list '}'
|
||||
| struct_or_union IDENTIFIER
|
||||
;
|
||||
|
||||
struct_or_union
|
||||
: STRUCT
|
||||
| UNION
|
||||
;
|
||||
|
||||
struct_declaration_list
|
||||
: struct_declaration
|
||||
| struct_declaration_list struct_declaration
|
||||
;
|
||||
|
||||
struct_declaration
|
||||
: specifier_qualifier_list struct_declarator_list ';'
|
||||
;
|
||||
|
||||
specifier_qualifier_list
|
||||
: type_specifier specifier_qualifier_list
|
||||
| type_specifier
|
||||
| type_qualifier specifier_qualifier_list
|
||||
| type_qualifier
|
||||
;
|
||||
|
||||
struct_declarator_list
|
||||
: struct_declarator
|
||||
| struct_declarator_list ',' struct_declarator
|
||||
;
|
||||
|
||||
struct_declarator
|
||||
: declarator
|
||||
| ':' constant_expression
|
||||
| declarator ':' constant_expression
|
||||
;
|
||||
|
||||
enum_specifier
|
||||
: ENUM '{' enumerator_list '}'
|
||||
| ENUM IDENTIFIER '{' enumerator_list '}'
|
||||
| ENUM IDENTIFIER
|
||||
;
|
||||
|
||||
enumerator_list
|
||||
: enumerator
|
||||
| enumerator_list ',' enumerator
|
||||
;
|
||||
|
||||
enumerator
|
||||
: IDENTIFIER
|
||||
| IDENTIFIER '=' constant_expression
|
||||
;
|
||||
|
||||
type_qualifier
|
||||
: CONST
|
||||
| VOLATILE
|
||||
;
|
||||
|
||||
declarator
|
||||
: pointer direct_declarator
|
||||
| direct_declarator
|
||||
;
|
||||
|
||||
direct_declarator
|
||||
: IDENTIFIER
|
||||
| '(' declarator ')'
|
||||
| direct_declarator '[' constant_expression ']'
|
||||
| direct_declarator '[' ']'
|
||||
| direct_declarator '(' parameter_type_list ')'
|
||||
| direct_declarator '(' identifier_list ')'
|
||||
| direct_declarator '(' ')'
|
||||
;
|
||||
|
||||
pointer
|
||||
: '*'
|
||||
| '*' type_qualifier_list
|
||||
| '*' pointer
|
||||
| '*' type_qualifier_list pointer
|
||||
;
|
||||
|
||||
type_qualifier_list
|
||||
: type_qualifier
|
||||
| type_qualifier_list type_qualifier
|
||||
;
|
||||
|
||||
|
||||
parameter_type_list
|
||||
: parameter_list
|
||||
| parameter_list ',' ELLIPSIS
|
||||
;
|
||||
|
||||
parameter_list
|
||||
: parameter_declaration
|
||||
| parameter_list ',' parameter_declaration
|
||||
;
|
||||
|
||||
parameter_declaration
|
||||
: declaration_specifiers declarator
|
||||
| declaration_specifiers abstract_declarator
|
||||
| declaration_specifiers
|
||||
;
|
||||
|
||||
identifier_list
|
||||
: IDENTIFIER
|
||||
| identifier_list ',' IDENTIFIER
|
||||
;
|
||||
|
||||
type_name
|
||||
: specifier_qualifier_list
|
||||
| specifier_qualifier_list abstract_declarator
|
||||
;
|
||||
|
||||
abstract_declarator
|
||||
: pointer
|
||||
| direct_abstract_declarator
|
||||
| pointer direct_abstract_declarator
|
||||
;
|
||||
|
||||
direct_abstract_declarator
|
||||
: '(' abstract_declarator ')'
|
||||
| '[' ']'
|
||||
| '[' constant_expression ']'
|
||||
| direct_abstract_declarator '[' ']'
|
||||
| direct_abstract_declarator '[' constant_expression ']'
|
||||
| '(' ')'
|
||||
| '(' parameter_type_list ')'
|
||||
| direct_abstract_declarator '(' ')'
|
||||
| direct_abstract_declarator '(' parameter_type_list ')'
|
||||
;
|
||||
|
||||
initializer
|
||||
: assignment_expression
|
||||
| '{' initializer_list '}'
|
||||
| '{' initializer_list ',' '}'
|
||||
;
|
||||
|
||||
initializer_list
|
||||
: initializer
|
||||
| initializer_list ',' initializer
|
||||
;
|
||||
|
||||
statement
|
||||
: labeled_statement
|
||||
| compound_statement
|
||||
| expression_statement
|
||||
| selection_statement
|
||||
| iteration_statement
|
||||
| jump_statement
|
||||
;
|
||||
|
||||
labeled_statement
|
||||
: IDENTIFIER ':' statement
|
||||
| CASE constant_expression ':' statement
|
||||
| DEFAULT ':' statement
|
||||
;
|
||||
|
||||
compound_statement
|
||||
: '{' '}'
|
||||
| '{' statement_list '}'
|
||||
| '{' declaration_list '}'
|
||||
| '{' declaration_list statement_list '}'
|
||||
;
|
||||
|
||||
declaration_list
|
||||
: declaration
|
||||
| declaration_list declaration
|
||||
;
|
||||
|
||||
statement_list
|
||||
: statement
|
||||
| statement_list statement
|
||||
;
|
||||
|
||||
expression_statement
|
||||
: ';'
|
||||
| expression ';'
|
||||
;
|
||||
|
||||
selection_statement
|
||||
: IF '(' expression ')' statement
|
||||
| IF '(' expression ')' statement ELSE statement
|
||||
| SWITCH '(' expression ')' statement
|
||||
;
|
||||
|
||||
iteration_statement
|
||||
: WHILE '(' expression ')' statement
|
||||
| DO statement WHILE '(' expression ')' ';'
|
||||
| FOR '(' expression_statement expression_statement ')' statement
|
||||
| FOR '(' expression_statement expression_statement expression ')' statement
|
||||
;
|
||||
|
||||
jump_statement
|
||||
: GOTO IDENTIFIER ';'
|
||||
| CONTINUE ';'
|
||||
| BREAK ';'
|
||||
| RETURN ';'
|
||||
| RETURN expression ';'
|
||||
;
|
||||
|
||||
translation_unit
|
||||
: external_declaration
|
||||
| translation_unit external_declaration
|
||||
;
|
||||
|
||||
external_declaration
|
||||
: function_definition
|
||||
| declaration
|
||||
;
|
||||
|
||||
function_definition
|
||||
: declaration_specifiers declarator declaration_list compound_statement
|
||||
| declaration_specifiers declarator compound_statement
|
||||
| declarator declaration_list compound_statement
|
||||
| declarator compound_statement
|
||||
;
|
||||
8
vendor/jison/examples/basic.json
vendored
8
vendor/jison/examples/basic.json
vendored
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"tokens": "ZERO PLUS",
|
||||
"bnf": {
|
||||
"E" :[ "E PLUS T",
|
||||
"T" ],
|
||||
"T" :[ "ZERO" ]
|
||||
}
|
||||
}
|
||||
9
vendor/jison/examples/basic2.json
vendored
9
vendor/jison/examples/basic2.json
vendored
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"comment": "Basic grammar that contains a nullable A nonterminal.",
|
||||
|
||||
"tokens": "x",
|
||||
"bnf": {
|
||||
"A" :[ "A x",
|
||||
"" ]
|
||||
}
|
||||
}
|
||||
16
vendor/jison/examples/basic2_lex.json
vendored
16
vendor/jison/examples/basic2_lex.json
vendored
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"comment": "Basic grammar that contains a nullable A nonterminal.",
|
||||
|
||||
"lex": {
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["x", "return 'x';"]
|
||||
]
|
||||
},
|
||||
|
||||
"tokens": "x",
|
||||
"bnf": {
|
||||
"A" :[ "A x",
|
||||
"" ]
|
||||
}
|
||||
}
|
||||
15
vendor/jison/examples/basic_lex.json
vendored
15
vendor/jison/examples/basic_lex.json
vendored
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"lex": {
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["[0-9]+", "return 'NAT';"],
|
||||
["\\+", "return '+';"]
|
||||
]
|
||||
},
|
||||
|
||||
"bnf": {
|
||||
"E" :[ "E + T",
|
||||
"T" ],
|
||||
"T" :[ "NAT" ]
|
||||
}
|
||||
}
|
||||
38
vendor/jison/examples/calculator.jison
vendored
38
vendor/jison/examples/calculator.jison
vendored
@@ -1,38 +0,0 @@
|
||||
|
||||
/* description: Parses end executes mathematical expressions. */
|
||||
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
%left '^'
|
||||
%left UMINUS
|
||||
|
||||
%%
|
||||
|
||||
S
|
||||
: e EOF
|
||||
{print($1); return $1;}
|
||||
;
|
||||
|
||||
e
|
||||
: e '+' e
|
||||
{$$ = $1+$3;}
|
||||
| e '-' e
|
||||
{$$ = $1-$3;}
|
||||
| e '*' e
|
||||
{$$ = $1*$3;}
|
||||
| e '/' e
|
||||
{$$ = $1/$3;}
|
||||
| e '^' e
|
||||
{$$ = Math.pow($1, $3);}
|
||||
| '-' e %prec UMINUS
|
||||
{$$ = -$2;}
|
||||
| '(' e ')'
|
||||
{$$ = $2;}
|
||||
| NUMBER
|
||||
{$$ = Number(yytext);}
|
||||
| E
|
||||
{$$ = Math.E;}
|
||||
| PI
|
||||
{$$ = Math.PI;}
|
||||
;
|
||||
|
||||
14
vendor/jison/examples/calculator.jisonlex
vendored
14
vendor/jison/examples/calculator.jisonlex
vendored
@@ -1,14 +0,0 @@
|
||||
%%
|
||||
\s+ {/* skip whitespace */}
|
||||
[0-9]+("."[0-9]+)?\b {return 'NUMBER';}
|
||||
"*" {return '*';}
|
||||
"/" {return '/';}
|
||||
"-" {return '-';}
|
||||
"+" {return '+';}
|
||||
"^" {return '^';}
|
||||
"(" {return '(';}
|
||||
")" {return ')';}
|
||||
"PI" {return 'PI';}
|
||||
"E" {return 'E';}
|
||||
<<EOF>> {return 'EOF';}
|
||||
|
||||
42
vendor/jison/examples/calculator.json
vendored
42
vendor/jison/examples/calculator.json
vendored
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"comment": "Parses end executes mathematical expressions.",
|
||||
|
||||
"lex": {
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["[0-9]+(?:\\.[0-9]+)?\\b", "return 'NUMBER';"],
|
||||
["\\*", "return '*';"],
|
||||
["\\/", "return '/';"],
|
||||
["-", "return '-';"],
|
||||
["\\+", "return '+';"],
|
||||
["\\^", "return '^';"],
|
||||
["\\(", "return '(';"],
|
||||
["\\)", "return ')';"],
|
||||
["PI\\b", "return 'PI';"],
|
||||
["E\\b", "return 'E';"],
|
||||
["$", "return 'EOF';"]
|
||||
]
|
||||
},
|
||||
|
||||
"operators": [
|
||||
["left", "+", "-"],
|
||||
["left", "*", "/"],
|
||||
["left", "^"],
|
||||
["left", "UMINUS"]
|
||||
],
|
||||
|
||||
"bnf": {
|
||||
"S" :[[ "e EOF", "print($1); return $1;" ]],
|
||||
|
||||
"e" :[[ "e + e", "$$ = $1+$3;" ],
|
||||
[ "e - e", "$$ = $1-$3;" ],
|
||||
[ "e * e", "$$ = $1*$3;" ],
|
||||
[ "e / e", "$$ = $1/$3;" ],
|
||||
[ "e ^ e", "$$ = Math.pow($1, $3);" ],
|
||||
[ "- e", "$$ = -$2;", {"prec": "UMINUS"} ],
|
||||
[ "( e )", "$$ = $2;" ],
|
||||
[ "NUMBER", "$$ = Number(yytext);" ],
|
||||
[ "E", "$$ = Math.E;" ],
|
||||
[ "PI", "$$ = Math.PI;" ]]
|
||||
}
|
||||
}
|
||||
105
vendor/jison/examples/classy.json
vendored
105
vendor/jison/examples/classy.json
vendored
@@ -1,105 +0,0 @@
|
||||
{
|
||||
"comment": "ClassyLang grammar. Very classy.",
|
||||
"author": "Zach Carter",
|
||||
|
||||
"lex": {
|
||||
"macros": {
|
||||
"digit": "[0-9]",
|
||||
"id": "[a-zA-Z][a-zA-Z0-9]*"
|
||||
},
|
||||
|
||||
"rules": [
|
||||
["//.*", "/* ignore comment */"],
|
||||
["main\\b", "return 'MAIN';"],
|
||||
["class\\b", "return 'CLASS';"],
|
||||
["extends\\b", "return 'EXTENDS';"],
|
||||
["nat\\b", "return 'NATTYPE';"],
|
||||
["if\\b", "return 'IF';"],
|
||||
["else\\b", "return 'ELSE';"],
|
||||
["for\\b", "return 'FOR';"],
|
||||
["printNat\\b", "return 'PRINTNAT';"],
|
||||
["readNat\\b", "return 'READNAT';"],
|
||||
["this\\b", "return 'THIS';"],
|
||||
["new\\b", "return 'NEW';"],
|
||||
["var\\b", "return 'VAR';"],
|
||||
["null\\b", "return 'NUL';"],
|
||||
["{digit}+", "return 'NATLITERAL';"],
|
||||
["{id}", "return 'ID';"],
|
||||
["==", "return 'EQUALITY';"],
|
||||
["=", "return 'ASSIGN';"],
|
||||
["\\+", "return 'PLUS';"],
|
||||
["-", "return 'MINUS';"],
|
||||
["\\*", "return 'TIMES';"],
|
||||
[">", "return 'GREATER';"],
|
||||
["\\|\\|", "return 'OR';"],
|
||||
["!", "return 'NOT';"],
|
||||
["\\.", "return 'DOT';"],
|
||||
["\\{", "return 'LBRACE';"],
|
||||
["\\}", "return 'RBRACE';"],
|
||||
["\\(", "return 'LPAREN';"],
|
||||
["\\)", "return 'RPAREN';"],
|
||||
[";", "return 'SEMICOLON';"],
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
[".", "throw 'Illegal character: '+yytext;"],
|
||||
["$", "return 'ENDOFFILE';"]
|
||||
]
|
||||
},
|
||||
|
||||
"tokens": "MAIN CLASS EXTENDS NATTYPE IF ELSE FOR PRINTNAT READNAT THIS NEW VAR NUL NATLITERAL ID ASSIGN PLUS MINUS TIMES EQUALITY GREATER OR NOT DOT SEMICOLON LBRACE RBRACE LPAREN RPAREN ENDOFFILE",
|
||||
"operators": [
|
||||
["right", "ASSIGN"],
|
||||
["left", "OR"],
|
||||
["nonassoc", "EQUALITY", "GREATER"],
|
||||
["left", "PLUS", "MINUS"],
|
||||
["left", "TIMES"],
|
||||
["right", "NOT"],
|
||||
["left", "DOT"]
|
||||
],
|
||||
|
||||
"bnf": {
|
||||
"pgm": ["cdl MAIN LBRACE vdl el RBRACE ENDOFFILE"],
|
||||
|
||||
"cdl": ["c cdl",
|
||||
""],
|
||||
|
||||
"c": ["CLASS id EXTENDS id LBRACE vdl mdl RBRACE"],
|
||||
|
||||
"vdl": ["VAR t id SEMICOLON vdl",
|
||||
""],
|
||||
|
||||
"mdl": ["t id LPAREN t id RPAREN LBRACE vdl el RBRACE mdl",
|
||||
""],
|
||||
|
||||
"t": ["NATTYPE",
|
||||
"id"],
|
||||
|
||||
"id": ["ID"],
|
||||
|
||||
"el": ["e SEMICOLON el",
|
||||
"e SEMICOLON"],
|
||||
|
||||
"e": ["NATLITERAL",
|
||||
"NUL",
|
||||
"id",
|
||||
"NEW id",
|
||||
"THIS",
|
||||
"IF LPAREN e RPAREN LBRACE el RBRACE ELSE LBRACE el RBRACE",
|
||||
"FOR LPAREN e SEMICOLON e SEMICOLON e RPAREN LBRACE el RBRACE",
|
||||
"READNAT LPAREN RPAREN",
|
||||
"PRINTNAT LPAREN e RPAREN",
|
||||
"e PLUS e",
|
||||
"e MINUS e",
|
||||
"e TIMES e",
|
||||
"e EQUALITY e",
|
||||
"e GREATER e",
|
||||
"NOT e",
|
||||
"e OR e",
|
||||
"e DOT id",
|
||||
"id ASSIGN e",
|
||||
"e DOT id ASSIGN e",
|
||||
"id LPAREN e RPAREN",
|
||||
"e DOT id LPAREN e RPAREN",
|
||||
"LPAREN e RPAREN"]
|
||||
}
|
||||
}
|
||||
|
||||
126
vendor/jison/examples/classy_ast.json
vendored
126
vendor/jison/examples/classy_ast.json
vendored
@@ -1,126 +0,0 @@
|
||||
{
|
||||
"comment": "ClassyLang grammar with AST-building actions. Very classy.",
|
||||
"author": "Zach Carter",
|
||||
"lex": {
|
||||
"macros": {
|
||||
"digit": "[0-9]",
|
||||
"id": "[a-zA-Z][a-zA-Z0-9]*"
|
||||
},
|
||||
|
||||
"rules": [
|
||||
["//.*", "/* ignore comment */"],
|
||||
["main\\b", "return 'MAIN';"],
|
||||
["class\\b", "return 'CLASS';"],
|
||||
["extends\\b", "return 'EXTENDS';"],
|
||||
["nat\\b", "return 'NATTYPE';"],
|
||||
["if\\b", "return 'IF';"],
|
||||
["else\\b", "return 'ELSE';"],
|
||||
["for\\b", "return 'FOR';"],
|
||||
["printNat\\b", "return 'PRINTNAT';"],
|
||||
["readNat\\b", "return 'READNAT';"],
|
||||
["this\\b", "return 'THIS';"],
|
||||
["new\\b", "return 'NEW';"],
|
||||
["var\\b", "return 'VAR';"],
|
||||
["null\\b", "return 'NUL';"],
|
||||
["{digit}+", "return 'NATLITERAL';"],
|
||||
["{id}", "return 'ID';"],
|
||||
["==", "return 'EQUALITY';"],
|
||||
["=", "return 'ASSIGN';"],
|
||||
["\\+", "return 'PLUS';"],
|
||||
["-", "return 'MINUS';"],
|
||||
["\\*", "return 'TIMES';"],
|
||||
[">", "return 'GREATER';"],
|
||||
["\\|\\|", "return 'OR';"],
|
||||
["!", "return 'NOT';"],
|
||||
["\\.", "return 'DOT';"],
|
||||
["\\{", "return 'LBRACE';"],
|
||||
["\\}", "return 'RBRACE';"],
|
||||
["\\(", "return 'LPAREN';"],
|
||||
["\\)", "return 'RPAREN';"],
|
||||
[";", "return 'SEMICOLON';"],
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
[".", "throw 'Illegal character: '+yytext;"],
|
||||
["$", "return 'ENDOFFILE';"]
|
||||
]
|
||||
},
|
||||
|
||||
"tokens": "MAIN CLASS EXTENDS NATTYPE IF ELSE FOR PRINTNAT READNAT THIS NEW VAR NUL NATLITERAL ID ASSIGN PLUS MINUS TIMES EQUALITY GREATER OR NOT DOT SEMICOLON LBRACE RBRACE LPAREN RPAREN ENDOFFILE",
|
||||
"operators": [
|
||||
["right", "ASSIGN"],
|
||||
["left", "OR"],
|
||||
["nonassoc", "EQUALITY", "GREATER"],
|
||||
["left", "PLUS", "MINUS"],
|
||||
["left", "TIMES"],
|
||||
["right", "NOT"],
|
||||
["left", "DOT"]
|
||||
],
|
||||
|
||||
"bnf": {
|
||||
"pgm": [["cdl MAIN LBRACE vdl el RBRACE ENDOFFILE",
|
||||
"$$ = ['PROGRAM',{},$1,$4,$5]; return $$;"]],
|
||||
|
||||
"cdl": [["c cdl",
|
||||
"$$ = prependChild($2, $1);"],
|
||||
["",
|
||||
"$$ = ['CLASS_DECL_LIST',{}];"]],
|
||||
|
||||
"c": [["CLASS id EXTENDS id LBRACE vdl mdl RBRACE",
|
||||
"$$ = ['CLASS_DECL',{},$2,$4,$6,$7];"]],
|
||||
|
||||
"vdl": [["VAR t id SEMICOLON vdl",
|
||||
"$$ = prependChild($5, ['VAR_DECL',{},$2,$3]);"],
|
||||
["",
|
||||
"$$ = ['VAR_DECL_LIST',{}];"]],
|
||||
|
||||
"mdl": [["t id LPAREN t id RPAREN LBRACE vdl el RBRACE mdl",
|
||||
"$$ = prependChild($11, ['METHOD_DECL',{},$1,$2,$4,$5,$8,$9]);"],
|
||||
["",
|
||||
"$$ = ['METHOD_DECL_LIST',{}];"]],
|
||||
|
||||
"t": [["NATTYPE",
|
||||
"$$ = ['NAT_TYPE',{}];"],
|
||||
["id",
|
||||
"$$ = $1"]],
|
||||
|
||||
"id": [["ID",
|
||||
"$$ = ['AST_ID',{val:yytext}]"]],
|
||||
"el": [["e SEMICOLON el",
|
||||
"$$ = prependChild($3, $1);"],
|
||||
["e SEMICOLON",
|
||||
"$$ = ['EXPR_LIST',{},$1];"]],
|
||||
|
||||
"e": [["NATLITERAL", "$$ = ['NAT_LITERAL_EXPR',{val:parseInt(yytext)}];"],
|
||||
["NUL", "$$ = ['NULL_EXPR',{}];"],
|
||||
["id", "$$ = ['ID_EXPR',{},$1];"],
|
||||
["NEW id", "$$ = ['NEW_EXPR',{},$2];"],
|
||||
["THIS", "$$ = ['THIS_EXPR',{}];"],
|
||||
["IF LPAREN e RPAREN LBRACE el RBRACE ELSE LBRACE el RBRACE",
|
||||
"$$ = ['IF_THEN_ELSE_EXPR',{},$3,$6,$10];"],
|
||||
["FOR LPAREN e SEMICOLON e SEMICOLON e RPAREN LBRACE el RBRACE",
|
||||
"$$ = ['FOR_EXPR',{},$3,$5,$7,$10];"],
|
||||
["READNAT LPAREN RPAREN",
|
||||
"$$ = ['READ_EXPR',{}];"],
|
||||
["PRINTNAT LPAREN e RPAREN",
|
||||
"$$ = ['PRINT_EXPR',{},$3];"],
|
||||
["e PLUS e", "$$ = ['PLUS_EXPR',{},$1,$3];"],
|
||||
["e MINUS e", "$$ = ['MINUS_EXPR',{},$1,$3];"],
|
||||
["e TIMES e", "$$ = ['TIMES_EXPR',{},$1,$3];"],
|
||||
["e EQUALITY e", "$$ = ['EQUALITY_EXPR',{},$1,$3];"],
|
||||
["e GREATER e", "$$ = ['GREATER_THAN_EXPR',{},$1,$3];"],
|
||||
["NOT e", "$$ = ['NOT_EXPR',{},$2];"],
|
||||
["e OR e", "$$ = ['OR_EXPR',{},$1,$3];"],
|
||||
["e DOT id", "$$ = ['DOT_ID_EXPR',{},$1,$3];"],
|
||||
["id ASSIGN e", "$$ = ['ASSIGN_EXPR',{},$1,$3];"],
|
||||
["e DOT id ASSIGN e",
|
||||
"$$ = ['DOT_ASSIGN_EXPR',{},$1,$3,$5];"],
|
||||
["id LPAREN e RPAREN",
|
||||
"$$ = ['METHOD_CALL_EXPR',{},$1,$3];"],
|
||||
["e DOT id LPAREN e RPAREN",
|
||||
"$$ = ['DOT_METHOD_CALL_EXPR',{},$1,$3,$5];"],
|
||||
["LPAREN e RPAREN",
|
||||
"$$ = $2;"]]
|
||||
},
|
||||
|
||||
"actionInclude": "function prependChild(node, child){ node.splice(2,0,child); return node; }"
|
||||
}
|
||||
|
||||
25
vendor/jison/examples/dism.json
vendored
25
vendor/jison/examples/dism.json
vendored
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"author": "Jay Ligatti",
|
||||
|
||||
"tokens": "ADD SUB MUL MOV LOD STR JMP BEQ BLT RDN PTN HLT INT LABEL COLON",
|
||||
"bnf": {
|
||||
"pgm" :[ "instlist" ],
|
||||
"instlist" :[ "label COLON inst instlist",
|
||||
"inst instlist",
|
||||
"" ],
|
||||
"inst" :[ "ADD intt intt intt",
|
||||
"SUB intt intt intt",
|
||||
"MUL intt intt intt",
|
||||
"MOV intt intt",
|
||||
"LOD intt intt intt",
|
||||
"STR intt intt intt",
|
||||
"JMP intt intt intt",
|
||||
"BEQ intt intt intt",
|
||||
"BLT intt intt intt",
|
||||
"RDN intt",
|
||||
"PTN intt",
|
||||
"HLT intt"],
|
||||
"label" :[ "LABEL" ],
|
||||
"intt" :[ "INT", "label" ]
|
||||
}
|
||||
}
|
||||
26
vendor/jison/examples/dism_lr0.json
vendored
26
vendor/jison/examples/dism_lr0.json
vendored
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"author": "Jay Ligatti",
|
||||
|
||||
"tokens": "ADD SUB MUL MOV LOD STR JMP BEQ BLT RDN PTN HLT INT LABEL COLON",
|
||||
"bnf": {
|
||||
"instlist" :[ "instlist label COLON inst",
|
||||
"instlist inst",
|
||||
"inst" ],
|
||||
|
||||
"inst" :[ "ADD intt intt intt",
|
||||
"SUB intt intt intt",
|
||||
"MUL intt intt intt",
|
||||
"MOV intt intt",
|
||||
"LOD intt intt intt",
|
||||
"STR intt intt intt",
|
||||
"JMP intt intt intt",
|
||||
"BEQ intt intt intt",
|
||||
"BLT intt intt intt",
|
||||
"RDN intt",
|
||||
"PTN intt",
|
||||
"HLT intt"],
|
||||
"label" :[ "LABEL" ],
|
||||
"intt" :[ "INT", "label" ]
|
||||
}
|
||||
}
|
||||
|
||||
80
vendor/jison/examples/json.js
vendored
80
vendor/jison/examples/json.js
vendored
@@ -1,80 +0,0 @@
|
||||
var Generator = require("jison").Generator;
|
||||
var system = require("system");
|
||||
var fs = require("file");
|
||||
|
||||
exports.grammar = {
|
||||
"comment": "ECMA-262 5th Edition, 15.12.1 The JSON Grammar.",
|
||||
"author": "Zach Carter",
|
||||
|
||||
"lex": {
|
||||
"macros": {
|
||||
"digit": "[0-9]",
|
||||
"esc": "\\\\",
|
||||
"int": "-?(?:[0-9]|[1-9][0-9]+)",
|
||||
"exp": "(?:[eE][-+]?[0-9]+)",
|
||||
"frac": "(?:\\.[0-9]+)"
|
||||
},
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["{int}{frac}?{exp}?\\b", "return 'NUMBER';"],
|
||||
["\"(?:{esc}[\"bfnrt/{esc}]|{esc}u[a-fA-F0-9]{4}|[^\"{esc}])*\"", "yytext = yytext.substr(1,yyleng-2); return 'STRING';"],
|
||||
["\\{", "return '{'"],
|
||||
["\\}", "return '}'"],
|
||||
["\\[", "return '['"],
|
||||
["\\]", "return ']'"],
|
||||
[",", "return ','"],
|
||||
[":", "return ':'"],
|
||||
["true\\b", "return 'TRUE'"],
|
||||
["false\\b", "return 'FALSE'"],
|
||||
["null\\b", "return 'NULL'"]
|
||||
]
|
||||
},
|
||||
|
||||
"tokens": "STRING NUMBER { } [ ] , : TRUE FALSE NULL",
|
||||
"start": "JSONText",
|
||||
|
||||
"bnf": {
|
||||
"JSONString": [ "STRING" ],
|
||||
|
||||
"JSONNumber": [ "NUMBER" ],
|
||||
|
||||
"JSONBooleanLiteral": [ "TRUE", "FALSE" ],
|
||||
|
||||
|
||||
"JSONText": [ "JSONValue" ],
|
||||
|
||||
"JSONValue": [ "JSONNullLiteral",
|
||||
"JSONBooleanLiteral",
|
||||
"JSONString",
|
||||
"JSONNumber",
|
||||
"JSONObject",
|
||||
"JSONArray" ],
|
||||
|
||||
"JSONObject": [ "{ }",
|
||||
"{ JSONMemberList }" ],
|
||||
|
||||
"JSONMember": [ "JSONString : JSONValue" ],
|
||||
|
||||
"JSONMemberList": [ "JSONMember",
|
||||
"JSONMemberList , JSONMember" ],
|
||||
|
||||
"JSONArray": [ "[ ]",
|
||||
"[ JSONElementList ]" ],
|
||||
|
||||
"JSONElementList": [ "JSONValue",
|
||||
"JSONElementList , JSONValue" ]
|
||||
}
|
||||
};
|
||||
|
||||
var options = {type: "slr", moduleType: "commonjs", moduleName: "jsoncheck"};
|
||||
|
||||
exports.main = function main (args) {
|
||||
var cwd = fs.path(fs.cwd()),
|
||||
code = new Generator(exports.grammar, options).generate(),
|
||||
stream = cwd.join(options.moduleName+".js").open("w");
|
||||
stream.print(code).close();
|
||||
};
|
||||
|
||||
if (require.main === module)
|
||||
exports.main(system.args);
|
||||
|
||||
83
vendor/jison/examples/json_ast.js
vendored
83
vendor/jison/examples/json_ast.js
vendored
@@ -1,83 +0,0 @@
|
||||
var Generator = require("jison").Generator;
|
||||
var system = require("system");
|
||||
var fs = require("file");
|
||||
|
||||
exports.grammar = {
|
||||
"comment": "ECMA-262 5th Edition, 15.12.1 The JSON Grammar. Parses JSON strings into objects.",
|
||||
"author": "Zach Carter",
|
||||
|
||||
"lex": {
|
||||
"macros": {
|
||||
"digit": "[0-9]",
|
||||
"esc": "\\\\",
|
||||
"int": "-?(?:[0-9]|[1-9][0-9]+)",
|
||||
"exp": "(?:[eE][-+]?[0-9]+)",
|
||||
"frac": "(?:\\.[0-9]+)"
|
||||
},
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["{int}{frac}?{exp}?\\b", "return 'NUMBER';"],
|
||||
["\"(?:{esc}[\"bfnrt/{esc}]|{esc}u[a-fA-F0-9]{4}|[^\"{esc}])*\"", "yytext = yytext.substr(1,yyleng-2); return 'STRING';"],
|
||||
["\\{", "return '{'"],
|
||||
["\\}", "return '}'"],
|
||||
["\\[", "return '['"],
|
||||
["\\]", "return ']'"],
|
||||
[",", "return ','"],
|
||||
[":", "return ':'"],
|
||||
["true\\b", "return 'TRUE'"],
|
||||
["false\\b", "return 'FALSE'"],
|
||||
["null\\b", "return 'NULL'"]
|
||||
]
|
||||
},
|
||||
|
||||
"tokens": "STRING NUMBER { } [ ] , : TRUE FALSE NULL",
|
||||
"start": "JSONText",
|
||||
|
||||
"bnf": {
|
||||
"JSONString": [[ "STRING", "$$ = yytext;" ]],
|
||||
|
||||
"JSONNumber": [[ "NUMBER", "$$ = Number(yytext);" ]],
|
||||
|
||||
"JSONNullLiteral": [[ "NULL", "$$ = null;" ]],
|
||||
|
||||
"JSONBooleanLiteral": [[ "TRUE", "$$ = true;" ],
|
||||
[ "FALSE", "$$ = false;" ]],
|
||||
|
||||
|
||||
"JSONText": [[ "JSONValue", "return $$ = $1;" ]],
|
||||
|
||||
"JSONValue": [[ "JSONNullLiteral", "$$ = $1;" ],
|
||||
[ "JSONBooleanLiteral", "$$ = $1;" ],
|
||||
[ "JSONString", "$$ = $1;" ],
|
||||
[ "JSONNumber", "$$ = $1;" ],
|
||||
[ "JSONObject", "$$ = $1;" ],
|
||||
[ "JSONArray", "$$ = $1;" ]],
|
||||
|
||||
"JSONObject": [[ "{ }", "$$ = {};" ],
|
||||
[ "{ JSONMemberList }", "$$ = $2;" ]],
|
||||
|
||||
"JSONMember": [[ "JSONString : JSONValue", "$$ = [$1, $3];" ]],
|
||||
|
||||
"JSONMemberList": [[ "JSONMember", "$$ = {}; $$[$1[0]] = $1[1];" ],
|
||||
[ "JSONMemberList , JSONMember", "$$ = $1; $1[$3[0]] = $3[1];" ]],
|
||||
|
||||
"JSONArray": [[ "[ ]", "$$ = [];" ],
|
||||
[ "[ JSONElementList ]", "$$ = $2;" ]],
|
||||
|
||||
"JSONElementList": [[ "JSONValue", "$$ = [$1];" ],
|
||||
[ "JSONElementList , JSONValue", "$$ = $1; $1.push($3);" ]]
|
||||
}
|
||||
};
|
||||
|
||||
var options = {type: "slr", moduleType: "commonjs", moduleName: "jsonparse"};
|
||||
|
||||
exports.main = function main (args) {
|
||||
var cwd = fs.path(fs.cwd()),
|
||||
code = new Generator(exports.grammar, options).generate(),
|
||||
stream = cwd.join(options.moduleName+".js").open("w");
|
||||
stream.print(code).close();
|
||||
};
|
||||
|
||||
if (require.main === module)
|
||||
exports.main(system.args);
|
||||
|
||||
26
vendor/jison/examples/precedence.json
vendored
26
vendor/jison/examples/precedence.json
vendored
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"comment": "Grammar showing precedence operators and semantic actions.",
|
||||
|
||||
"lex": {
|
||||
"rules": [
|
||||
["\\s+", "/* skip whitespace */"],
|
||||
["[0-9]+", "return 'NAT';"],
|
||||
["\\+", "return '+';"],
|
||||
["\\*", "return '*';"],
|
||||
["$", "return 'EOF';"]
|
||||
]
|
||||
},
|
||||
|
||||
"tokens": "NAT + * EOF",
|
||||
"operators": [
|
||||
["left", "+"],
|
||||
["left", "*"]
|
||||
],
|
||||
"bnf": {
|
||||
"S" :[[ "e EOF", "return $1;" ]],
|
||||
"e" :[[ "e + e", "$$ = [$1,'+', $3];" ],
|
||||
[ "e * e", "$$ = [$1, '*', $3];" ],
|
||||
[ "NAT", "$$ = parseInt(yytext);" ]]
|
||||
}
|
||||
}
|
||||
|
||||
13
vendor/jison/examples/reduce_conflict.json
vendored
13
vendor/jison/examples/reduce_conflict.json
vendored
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"comment": "Produces a reduce-reduce conflict unless using LR(1).",
|
||||
"tokens": "z d b c a",
|
||||
"start": "S",
|
||||
"bnf": {
|
||||
"S" :[ "a A c",
|
||||
"a B d",
|
||||
"b A d",
|
||||
"b B c"],
|
||||
"A" :[ "z" ],
|
||||
"B" :[ "z" ]
|
||||
}
|
||||
}
|
||||
133
vendor/jison/lib/jison.js
vendored
133
vendor/jison/lib/jison.js
vendored
@@ -152,10 +152,10 @@ generator.augmentGrammar = function augmentGrammar (grammar) {
|
||||
this.productions.unshift(acceptProduction);
|
||||
|
||||
// prepend parser tokens
|
||||
this.symbols.unshift("$accept","$end");
|
||||
this.symbols.unshift("$accept",this.EOF);
|
||||
this.symbols_["$accept"] = 0;
|
||||
this.symbols_["$end"] = 1;
|
||||
this.terminals.unshift("$end");
|
||||
this.symbols_[this.EOF] = 1;
|
||||
this.terminals.unshift(this.EOF);
|
||||
|
||||
this.nonterminals["$accept"] = new Nonterminal("$accept");
|
||||
this.nonterminals["$accept"].productions.push(acceptProduction);
|
||||
@@ -184,6 +184,8 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
|
||||
var symbolId = 1;
|
||||
var symbols_ = {};
|
||||
|
||||
var her = false; // has error recovery
|
||||
|
||||
function addSymbol (s) {
|
||||
if (s && !symbols_[s]) {
|
||||
symbols_[s] = ++symbolId;
|
||||
@@ -191,6 +193,9 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
|
||||
}
|
||||
}
|
||||
|
||||
// add error symbol; will be third symbol, or "2" ($accept, $end, error)
|
||||
addSymbol("error");
|
||||
|
||||
for (symbol in bnf) {
|
||||
if (!bnf.hasOwnProperty(symbol)) continue;
|
||||
|
||||
@@ -211,7 +216,7 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
|
||||
else
|
||||
rhs = handle[0].slice(0);
|
||||
|
||||
for (i=0; i<rhs.length; i++) if (!symbols_[rhs[i]]) {
|
||||
for (i=0; her = her || rhs[i] === 'error',i<rhs.length; i++) if (!symbols_[rhs[i]]) {
|
||||
addSymbol(rhs[i]);
|
||||
}
|
||||
|
||||
@@ -252,7 +257,7 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
|
||||
}
|
||||
} else {
|
||||
rhs = handle.trim().split(' ');
|
||||
for (i=0; i<rhs.length; i++) if (!symbols_[rhs[i]]) {
|
||||
for (i=0; her = her || rhs[i] === 'error',i<rhs.length; i++) if (!symbols_[rhs[i]]) {
|
||||
addSymbol(rhs[i]);
|
||||
}
|
||||
r = new Production(symbol, rhs, productions.length+1);
|
||||
@@ -280,6 +285,8 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
|
||||
}
|
||||
});
|
||||
|
||||
this.hasErrorRecovery = her;
|
||||
|
||||
this.terminals = terms;
|
||||
this.terminals_ = terms_;
|
||||
this.symbols_ = symbols_;
|
||||
@@ -861,14 +868,14 @@ lrGeneratorMixin.generateModule = function generateModule (opt) {
|
||||
lrGeneratorMixin.generateModule_ = function generateModule_ () {
|
||||
var out = "{";
|
||||
out += [
|
||||
"trace: " + String(this.trace),
|
||||
"trace: " + String(this.trace || parser.trace),
|
||||
"yy: {}",
|
||||
"symbols_: " + JSON.stringify(this.symbols_),
|
||||
"terminals_: " + JSON.stringify(this.terminals_),
|
||||
"productions_: " + JSON.stringify(this.productions_),
|
||||
"performAction: " + String(this.performAction),
|
||||
"table: " + JSON.stringify(this.table),
|
||||
"parseError: " + String(this.parseError || parser.parseError),
|
||||
"parseError: " + String(this.parseError || (this.hasErrorRecovery ? traceParseError : parser.parseError)),
|
||||
"parse: " + String(parser.parse)
|
||||
].join(",\n");
|
||||
out += "};";
|
||||
@@ -882,7 +889,7 @@ function commonjsMain (args) {
|
||||
if (!args[1])
|
||||
throw new Error('Usage: '+args[0]+' FILE');
|
||||
var source = cwd.join(args[1]).read({charset: "utf-8"});
|
||||
this.parse(source);
|
||||
exports.parser.parse(source);
|
||||
}
|
||||
|
||||
// debug mixin for LR parser generators
|
||||
@@ -925,6 +932,7 @@ var parser = typal.beget();
|
||||
|
||||
lrGeneratorMixin.createParser = function createParser () {
|
||||
var p = parser.beget();
|
||||
p.yy = {};
|
||||
|
||||
p.init({
|
||||
table: this.table,
|
||||
@@ -934,6 +942,11 @@ lrGeneratorMixin.createParser = function createParser () {
|
||||
performAction: this.performAction
|
||||
});
|
||||
|
||||
// don't throw if grammar recovers from errors
|
||||
if (this.hasErrorRecovery) {
|
||||
p.parseError = traceParseError;
|
||||
}
|
||||
|
||||
// for debugging
|
||||
p.productions = this.productions;
|
||||
|
||||
@@ -947,11 +960,14 @@ lrGeneratorMixin.createParser = function createParser () {
|
||||
return p;
|
||||
};
|
||||
|
||||
parser.yy = {};
|
||||
parser.trace = generator.trace;
|
||||
parser.warn = generator.warn;
|
||||
parser.error = generator.error;
|
||||
|
||||
function traceParseError (err, hash) {
|
||||
this.trace(err);
|
||||
}
|
||||
|
||||
parser.parseError = lrGeneratorMixin.parseError = function parseError (str, hash) {
|
||||
throw new Error(str);
|
||||
};
|
||||
@@ -965,12 +981,29 @@ parser.parse = function parse (input) {
|
||||
yylineno = 0,
|
||||
yyleng = 0,
|
||||
shifts = 0,
|
||||
reductions = 0;
|
||||
reductions = 0,
|
||||
recovering = 0,
|
||||
TERROR = 2,
|
||||
EOF = 1;
|
||||
|
||||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
this.yy.lexer = this.lexer;
|
||||
|
||||
var parseError = this.yy.parseError = this.yy.parseError || this.parseError;
|
||||
var parseError = this.yy.parseError = typeof this.yy.parseError == 'function' ? this.yy.parseError : this.parseError;
|
||||
|
||||
function popStack (n) {
|
||||
stack.length = stack.length - 2*n;
|
||||
vstack.length = vstack.length - n;
|
||||
}
|
||||
|
||||
function checkRecover (st) {
|
||||
for (var p in table[st]) if (p == TERROR) {
|
||||
//print('RECOVER!!');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lex() {
|
||||
var token;
|
||||
@@ -982,7 +1015,7 @@ parser.parse = function parse (input) {
|
||||
return token;
|
||||
};
|
||||
|
||||
var symbol, state, action, a, r, yyval={},p,len,ip=0,newState, expected;
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected, recovered = false;
|
||||
symbol = lex();
|
||||
while (true) {
|
||||
// set first input
|
||||
@@ -990,18 +1023,55 @@ parser.parse = function parse (input) {
|
||||
// read action for current state and first input
|
||||
action = table[state] && table[state][symbol];
|
||||
|
||||
// handle parse error
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p != 1) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
|
||||
if (!recovering) {
|
||||
// Report error
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
}
|
||||
if (this.lexer.showPosition) {
|
||||
parseError.call(this, 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', '),
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, expected: expected});
|
||||
} else {
|
||||
parseError.call(this, 'Parse error on line '+(yylineno+1)+": Unexpected '"+this.terminals_[symbol]+"'",
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, expected: expected});
|
||||
}
|
||||
}
|
||||
if (this.lexer.showPosition) {
|
||||
parseError('Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', '),
|
||||
{text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
|
||||
} else {
|
||||
parseError('Parse error on line '+(yylineno+1)+": Unexpected '"+this.terminals_[symbol]+"'",
|
||||
{text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
|
||||
|
||||
// just recovered from another error
|
||||
if (recovering == 3) {
|
||||
if (symbol == EOF) {
|
||||
throw 'Parsing halted.'
|
||||
}
|
||||
|
||||
// discard current lookahead and grab another
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
symbol = lex();
|
||||
}
|
||||
|
||||
// try to recover from error
|
||||
while (1) {
|
||||
// check for error recovery rule in this state
|
||||
if (checkRecover(state)) {
|
||||
break;
|
||||
}
|
||||
if (state == 0) {
|
||||
throw 'Parsing halted.'
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length-1];
|
||||
}
|
||||
|
||||
preErrorSymbol = symbol; // save the lookahead token
|
||||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||||
state = stack[stack.length-1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||||
}
|
||||
|
||||
// this shouldn't happen, unless resolve defaults are off
|
||||
@@ -1009,20 +1079,27 @@ parser.parse = function parse (input) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
||||
}
|
||||
|
||||
a = action;
|
||||
a = action;
|
||||
|
||||
switch (a[0]) {
|
||||
|
||||
case 1: // shift
|
||||
shifts++;
|
||||
|
||||
stack.push(symbol);++ip;
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
symbol = lex();
|
||||
vstack.push(null); // semantic values or junk only, no terminals
|
||||
stack.push(symbol);
|
||||
vstack.push(this.lexer.yytext); // semantic values or junk only, no terminals
|
||||
stack.push(a[1]); // push state
|
||||
if (!preErrorSymbol) { // normal execution/no error
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
symbol = lex();
|
||||
if (recovering > 0)
|
||||
recovering--;
|
||||
} else { // error just occurred, resume old lookahead f/ before error
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // reduce
|
||||
|
||||
13
vendor/jison/lib/jison/bnf.js
vendored
13
vendor/jison/lib/jison/bnf.js
vendored
@@ -1,14 +1,18 @@
|
||||
if (typeof require !== 'undefined') {
|
||||
var bnf = require("./util/bnf-parser").parser;
|
||||
var jisonlex = require("./jisonlex");
|
||||
exports.parse = function parse () { return bnf.parse.apply(bnf, arguments) };
|
||||
}
|
||||
|
||||
// adds a declaration to the grammar
|
||||
bnf.yy.addDeclaration = function (grammar, decl) {
|
||||
if (decl.start) {
|
||||
grammar.start = decl.start
|
||||
grammar.start = decl.start;
|
||||
}
|
||||
if (decl.operator) {
|
||||
else if (decl.lex) {
|
||||
grammar.lex = parseLex(decl.lex);
|
||||
}
|
||||
else if (decl.operator) {
|
||||
if (!grammar.operators) {
|
||||
grammar.operators = [];
|
||||
}
|
||||
@@ -41,3 +45,8 @@ bnf.yy.lexAction = function (lexer) {
|
||||
}
|
||||
}
|
||||
|
||||
// parse an embedded lex section
|
||||
var parseLex = function (text) {
|
||||
return jisonlex.parse(text.replace(/(?:^%lex)|(?:\/lex$)/g, ''));
|
||||
}
|
||||
|
||||
|
||||
12
vendor/jison/lib/jison/jisonlex.js
vendored
12
vendor/jison/lib/jison/jisonlex.js
vendored
@@ -1,11 +1,15 @@
|
||||
if (typeof require !== 'undefined') {
|
||||
var jisonlex = require("./util/lex-parser").parser;
|
||||
exports.parse = function parse () {
|
||||
jisonlex.yy.ruleSection = false;
|
||||
return jisonlex.parse.apply(jisonlex, arguments);
|
||||
};
|
||||
} else {
|
||||
var exports = jisonlex;
|
||||
}
|
||||
|
||||
var parse_ = jisonlex.parse;
|
||||
jisonlex.parse = exports.parse = function parse () {
|
||||
jisonlex.yy.ruleSection = false;
|
||||
return parse_.apply(jisonlex, arguments);
|
||||
};
|
||||
|
||||
function encodeRE (s) { return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); }
|
||||
|
||||
jisonlex.yy = {
|
||||
|
||||
30
vendor/jison/lib/jison/json2jison.js
vendored
30
vendor/jison/lib/jison/json2jison.js
vendored
@@ -18,13 +18,16 @@ function genDecls (grammar, options) {
|
||||
if (key === 'start') {
|
||||
s += "\n%start "+grammar.start+"\n\n";
|
||||
}
|
||||
if (key === 'author') {
|
||||
else if (key === 'author') {
|
||||
s += "\n/* author: "+grammar.author+" */\n\n";
|
||||
}
|
||||
if (key === 'comment') {
|
||||
else if (key === 'comment') {
|
||||
s += "\n/* description: "+grammar.comment+" */\n\n";
|
||||
}
|
||||
if (key === 'operators') {
|
||||
else if (key === 'lex') {
|
||||
s += "%lex\n"+genLex(grammar.lex)+"/lex\n\n";
|
||||
}
|
||||
else if (key === 'operators') {
|
||||
for (var i=0; i<grammar.operators.length; i++) {
|
||||
s += "%"+grammar.operators[i][0]+' '+quoteSymbols(grammar.operators[i].slice(1).join(' '))+"\n";
|
||||
}
|
||||
@@ -100,8 +103,8 @@ function genLex (lex) {
|
||||
var s = [];
|
||||
|
||||
if (lex.macros) {
|
||||
for (var macro;macro=lex.macros.shift();) {
|
||||
s.push(macro[0], '\t\t', macros[1], '\n');
|
||||
for (var macro in lex.macros) if (lex.macros.hasOwnProperty(macro)) {
|
||||
s.push(macro, ' ', lex.macros[macro], '\n');
|
||||
}
|
||||
}
|
||||
if (lex.actionInclude) {
|
||||
@@ -110,14 +113,16 @@ function genLex (lex) {
|
||||
s.push('\n%%\n');
|
||||
if (lex.rules) {
|
||||
for (var rule;rule=lex.rules.shift();) {
|
||||
s.push(rule[0], ' ', genLexRule(rule[1]), '\n');
|
||||
s.push(genLexRegex(rule[0]), ' ', genLexRule(rule[1]), '\n');
|
||||
}
|
||||
}
|
||||
s.push('\n%%\n');
|
||||
s.push('\n');
|
||||
|
||||
return s.join('');
|
||||
}
|
||||
|
||||
function genLexRegex (regex) {
|
||||
return regex.match(/\\b$/) ? '"'+regex.replace(/\\b$/, '')+'"' : regex;
|
||||
}
|
||||
function genLexRule (rule) {
|
||||
return rule.match(/\\}/) ? '%{'+rule+'}%' : '{'+rule+'}';
|
||||
}
|
||||
@@ -136,14 +141,5 @@ exports.main = function main (args) {
|
||||
stream.print(json2jison(grammar));
|
||||
stream.close();
|
||||
}
|
||||
|
||||
var lex = grammar.lex || grammar.rules && grammar;
|
||||
|
||||
if (lex) {
|
||||
var fname = fs.path(fs.cwd()).join(gfile.basename(".json").replace(/[._]?lex$/,'') + ".jisonlex"),
|
||||
stream = fname.open("w");
|
||||
stream.print(genLex(lex));
|
||||
stream.close();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
24
vendor/jison/lib/jison/lexer.js
vendored
24
vendor/jison/lib/jison/lexer.js
vendored
@@ -9,6 +9,10 @@ function prepareRules(rules, macros, actions, tokens) {
|
||||
var m,i,k,action,
|
||||
newRules = [];
|
||||
|
||||
if (macros) {
|
||||
macros = prepareMacros(macros);
|
||||
}
|
||||
|
||||
actions.push('switch(arguments[2]) {');
|
||||
|
||||
for (i=0;i < rules.length; i++) {
|
||||
@@ -38,6 +42,26 @@ function prepareRules(rules, macros, actions, tokens) {
|
||||
return newRules;
|
||||
}
|
||||
|
||||
// expand macros within macros
|
||||
function prepareMacros (macros) {
|
||||
var cont = true,
|
||||
m,i,k,mnew;
|
||||
while (cont) {
|
||||
cont = false;
|
||||
for (i in macros) if (macros.hasOwnProperty(i)) {
|
||||
m = macros[i];
|
||||
for (k in macros) if (macros.hasOwnProperty(k) && i !== k) {
|
||||
mnew = m.split("{"+k+"}").join(macros[k]);
|
||||
if (mnew !== m) {
|
||||
cont = true;
|
||||
macros[i] = mnew;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return macros;
|
||||
}
|
||||
|
||||
function buildActions (dict, tokens) {
|
||||
var actions = [dict.actionInclude || ''];
|
||||
var tok;
|
||||
|
||||
188
vendor/jison/lib/jison/util/bnf-parser.js
vendored
188
vendor/jison/lib/jison/util/bnf-parser.js
vendored
@@ -3,9 +3,9 @@ var bnf = (function(){
|
||||
var parser = {trace: function trace() {
|
||||
},
|
||||
yy: {},
|
||||
symbols_: {"spec":2,"declaration_list":3,"%%":4,"grammar":5,"EOF":6,"declaration":7,"START":8,"id":9,"operator":10,"associativity":11,"token_list":12,"LEFT":13,"RIGHT":14,"NONASSOC":15,"symbol":16,"production_list":17,"production":18,":":19,"handle_list":20,";":21,"|":22,"handle_action":23,"handle":24,"prec":25,"action":26,"PREC":27,"STRING":28,"ID":29,"ACTION":30,"$accept":0,"$end":1},
|
||||
terminals_: {"4":"%%","6":"EOF","8":"START","13":"LEFT","14":"RIGHT","15":"NONASSOC","19":":","21":";","22":"|","27":"PREC","28":"STRING","29":"ID","30":"ACTION"},
|
||||
productions_: [0,[2,4],[2,5],[3,2],[3,0],[7,2],[7,1],[10,2],[11,1],[11,1],[11,1],[12,2],[12,1],[5,1],[17,2],[17,1],[18,4],[20,3],[20,1],[23,3],[24,2],[24,0],[25,2],[25,0],[16,1],[16,1],[9,1],[26,1],[26,0]],
|
||||
symbols_: {"error":2,"spec":3,"declaration_list":4,"%%":5,"grammar":6,"EOF":7,"declaration":8,"START":9,"id":10,"LEX_BLOCK":11,"operator":12,"associativity":13,"token_list":14,"LEFT":15,"RIGHT":16,"NONASSOC":17,"symbol":18,"production_list":19,"production":20,":":21,"handle_list":22,";":23,"|":24,"handle_action":25,"handle":26,"prec":27,"action":28,"PREC":29,"STRING":30,"ID":31,"ACTION":32,"$accept":0,"$end":1},
|
||||
terminals_: {"2":"error","5":"%%","7":"EOF","9":"START","11":"LEX_BLOCK","15":"LEFT","16":"RIGHT","17":"NONASSOC","21":":","23":";","24":"|","29":"PREC","30":"STRING","31":"ID","32":"ACTION"},
|
||||
productions_: [0,[3,4],[3,5],[4,2],[4,0],[8,2],[8,1],[8,1],[12,2],[13,1],[13,1],[13,1],[14,2],[14,1],[6,1],[19,2],[19,1],[20,4],[22,3],[22,1],[25,3],[26,2],[26,0],[27,2],[27,0],[18,1],[18,1],[10,1],[28,1],[28,0]],
|
||||
performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
||||
var $$ = arguments[5], $0 = arguments[5].length;
|
||||
switch (arguments[4]) {
|
||||
@@ -30,50 +30,53 @@ performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
||||
this.$ = {start: $$[$0 - 2 + 2 - 1]};
|
||||
break;
|
||||
case 6:
|
||||
this.$ = {operator: $$[$0 - 1 + 1 - 1]};
|
||||
this.$ = {lex: $$[$0 - 1 + 1 - 1]};
|
||||
break;
|
||||
case 7:
|
||||
this.$ = {operator: $$[$0 - 1 + 1 - 1]};
|
||||
break;
|
||||
case 8:
|
||||
this.$ = [$$[$0 - 2 + 1 - 1]];
|
||||
this.$.push.apply(this.$, $$[$0 - 2 + 2 - 1]);
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
this.$ = "left";
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
this.$ = "right";
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
this.$ = "nonassoc";
|
||||
break;
|
||||
case 11:
|
||||
case 12:
|
||||
this.$ = $$[$0 - 2 + 1 - 1];
|
||||
this.$.push($$[$0 - 2 + 2 - 1]);
|
||||
break;
|
||||
case 12:
|
||||
case 13:
|
||||
this.$ = [$$[$0 - 1 + 1 - 1]];
|
||||
break;
|
||||
case 13:
|
||||
case 14:
|
||||
this.$ = $$[$0 - 1 + 1 - 1];
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
this.$ = $$[$0 - 2 + 1 - 1];
|
||||
this.$[$$[$0 - 2 + 2 - 1][0]] = $$[$0 - 2 + 2 - 1][1];
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
this.$ = {};
|
||||
this.$[$$[$0 - 1 + 1 - 1][0]] = $$[$0 - 1 + 1 - 1][1];
|
||||
break;
|
||||
case 16:
|
||||
case 17:
|
||||
this.$ = [$$[$0 - 4 + 1 - 1], $$[$0 - 4 + 3 - 1]];
|
||||
break;
|
||||
case 17:
|
||||
case 18:
|
||||
this.$ = $$[$0 - 3 + 1 - 1];
|
||||
this.$.push($$[$0 - 3 + 3 - 1]);
|
||||
break;
|
||||
case 18:
|
||||
case 19:
|
||||
this.$ = [$$[$0 - 1 + 1 - 1]];
|
||||
break;
|
||||
case 19:
|
||||
case 20:
|
||||
this.$ = [$$[$0 - 3 + 1 - 1].length ? $$[$0 - 3 + 1 - 1].join(" ") : ""];
|
||||
if ($$[$0 - 3 + 3 - 1]) {
|
||||
this.$.push($$[$0 - 3 + 3 - 1]);
|
||||
@@ -85,24 +88,21 @@ performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
||||
this.$ = this.$[0];
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
case 21:
|
||||
this.$ = $$[$0 - 2 + 1 - 1];
|
||||
this.$.push($$[$0 - 2 + 2 - 1]);
|
||||
break;
|
||||
case 21:
|
||||
case 22:
|
||||
this.$ = [];
|
||||
break;
|
||||
case 22:
|
||||
case 23:
|
||||
this.$ = {prec: $$[$0 - 2 + 2 - 1]};
|
||||
break;
|
||||
case 23:
|
||||
case 24:
|
||||
this.$ = null;
|
||||
break;
|
||||
case 24:
|
||||
this.$ = $$[$0 - 1 + 1 - 1];
|
||||
break;
|
||||
case 25:
|
||||
this.$ = yytext;
|
||||
this.$ = $$[$0 - 1 + 1 - 1];
|
||||
break;
|
||||
case 26:
|
||||
this.$ = yytext;
|
||||
@@ -111,20 +111,40 @@ performAction: function anonymous(yytext, yyleng, yylineno, yy) {
|
||||
this.$ = yytext;
|
||||
break;
|
||||
case 28:
|
||||
this.$ = yytext;
|
||||
break;
|
||||
case 29:
|
||||
this.$ = "";
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
},
|
||||
table: [{"2":1,"3":2,"4":[2,4],"8":[2,4],"13":[2,4],"14":[2,4],"15":[2,4]},{"1":[3]},{"4":[1,3],"7":4,"8":[1,5],"10":6,"11":7,"13":[1,8],"14":[1,9],"15":[1,10]},{"5":11,"17":12,"18":13,"9":14,"29":[1,15]},{"4":[2,3],"8":[2,3],"13":[2,3],"14":[2,3],"15":[2,3]},{"9":16,"29":[1,15]},{"15":[2,6],"14":[2,6],"13":[2,6],"8":[2,6],"4":[2,6]},{"12":17,"16":18,"9":19,"28":[1,20],"29":[1,15]},{"28":[2,8],"29":[2,8]},{"28":[2,9],"29":[2,9]},{"28":[2,10],"29":[2,10]},{"6":[1,21],"4":[1,22]},{"18":23,"9":14,"29":[1,15],"6":[2,13],"4":[2,13]},{"4":[2,15],"6":[2,15],"29":[2,15]},{"19":[1,24]},{"19":[2,26],"4":[2,26],"8":[2,26],"13":[2,26],"14":[2,26],"15":[2,26],"29":[2,26],"28":[2,26],"21":[2,26],"22":[2,26],"30":[2,26],"27":[2,26]},{"15":[2,5],"14":[2,5],"13":[2,5],"8":[2,5],"4":[2,5]},{"16":25,"9":19,"28":[1,20],"29":[1,15],"4":[2,7],"8":[2,7],"13":[2,7],"14":[2,7],"15":[2,7]},{"15":[2,12],"14":[2,12],"13":[2,12],"8":[2,12],"4":[2,12],"29":[2,12],"28":[2,12]},{"28":[2,24],"29":[2,24],"4":[2,24],"8":[2,24],"13":[2,24],"14":[2,24],"15":[2,24],"27":[2,24],"30":[2,24],"22":[2,24],"21":[2,24]},{"28":[2,25],"29":[2,25],"4":[2,25],"8":[2,25],"13":[2,25],"14":[2,25],"15":[2,25],"27":[2,25],"30":[2,25],"22":[2,25],"21":[2,25]},{"1":[2,1]},{"6":[1,26]},{"4":[2,14],"6":[2,14],"29":[2,14]},{"20":27,"23":28,"24":29,"21":[2,21],"22":[2,21],"30":[2,21],"27":[2,21],"29":[2,21],"28":[2,21]},{"15":[2,11],"14":[2,11],"13":[2,11],"8":[2,11],"4":[2,11],"29":[2,11],"28":[2,11]},{"1":[2,2]},{"21":[1,30],"22":[1,31]},{"21":[2,18],"22":[2,18]},{"25":32,"16":33,"27":[1,34],"9":19,"28":[1,20],"29":[1,15],"21":[2,23],"22":[2,23],"30":[2,23]},{"29":[2,16],"6":[2,16],"4":[2,16]},{"23":35,"24":29,"21":[2,21],"22":[2,21],"30":[2,21],"27":[2,21],"29":[2,21],"28":[2,21]},{"26":36,"30":[1,37],"21":[2,28],"22":[2,28]},{"21":[2,20],"22":[2,20],"30":[2,20],"27":[2,20],"29":[2,20],"28":[2,20]},{"16":38,"9":19,"28":[1,20],"29":[1,15]},{"21":[2,17],"22":[2,17]},{"22":[2,19],"21":[2,19]},{"21":[2,27],"22":[2,27]},{"21":[2,22],"22":[2,22],"30":[2,22]}],
|
||||
table: [{"3":1,"4":2,"5":[2,4],"9":[2,4],"11":[2,4],"15":[2,4],"16":[2,4],"17":[2,4]},{"1":[3]},{"5":[1,3],"8":4,"9":[1,5],"11":[1,6],"12":7,"13":8,"15":[1,9],"16":[1,10],"17":[1,11]},{"6":12,"19":13,"20":14,"10":15,"31":[1,16]},{"5":[2,3],"9":[2,3],"11":[2,3],"15":[2,3],"16":[2,3],"17":[2,3]},{"10":17,"31":[1,16]},{"17":[2,6],"16":[2,6],"15":[2,6],"11":[2,6],"9":[2,6],"5":[2,6]},{"17":[2,7],"16":[2,7],"15":[2,7],"11":[2,7],"9":[2,7],"5":[2,7]},{"14":18,"18":19,"10":20,"30":[1,21],"31":[1,16]},{"30":[2,9],"31":[2,9]},{"30":[2,10],"31":[2,10]},{"30":[2,11],"31":[2,11]},{"7":[1,22],"5":[1,23]},{"20":24,"10":15,"31":[1,16],"7":[2,14],"5":[2,14]},{"5":[2,16],"7":[2,16],"31":[2,16]},{"21":[1,25]},{"21":[2,27],"5":[2,27],"9":[2,27],"11":[2,27],"15":[2,27],"16":[2,27],"17":[2,27],"31":[2,27],"30":[2,27],"23":[2,27],"24":[2,27],"32":[2,27],"29":[2,27]},{"17":[2,5],"16":[2,5],"15":[2,5],"11":[2,5],"9":[2,5],"5":[2,5]},{"18":26,"10":20,"30":[1,21],"31":[1,16],"5":[2,8],"9":[2,8],"11":[2,8],"15":[2,8],"16":[2,8],"17":[2,8]},{"17":[2,13],"16":[2,13],"15":[2,13],"11":[2,13],"9":[2,13],"5":[2,13],"31":[2,13],"30":[2,13]},{"30":[2,25],"31":[2,25],"5":[2,25],"9":[2,25],"11":[2,25],"15":[2,25],"16":[2,25],"17":[2,25],"29":[2,25],"32":[2,25],"24":[2,25],"23":[2,25]},{"30":[2,26],"31":[2,26],"5":[2,26],"9":[2,26],"11":[2,26],"15":[2,26],"16":[2,26],"17":[2,26],"29":[2,26],"32":[2,26],"24":[2,26],"23":[2,26]},{"1":[2,1]},{"7":[1,27]},{"5":[2,15],"7":[2,15],"31":[2,15]},{"22":28,"25":29,"26":30,"23":[2,22],"24":[2,22],"32":[2,22],"29":[2,22],"31":[2,22],"30":[2,22]},{"17":[2,12],"16":[2,12],"15":[2,12],"11":[2,12],"9":[2,12],"5":[2,12],"31":[2,12],"30":[2,12]},{"1":[2,2]},{"23":[1,31],"24":[1,32]},{"23":[2,19],"24":[2,19]},{"27":33,"18":34,"29":[1,35],"10":20,"30":[1,21],"31":[1,16],"23":[2,24],"24":[2,24],"32":[2,24]},{"31":[2,17],"7":[2,17],"5":[2,17]},{"25":36,"26":30,"23":[2,22],"24":[2,22],"32":[2,22],"29":[2,22],"31":[2,22],"30":[2,22]},{"28":37,"32":[1,38],"23":[2,29],"24":[2,29]},{"23":[2,21],"24":[2,21],"32":[2,21],"29":[2,21],"31":[2,21],"30":[2,21]},{"18":39,"10":20,"30":[1,21],"31":[1,16]},{"23":[2,18],"24":[2,18]},{"24":[2,20],"23":[2,20]},{"23":[2,28],"24":[2,28]},{"23":[2,23],"24":[2,23],"32":[2,23]}],
|
||||
parseError: function parseError(str, hash) {
|
||||
throw new Error(str);
|
||||
},
|
||||
parse: function parse(input) {
|
||||
var self = this, stack = [0], vstack = [null], table = this.table, yytext = "", yylineno = 0, yyleng = 0, shifts = 0, reductions = 0;
|
||||
var self = this, stack = [0], vstack = [null], table = this.table, yytext = "", yylineno = 0, yyleng = 0, shifts = 0, reductions = 0, recovering = 0, TERROR = 2, EOF = 1;
|
||||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
var parseError = this.yy.parseError = this.yy.parseError || this.parseError;
|
||||
this.yy.lexer = this.lexer;
|
||||
var parseError = this.yy.parseError = typeof this.yy.parseError == "function" ? this.yy.parseError : this.parseError;
|
||||
|
||||
function popStack(n) {
|
||||
stack.length = stack.length - 2 * n;
|
||||
vstack.length = vstack.length - n;
|
||||
}
|
||||
|
||||
|
||||
function checkRecover(st) {
|
||||
for (var p in table[st]) {
|
||||
if (p == TERROR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function lex() {
|
||||
var token;
|
||||
@@ -135,23 +155,49 @@ parse: function parse(input) {
|
||||
return token;
|
||||
}
|
||||
|
||||
var symbol, state, action, a, r, yyval = {}, p, len, ip = 0, newState, expected;
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected, recovered = false;
|
||||
symbol = lex();
|
||||
while (true) {
|
||||
state = stack[stack.length - 1];
|
||||
action = table[state] && table[state][symbol];
|
||||
if (typeof action === "undefined" || !action.length || !action[0]) {
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p != 1) {
|
||||
expected.push("'" + this.terminals_[p] + "'");
|
||||
if (!recovering) {
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'" + this.terminals_[p] + "'");
|
||||
}
|
||||
}
|
||||
if (this.lexer.showPosition) {
|
||||
parseError.call(this, "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", "), {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, expected: expected});
|
||||
} else {
|
||||
parseError.call(this, "Parse error on line " + (yylineno + 1) + ": Unexpected '" + this.terminals_[symbol] + "'", {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, expected: expected});
|
||||
}
|
||||
}
|
||||
if (this.lexer.showPosition) {
|
||||
parseError("Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", "), {text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
|
||||
} else {
|
||||
parseError("Parse error on line " + (yylineno + 1) + ": Unexpected '" + this.terminals_[symbol] + "'", {text: this.lexer.match, token: this.terminals_[symbol], line: this.lexer.yylineno, expected: expected});
|
||||
if (recovering == 3) {
|
||||
if (symbol == EOF) {
|
||||
throw "Parsing halted.";
|
||||
}
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
symbol = lex();
|
||||
}
|
||||
while (true) {
|
||||
if (checkRecover(state)) {
|
||||
break;
|
||||
}
|
||||
if (state == 0) {
|
||||
throw "Parsing halted.";
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length - 1];
|
||||
}
|
||||
preErrorSymbol = symbol;
|
||||
symbol = TERROR;
|
||||
state = stack[stack.length - 1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3;
|
||||
}
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
|
||||
@@ -161,13 +207,20 @@ parse: function parse(input) {
|
||||
case 1:
|
||||
shifts++;
|
||||
stack.push(symbol);
|
||||
++ip;
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
symbol = lex();
|
||||
vstack.push(null);
|
||||
vstack.push(this.lexer.yytext);
|
||||
stack.push(a[1]);
|
||||
if (!preErrorSymbol) {
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
symbol = lex();
|
||||
if (recovering > 0) {
|
||||
recovering--;
|
||||
}
|
||||
} else {
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
reductions++;
|
||||
@@ -305,67 +358,70 @@ lexer.performAction = function anonymous(yy, yy_) {
|
||||
return yy.lexComment(this);
|
||||
break;
|
||||
case 3:
|
||||
return 29;
|
||||
return 31;
|
||||
break;
|
||||
case 4:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 28;
|
||||
return 30;
|
||||
break;
|
||||
case 5:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 28;
|
||||
return 30;
|
||||
break;
|
||||
case 6:
|
||||
return 19;
|
||||
break;
|
||||
case 7:
|
||||
return 21;
|
||||
break;
|
||||
case 7:
|
||||
return 23;
|
||||
break;
|
||||
case 8:
|
||||
return 22;
|
||||
return 24;
|
||||
break;
|
||||
case 9:
|
||||
return 4;
|
||||
return 5;
|
||||
break;
|
||||
case 10:
|
||||
return 27;
|
||||
return 29;
|
||||
break;
|
||||
case 11:
|
||||
return 8;
|
||||
return 9;
|
||||
break;
|
||||
case 12:
|
||||
return 13;
|
||||
break;
|
||||
case 13:
|
||||
return 14;
|
||||
break;
|
||||
case 14:
|
||||
return 15;
|
||||
break;
|
||||
case 13:
|
||||
return 16;
|
||||
break;
|
||||
case 14:
|
||||
return 17;
|
||||
break;
|
||||
case 15:
|
||||
return 11;
|
||||
break;
|
||||
case 16:
|
||||
break;
|
||||
case 17:
|
||||
return yy.lexAction(this);
|
||||
break;
|
||||
case 18:
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 30;
|
||||
return yy.lexAction(this);
|
||||
break;
|
||||
case 19:
|
||||
yy_.yytext = yy_.yytext.substr(2, yy_.yytext.length - 4);
|
||||
return 30;
|
||||
yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2);
|
||||
return 32;
|
||||
break;
|
||||
case 20:
|
||||
yy_.yytext = yy_.yytext.substr(2, yy_.yytext.length - 4);
|
||||
return 32;
|
||||
break;
|
||||
case 21:
|
||||
return 6;
|
||||
break;
|
||||
case 22:
|
||||
return 7;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
};
|
||||
lexer.rules = [/^\s+/, /^\/\/.*/, /^\/\*[^*]*\*/, /^[a-zA-Z][a-zA-Z0-9_-]*/, /^"[^"]+"/, /^'[^']+'/, /^:/, /^;/, /^\|/, /^%%/, /^%prec\b/, /^%start\b/, /^%left\b/, /^%right\b/, /^%nonassoc\b/, /^%[a-zA-Z]+[^\n]*/, /^<[a-zA-Z]*>/, /^\{\{[^}]*\}/, /^\{[^}]*\}/, /^%\{(.|\n)*?%\}/, /^./, /^$/];return lexer;})()
|
||||
lexer.rules = [/^\s+/,/^\/\/.*/,/^\/\*[^*]*\*/,/^[a-zA-Z][a-zA-Z0-9_-]*/,/^"[^"]+"/,/^'[^']+'/,/^:/,/^;/,/^\|/,/^%%/,/^%prec\b/,/^%start\b/,/^%left\b/,/^%right\b/,/^%nonassoc\b/,/^%lex[\w\W]*?\/lex\b/,/^%[a-zA-Z]+[^\n]*/,/^<[a-zA-Z]*>/,/^\{\{[^}]*\}/,/^\{[^}]*\}/,/^%\{(.|\n)*?%\}/,/^./,/^$/];return lexer;})()
|
||||
parser.lexer = lexer;
|
||||
return parser;
|
||||
})();
|
||||
@@ -378,7 +434,7 @@ exports.main = function commonjsMain(args) {
|
||||
throw new Error("Usage: " + args[0] + " FILE");
|
||||
}
|
||||
var source = cwd.join(args[1]).read({charset: "utf-8"});
|
||||
this.parse(source);
|
||||
exports.parser.parse(source);
|
||||
}
|
||||
if (require.main === module) {
|
||||
exports.main(require("system").args);
|
||||
|
||||
182
vendor/jison/lib/jison/util/lex-parser.js
vendored
182
vendor/jison/lib/jison/util/lex-parser.js
vendored
File diff suppressed because one or more lines are too long
110
vendor/jison/src/bnf.jison
vendored
110
vendor/jison/src/bnf.jison
vendored
@@ -1,110 +0,0 @@
|
||||
%%
|
||||
|
||||
spec
|
||||
: declaration_list '%%' grammar EOF
|
||||
{$$ = $1; $$.bnf = $3; return $$;}
|
||||
| declaration_list '%%' grammar '%%' EOF
|
||||
{$$ = $1; $$.bnf = $3; return $$;}
|
||||
;
|
||||
|
||||
declaration_list
|
||||
: declaration_list declaration
|
||||
{$$ = $1; yy.addDeclaration($$, $2);}
|
||||
|
|
||||
{{$$ = {};}}
|
||||
;
|
||||
|
||||
declaration
|
||||
: START id
|
||||
{{$$ = {start: $2};}}
|
||||
| operator
|
||||
{{$$ = {operator: $1};}}
|
||||
;
|
||||
|
||||
operator
|
||||
: associativity token_list
|
||||
{$$ = [$1]; $$.push.apply($$, $2);}
|
||||
;
|
||||
|
||||
associativity
|
||||
: LEFT
|
||||
{$$ = 'left';}
|
||||
| RIGHT
|
||||
{$$ = 'right';}
|
||||
| NONASSOC
|
||||
{$$ = 'nonassoc';}
|
||||
;
|
||||
|
||||
token_list
|
||||
: token_list symbol
|
||||
{$$ = $1; $$.push($2);}
|
||||
| symbol
|
||||
{$$ = [$1];}
|
||||
;
|
||||
|
||||
grammar
|
||||
: production_list
|
||||
{$$ = $1;}
|
||||
;
|
||||
|
||||
production_list
|
||||
: production_list production
|
||||
{$$ = $1; $$[$2[0]] = $2[1];}
|
||||
| production
|
||||
{{$$ = {}; $$[$1[0]] = $1[1];}}
|
||||
;
|
||||
|
||||
production
|
||||
: id ':' handle_list ';'
|
||||
{$$ = [$1, $3];}
|
||||
;
|
||||
|
||||
handle_list
|
||||
: handle_list '|' handle_action
|
||||
{$$ = $1; $$.push($3);}
|
||||
| handle_action
|
||||
{$$ = [$1];}
|
||||
;
|
||||
|
||||
handle_action
|
||||
: handle prec action
|
||||
{$$ = [($1.length ? $1.join(' ') : '')];
|
||||
if($3) $$.push($3);
|
||||
if($2) $$.push($2);
|
||||
if ($$.length === 1) $$ = $$[0];
|
||||
}
|
||||
;
|
||||
|
||||
handle
|
||||
: handle symbol
|
||||
{$$ = $1; $$.push($2)}
|
||||
|
|
||||
{$$ = [];}
|
||||
;
|
||||
|
||||
prec
|
||||
: PREC symbol
|
||||
{{$$ = {prec: $2};}}
|
||||
|
|
||||
{$$ = null;}
|
||||
;
|
||||
|
||||
symbol
|
||||
: id
|
||||
{$$ = $1;}
|
||||
| STRING
|
||||
{$$ = yytext;}
|
||||
;
|
||||
|
||||
id
|
||||
: ID
|
||||
{$$ = yytext;}
|
||||
;
|
||||
|
||||
action
|
||||
: ACTION
|
||||
{$$ = yytext;}
|
||||
|
|
||||
{$$ = '';}
|
||||
;
|
||||
|
||||
27
vendor/jison/src/bnf.jisonlex
vendored
27
vendor/jison/src/bnf.jisonlex
vendored
@@ -1,27 +0,0 @@
|
||||
|
||||
%%
|
||||
\s+ {/* skip whitespace */}
|
||||
"//".* {/* skip comment */}
|
||||
"/*"[^*]*"*" {return yy.lexComment(this);}
|
||||
[a-zA-Z][a-zA-Z0-9_-]* {return 'ID';}
|
||||
'"'[^"]+'"' {yytext = yytext.substr(1, yyleng-2); return 'STRING';}
|
||||
"'"[^']+"'" {yytext = yytext.substr(1, yyleng-2); return 'STRING';}
|
||||
":" {return ':';}
|
||||
";" {return ';';}
|
||||
"|" {return '|';}
|
||||
"%%" {return '%%';}
|
||||
"%prec" {return 'PREC';}
|
||||
"%start" {return 'START';}
|
||||
"%left" {return 'LEFT';}
|
||||
"%right" {return 'RIGHT';}
|
||||
"%nonassoc" {return 'NONASSOC';}
|
||||
"%"[a-zA-Z]+[^\n]* {/* ignore unrecognized decl */}
|
||||
"<"[a-zA-Z]*">" { /* ignore type */}
|
||||
"{{"[^}]*"}" {return yy.lexAction(this);}
|
||||
"{"[^}]*"}" {yytext = yytext.substr(1, yyleng-2); return 'ACTION';}
|
||||
"%{"(.|\n)*?"%}" {yytext = yytext.substr(2, yytext.length-4);return 'ACTION';}
|
||||
. {/* ignore bad characters */}
|
||||
<<EOF>> {return 'EOF';}
|
||||
|
||||
%%
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user