As evidenced in #3804, commit 8ab15d7 broke the CoffeeScript API. The REPL uses
those APIs, but wasn't updated in that commit. Still, that shouldn't have
_broken_ the REPL. The reason it broke is because the added _option_
'referencedVars' wasn't actually _optional;_ if it was omitted code that relies
on it being set broke. This commit defaults that option to an empty array, which
makes things behave exactly like before when the 'referencedVars' option is
omitted.
Supersedes #3805. Here is a comparison of master, #3805 and this commit:
# master
$ bin/coffee
coffee> 1 %% 2
TypeError: Array.prototype.indexOf called on null or undefined
# #3805
$ bin/coffee
coffee> 1 %% 2
1
coffee> (_results = null; i) for i in [1, 2, 3]
TypeError: Cannot call method 'push' of null
# this commit
$ bin/coffee
coffee> 1 %% 2
1
coffee> (_results = null; i) for i in [1, 2, 3]
[ 1, 2, 3 ]
Instead of compiling to `"" + + (+"-");`, `"#{+}-"'` now gives an appropriate
error message:
[stdin]:1:5: error: unexpected end of interpolation
"#{+}-"
^
This is done by _always_ (instead of just sometimes) wrapping the interpolations
in parentheses in the lexer. Unnecessary parentheses won't be output anyway.
I got tired of updating the tests in test/location.coffee (which I had enough of
in #3770), which relies on implementation details (the exact amount of tokens
generated for a given string of code) to do their testing, so I refactored them
to be less fragile.
Since zaach/jison commit 3548861b, `parser.lexer` is never modified anymore (a
copy of it is made, and that copy is modified instead). CoffeeScript itself
modifies `parser.lexer` and then accesses those modifications in the custom
`parser.yy.parseError` function, but that of course does not work anymore. This
commit puts the data that `parser.yy.parseError` needs directly on the `parser`
so that it is not lost.
Supersedes #3603. Fixes#3608 and zaach/jison#243.
Using the static property `Scope.root` for the top-level scope of a file is a
hack, which makes it impossible to have several independent `Scope` instances
at the same time (should we ever need that).
This commit makes every instance have a reference to its root instead.
Any variables generated by CoffeeScript are now made sure to be named to
something not present in the source code being compiled. This way you can no
longer interfere with them, either on purpose or by mistake. (#1500, #1574)
For example, `({a}, _arg) ->` now compiles correctly. (#1574)
As opposed to the somewhat complex implementations discussed in #1500, this
commit takes a very simple approach by saving all used variables names using a
single pass over the token stream. Any generated variables are then made sure
not to exist in that list.
`(@a) -> a` used to be equivalent to `(@a) -> @a`, but now throws a runtime
`ReferenceError` instead (unless `a` exists in an upper scope of course). (#3318)
`(@a) ->` used to compile to `(function(a) { this.a = a; })`. Now it compiles to
`(function(_at_a) { this.a = _at_a; })`. (But you cannot access `_at_a` either,
of course.)
Because of the above, `(@a, a) ->` is now valid; `@a` and `a` are not duplicate
parameters.
Duplicate this-parameters with a reserved word, such as `(@case, @case) ->`,
used to compile but now throws, just like regular duplicate parameters.
Allow the `by c` part in `for [a..b] by c then`.
Continue disallowing a `when d` part, since it makes no sense having a guard
that isn't given access to anything that changes on every iteration.
A regex may not follow a specific set of tokens. These were already known before
in the `NOT_REGEX` and `NOT_SPACED_REGEX` arrays. (However, I've refactored them
to be more correct and to add a few missing tokens). In all other cases (except
after a spaced callable) a slash is the start of a regex, and may now start with
a space or an equals sign. It’s really that simple!
A slash after a spaced callable is the only ambigous case. We cannot know if
that's division or function application with a regex as the argument. The
spacing determines which is which:
Space on both sides:
- `a / b/i` -> `a / b / i`
- `a /= b/i` -> `a /= b / i`
No spaces:
- `a/b/i` -> `a / b / i`
- `a/=b/i` -> `a /= b / i`
Space on the right side:
- `a/ b/i` -> `a / b / i`
- `a/= b/i` -> `a /= b / i`
Space on the left side:
- `a /b/i` -> `a(/b/i)`
- `a /=b/i` -> `a(/=b/i)`
The last case used to compile to `a /= b / i`, but that has been changed to be
consistent with the `/` operator. The last case really looks like a regex, so it
should be parsed as one.
Moreover, you may now also space the `/` and `/=` operators with other
whitespace characters than a space (such as tabs and non-breaking spaces) for
consistency.
Lastly, unclosed regexes are now reported as such, instead of generating some
other confusing error message.
It should perhaps also be noted that apart from escaping (such as `a /\ b/`) you
may now also use parentheses to disambiguate division and regex: `a (/ b/)`. See
https://github.com/jashkenas/coffeescript/issues/3182#issuecomment-26688427.
Before commit c056c93e `Op::isComplex()` used to return true always. As far as I
understand, that commit attempts to exclude code such as `+1` and `-2` from
being marked as complex (and thus getting cached into `_ref` variables
sometimes). CoffeeScript is supposed to generate readable output so that choice
is understandable. However, it also excludes code such as `+a` (by mistake I
believe), which can cause `a` to be coerced multiple times. This commit fixes
this by only excluding unary + and - ops followed by a number.
It is possible to match only valid JavaScript identifiers with a really long
regex (like coco and CoffeeScriptRedux does), but CoffeeScript uses a much
simpler one, which allows a bit too much.
Quoting jashkenas/coffeescript#1718 #issuecomment-2152464 @jashkenas:
> But it still seems very much across the "worth it" line. You'll get the
> SyntaxError as soon as it hits JS, and performance aside -- even the increase
> in filesize for our browser coffee-script.js lib seems too much, considering
> this is something no one ever does, apart from experimentation.
In short, CoffeeScript treats any non-ASCII character as part of an identifier.
However, unicode spaces should be excluded since having blank characters as part
of a _word_ is very confusing. This commit does so, while still keeping the
regex really simple.
Previously such errors pointed at the end of the input, which wasn't very
helpful. This is also consistent with unclosed strings, where the errors point
at the opening quote.
Note that this includes unclosed #{ (interpolations).
- Fix#3394: Unclosed single-quoted strings (both regular ones and heredocs)
used to pass through the lexer, causing a parsing error later, while
double-quoted strings caused an error already in the lexing phase. Now both
single and double-quoted unclosed strings error out in the lexer (which is the
more logical option) with consistent error messages. This also fixes the last
comment by @satyr in #3301.
- Similar to the above, unclosed heregexes also used to pass through the lexer
and not error until in the parsing phase, which resulted in confusing error
messages. This has been fixed, too.
- Fix#3348, by adding passing tests.
- Fix#3529: If a string starts with an interpolation, an empty string is no
longer emitted before the interpolation (unless it is needed to coerce the
interpolation into a string).
- Block comments cannot contain `*/`. Now the error message also shows exactly
where the offending `*/`. This improvement might seem unrelated, but I had to
touch that code anyway to refactor string and regex related code, and the
change was very trivial. Moreover, it's consistent with the next two points.
- Regexes cannot start with `*`. Now the error message also shows exactly where
the offending `*` is. (It might actually not be exatly at the start in
heregexes.) It is a very minor improvement, but it was trivial to add.
- Octal escapes in strings are forbidden in CoffeeScript (just like in
JavaScript strict mode). However, this used to be the case only for regular
strings. Now they are also forbidden in heredocs. Moreover, the errors now
point at the offending octal escape.
- Invalid regex flags are no longer allowed. This includes repeated modifiers
and unknown ones. Moreover, invalid modifiers do not stop a heregex from
being matched, which results in better error messages.
- Fix#3621: `///a#{1}///` compiles to `RegExp("a" + 1)`. So does
`RegExp("a#{1}")`. Still, those two code snippets used to generate different
tokens, which is a bit weird, but more importantly causes problems for
coffeelint (see clutchski/coffeelint#340). This required lots of tests in
test/location.coffee to be updated. Note that some updates to those tests are
unrelated to this point; some have been updated to be more consistent (I
discovered this because the refactored code happened to be seemingly more
correct).
- Regular regex literals used to erraneously allow newlines to be escaped,
causing invalid JavaScript output. This has been fixed.
- Heregexes may now be completely empty (`//////`), instead of erroring out with
a confusing message.
- Fix#2388: Heredocs and heregexes used to be lexed simply, which meant that
you couldn't nest a heredoc within a heredoc (double-quoted, that is) or a
heregex inside a heregex.
- Fix#2321: If you used division inside interpolation and then a slash later in
the string containing that interpolation, the division slash and the latter
slash was erraneously matched as a regex. This has been fixed.
- Indentation inside interpolations in heredocs no longer affect how much
indentation is removed from each line of the heredoc (which is more
intuitive).
- Whitespace is now correctly trimmed from the start and end of strings in a few
edge cases.
- Last but not least, the lexing of interpolated strings now seems to be more
efficient. For a regular double-quoted string, we used to use a custom
function to find the end of it (taking interpolations and interpolations
within interpolations etc. into account). Then we used to re-find the
interpolations and recursively lex their contents. In effect, the same string
was processed twice, or even more in the case of deeper nesting of
interpolations. Now the same string is processed just once.
- Code duplication between regular strings, heredocs, regular regexes and
heregexes has been reduced.
- The above two points should result in more easily read code, too.
Currently CoffeeScript reports a success even if it failed to write a
compiled file to disk. This behavior confuses automated tools such as
test runners which may return false positives if a test failed to
compile because of a file lock.
1. It just seems like a bad practice to encourage people to run npm with `sudo`
2. The doc wasn’t consistent with itself — down below in the full “Installation” section the same command did *not* include `sudo`
Node changed their repl so that it inherits from readline.Interface.
This means that `prompt` is now the rli function and not the original
prompt string. This may be a little hacky, but I figure it would give
someone a start if they want to do a better fix.
The commit that changed this in Node is joyent/node@3ae0b17c76
This bug was mentioned in Issue #3395.
This is done by adding a root level wrapper script for
lib/coffee-script/repl, similar to how the register script is wrapped.
This allows user programs to embed a CoffeeScript REPL without digging
into CoffeeScript's internals.
Per https://www.npmjs.org/doc/json.html#preferGlobal
> If your package is primarily a command-line application that should be installed globally, then set this value to true to provide a warning if it is installed locally.
>
> It doesn't actually prevent users from installing it locally, but it does help prevent some confusion if it doesn't work as expected.
- Simplify the command to install latest master.
- Promote using `--save` when installing locally, since it automatically
locks the minor version, protecting users from accidentally installing
breaking updates.
In V8, the `stack` property of errors contains a prelude and then the
stack trace. The contents of the prelude depends on whether the error
has a message or not.
If the error has _not_ got a message, the prelude contains the name of the
error and a newline.
If the error _has_ got a message, the prelude contains the name of the
error, a colon, a space, the message and a newline.
In other words, the prelude consists of `error.toString() + "\n"`
Before, coffee-script’s patched stack traces worked exactly like that,
except that it _always_ added a colon and a space after the name of the
error.
This fix is important because it allows for easy and consistent
consumption of the stack trace only:
`stack = error.stack[error.toString().length..]`
This was added in f4a7cca075 to fix#1038
for CoffeeScript 1.0.1. `.isUndefined` was removed in
caf3da2f66 but this code was never
updated. That actually caused the behavior of this code to change
(trailing `undefined` and `return undefined` statements no longer got
optimized away) when CoffeeScript 1.3.2 was released, but the new
behavior was deemed correct in
https://github.com/jashkenas/coffee-script/issues/1038#issuecomment-14427560.
This documents current behavior. When #1038 was fixed, we also optimized
away trailing "undefined" and "return undefined", but that is no longer
the case.
The commas separating these three keywords are not code themselves – not what the user would write – so they should be outside of the `<tt>` tags.
Edits the table in the section [Operators and Aliases](http://coffeescript.org/#operators).
* Move all source path filtering to `compilePath`
* Restrict modification of `sources` to
* `compilePath` for adding
* `removeSource` for removing
* Don't add unfiltered paths to `sources` (and remove them later on)
* Use absolute paths for source files and target paths
* Memorize and explicitly check for watched directories
* Make path comparison and construction more precise and clear
* Remove now unnecessary check for special relative paths
* Break up `Closure` and merge `Closure.wrap` into `Base.compileClosure`
* Construct class closure directly in `Class.compileNode`
* Reuse `isLiteralArguments` in `Range.compileArray`
* Move all helpers to bottom of file
* Add test for #3063
* Resolves#3059: Don't remove escaped whitespace.
* Fixes#2238: Prevent escaping slashes that are already escaped.
* Fix detection of end of heregex with escaped slashes.
Add a new cli option: -g --polling [SPAN]
If state polling mode is enabled, use it.
Else use the native api.
This is useful while watching remote directory.
Such as the `fs.watch` won't catch the SMB server's file change event.
Make the REPL *CLI* use the global context so as to (a) be consistent
with the `node` REPL CLI and, therefore, (b) make packages that modify
native prototypes (such as 'colors' and 'sugar') work as expected.
Note that, by contrast, programmatic use (`require 'repl'`) will
continue to default to a NON-global context - again, consistent with
node's behavior.
Make the REPL *CLI* use the global context so as to (a) be consistent
with the `node` REPL CLI and, therefore, (b) make packages that modify
native prototypes (such as 'colors' and 'sugar') work as expected.
Note that, by contrast, programmatic use (`require 'repl'`) will
continue to default to a NON-global context - again, consistent with
node's behavior.
Note that, at least for now, CoffeeScript's own REPL *CLI* still uses a
non-global context, rendering modules such as `color`, which attempt to
modify the prototypes of JavaScript primitives, ineffective. By
contrast, node's own CLI does use the global context.
(My apologies: In the previous commit I accidentally made `useGlobal:
yes` the default for _programmatic_ use also, but the intent was to
only do it for the stand-alone *CLI*.)
Make the REPL *CLI* use the global context so as to (a) be consistent
with the `node` REPL CLI and, therefore, (b) make packages that modify
native prototypes (such as 'colors' and 'sugar') work as expected.
Note that, by contrast, programmatic use (`require 'repl'`) will
continue to default to a NON-global context - again, consistent with
node's behavior.
This will make packages that modify prototypes - e.g. 'colors', 'sugar'
- work as expected.
To verify that the `node` REPL uses the global context, execute `global
=== module.exports.repl.context`.
Note: Tests pass, except `cluster.coffee`, which, however, failed even
before these modifications.
This solves two potential problems when it comes to forking:
1) Forking will now work correctly even when `coffee` is not installed
globally.
2) Forking when using a locally installed version of `coffee` will fork
using that version, and not fallback to a globally installed version.
Fixes#2957
This makes the "stack" property more useful when it's shown on other Node.js applications that compile CoffeeScript (e.g. testing libraries) and should fix#3023. A minimal example:
$ node -e 'require("coffee-script").compile("class class")'
/usr/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:41
throw err;
^
[stdin]:1:7: error: unexpected CLASS
class class
^^^^^
Instead of throwing the syntax errors with their source file location and needing to then catch them and call a `prettyErrorMessage` function in order to get the formatted error message, now syntax errors know how to pretty-print themselves (their `toString` method gets overridden).
An intermediate `catch` & re-`throw` is needed at the level of `CoffeeScript.compile` and friends. But the benefit of this approach is that now libraries that use the `CoffeeScript` object directly don't need to bother catching the possible compilation errors and calling a special function in order to get the nice error messages; they can just print the error itself (or let it bubble up) and the error will know how to pretty-print itself.
* Supplement missing block before `ELSE` token only for multi-line `if`.
* Don't prematurely remove `TERMINATOR` before `ELSE` (so we can differentiate single- and multi-line forms).
* Cleanup: Remove `WHEN` from `EXPRESSION_CLOSE`. (Only `LEADING_WHEN` tokens are preceded by a `TERMINATOR`.)
* Cleanup: Remove really old, inapplicable text from comment.
In #3031, an extensions variable was introduced with file-level scope
that defined the filetypes that CoffeeScript can compile. However, the
Module::load patching calls findExtension() which uses a local variable
called "extensions", which was overriding the outer level one and
causing getSourceMap() to fail.
Example: if compilation invoked like this: 'coffee -o ../lib/ -cw ./', then
Source file: ./OutputFolder/file.coffee, compiled output: ./../lib/tputFolder/
The code only expected '.' to mark the local folder. However, './' is equally valid.
The history file was set to close on process exit, when it
should close on REPL exit. Listening to the process exit
event causes a warning when more than 10 CoffeeScript REPL
instances are opened in the same program, which happens in
the test.
* Expect a blank line as delimiter between text and code (#2821).
* Don't change indentation of code. It is not necessary and leads to
erroneous locationData. (#2835)
* Don't modify blank lines and reverse the change in the lexer.
* Don't ignore indentation with mixed whitespace.
remove unnecessary parens and else statement in repl
we do this by convention of the main coffee source
fix: exit should be process.exit
compiled and build full
Before:
coffee> foo = (bar, baz, bar, qux) ->
repl:1:7: error: multiple parameters named 'bar'
foo = (bar, baz, bar, qux) ->
^^^^^^^^^^^^^^^^^^^^^^^
Now:
coffee> foo = (bar, baz, bar, qux) ->
repl:1:18: error: multiple parameters named 'bar'
foo = (bar, baz, bar, qux) ->
^^^
Also works with destructuring parameters and what have you.
Nothing really fancy here; mostly preserves the old format. Maybe if we had a more full-fledged test editor we could show the errors in-line =D
Also, i couldn't get the `rake doc` task running properly, so i mostly test this editing the index.html directly (ups!).
These are the modifications I had to do in order to get source maps working
in 27.0.1425.2 (Official Build 185250) canary. I haven't tested other
browsers.
I first looked at the V3 spec and a few examples, and I saw that the
`source` key of the source map should be called `sources`.
After doing the `source` to `sources` change, the coffee source and for
some odd reason the javascript file would not show up in the browser
dev tools (it was being fetched but not evaluated).
To fix this, I had to add the coffee source to the `sources` list in the
source map file.
Move filename processing to a `parseFileName` function in
helpers.coffee.
Map `.coffee.md` as a Literate CoffeeScript extension.
Also, make .litcoffee and .coffee.md files executable without their file
extension - eg. `coffee test` would work for a file called
`test.litcoffee`.
Since the move to the nodeREPL package, input lines to be evaluated are
now wrapped in parentheses; that is:
'foo'
would become:
('foo'
)
The old way of detecting empty lines was to see if the input string was
either totally empty, or whitespace-only. The addition of these
parentheses breaks that.
In order to fix this, we simply tweak the regex a little to ignore these
added parentheses if they're present. As an added bonus, the regex
should match empty inputs even if they aren't.
This also makes the "empty command evaluates to undefined" test pass,
for the right reasons (i.e. not because of the broken error behavior
from before).
Compatibility is kept for path.exists. Versions of node that have
made the change will use fs.exists, while older versions will fall
back to path.exists. The same goes for path.existsSync.
The readline interface of node has changed in [aad12d0][] and because of
that the autocompletion and key movement didn't work anymore. This
commit fixes this by checking whether stdin is in raw mode (i.e. invoked
as a script) or not (as a repl).
[aad12d0]: https://github.com/joyent/node/commit/aad12d0
8bc6001d27 removed autocompletions of
non-enumerable own-properties in trying to add enumerable prototype
properties to the autocompletions. This commit adds them back and unions
them with the enumerable prototype properties.
case to show it's required.
What's going on: inside of Coffee-generated closures, calling `super()`
is implicitly making use of `this` (or explicitly doing so if you look
at the output code), so we have to pass `this` through closures as if
`@` is being accessed within the closure. So, just add one more
condition to the list in `Closure::literalThis`
Currently, the only mention of heregexes' support for interpolation is
in the change log. This feature is useful enough to warrant a mention in
the heregex section itself.
I also felt that the heregex section was a bit less clear than it could
be, so I slightly reworded it.
Make REPL continuation work better. Check for trailing "\" fails when
run function is called with buffer terminated by newline. Chomp'ing
buffer to remove newline fixes this issue.
The ultraviolet gem doesn't work with Ruby 1.9, instead
we need to use the updated 'spox' versions of ultraviolet
and plist:
spox-ultraviolet, spox-plist
This new rake task: install_coffeescript_syntax loads
either the original gems if running Ruby < 1.9 or the
'spox' versions if running on Ruby >= 1.9.
Load CoffeeScript.tmLanguage directly from the github repo
for the TextMate bundle.
Parse and write the yaml-format syntax file directly
into the correct location in the ultraviolet gem.
This is only slightly problematic for the most pathological of cases
where a prelude is followed by a set of statements, none of which
generate top-level variables or attempt to return. In these cases, the
non-prelude statements will be indented. See related discussion at
e4b3e838e2.
This pleasently surprised but also confused me when it worked. Now it's
documented. No example (yet), alas, but better than nothing.
Originally added in/around 07e66dd2.
This confused me every time I Ctrl+F'ed the home page for "index" and only got
this cryptic statement:
"Comprehensions replace (and compile into) for loops, with optional guard clauses
and the value of the current array index."
Now I can see how the index is used in the code.
While recursively traversing a source directory, if a directory was encountered containing either no .coffee files (ex. an .svn metadata directory) or where the last file processed in that directory was not a .coffee file, compileJoin() might never be called.
This issue was originally introduced by a (well-needed) optimization in commit dc272a680b.
In join mode, anytime the 'unprocessed' count is decremented, the remaining file count should be evaluated to determine if it is time to run compileJoin(). Previously, compileJoin() would only ever be called in one of the four possible terminating branches of this recursive asynchronous operation.
CoffeeScript.eval. Instead of writing about all the changes and why I
made those decisions, I'll just answer any questions in the commit
comments, so add a commit comment if you want to question anything.
Thanks to @TrevorBurnham and @satyr for their help/contributions. Also,
closes#1487. And still no REPL tests...
CoffeeScript.eval. Instead of writing about all the changes and why I
made those decisions, I'll just answer any questions in the commit
comments, so add a commit comment if you want to question anything.
Thanks to @TrevorBurnham and @satyr for their help/contributions. Also,
closes#1487. And still no REPL tests...
Here's how the algorithm in balancedString() was modified. When we
encounter a slash in an interpolation, we:
* try to find a heregex right after it; if found---skip it. Three
slashes always terminate a heregex, no matter if there is an open
"#{" before them or not, so we don't have to bother about
sub-interpolations inside the heregex.
* try to find a regex right after it; if found---skip it. Simple
regexen can't contain interpolations.
* otherwise, assume that the slash means division and carry on.
x = 10
([x]) -> # used to not declare var x
this is one fix, the other way to fix
it is to remove the entire if ... olen is 1 ....
block... not sure if that's a good idea or not.
*why* `require` and only `require` was affected. All other globals that
I tried were unaffected: `console`, `parseInt`, `process`, `global`,
`Array`, `Object`, `Buffer`, `setTimeout`, ...
"[v] = a ? b" must compile to
v = (typeof a != "undefined" && a !== null ? a : b)[0];
and not to:
v = typeof a != "undefined" && a !== null ? a : b[0];
Check the readline.createInterface for arity. If it is 3,
assume the newer interface requiring separate stdin and stdout.
Otherwise, use the older calling style.
This change allows files to be `--require`d before entering the REPL. It's also
an opimization, since files are `--require`d only once, rather than being
required again every time a file is compiled.
A secondary change is that `module.filename` is temporarily modified. This is
somewhat less aesthetically appealing than the old approach of using
fs.realpathSync, but it allows you to run `coffee -r ./foo` rather than having
to write `coffee -r ./foo.coffee`, since Node does not accept absolute paths
without a file extension.
See the tests added to test_comprehensions.coffee. Previously, after
`for i in [1..3]`, i was 4. Also, index variables were never set to
any value in comprehensions containing both a closure and a break or
return.
Allows `path.join` to do some processing on the base path
that was also happening on the full path.
Fixes: `coffee -o ./ ./`
Still broken: `coffee -o . .`
coffee -e -r ./snarl 'Hello!'
Contents of 'snarl.coffee' in the working directory:
http = require 'http'
CoffeeScript.on 'exception', (err) ->
client = http.createClient 9889, 'localhost'
request = client.request 'GET', '/?d={"action":1,"applicationName":"CoffeeScript","title":' + JSON.stringify(err.message) + ',"description":' + JSON.stringify(err.stack) + ',"priority":3}'
request.end()
err.handled = yes
To examine arguments available for each event (for debugging and getting started), use `puts JSON.stringify arguments`.
See http://nodejs.org/api.html#modules-309 and NODE_PATH for more details on how -r looks for files.
* Before you open a ticket or send a pull request, [search](https://github.com/jashkenas/coffeescript/issues) for previous discussions about the same feature or issue. Add to the earlier ticket if you find one.
* Before sending a pull request for a feature, be sure to have [tests](https://github.com/jashkenas/coffeescript/tree/master/test).
* Use the same coding style as the rest of the [codebase](https://github.com/jashkenas/coffeescript/tree/master/src). If you're just getting started with CoffeeScript, there's a nice [style guide](https://github.com/polarmobile/coffeescript-style-guide).
* In your pull request, do not add documentation to `index.html` or re-build the minified `coffee-script.js` file. We'll do those things before cutting a new release.
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>
<p>Running <code>cake</code> with no arguments will print out a list of all the tasks in the
current directory's Cakefile.</p></td><tdclass="code"><divclass="highlight"><pre></pre></div></td></tr><trid="section-2"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-2">#</a></div><p>External dependencies.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">fs: </span><spanclass="nx">require</span><spanclass="s1">'fs'</span>
<spanclass="nv">CoffeeScript: </span><spanclass="nx">require</span><spanclass="s1">'./coffee-script'</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>Keep track of the list of defined tasks, the accepted options, and so on.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">tasks: </span><spanclass="p">{}</span>
<spanclass="nv">oparse: </span><spanclass="kc">null</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>Mixin the top-level Cake functions for Cakefiles to use directly.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nx">helpers</span><spanclass="p">.</span><spanclass="nx">extend</span><spanclass="nx">global</span><spanclass="p">,</span><spanclass="p">{</span></pre></div></td></tr><trid="section-5"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-5">#</a></div><p>Define a Cake task with a short name, an optional sentence description,
and the function to run as the action itself.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">task: </span><spanclass="p">(</span><spanclass="nx">name</span><spanclass="p">,</span><spanclass="nx">description</span><spanclass="p">,</span><spanclass="nx">action</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">tasks</span><spanclass="p">[</span><spanclass="nx">name</span><spanclass="p">]</span><spanclass="o">:</span><spanclass="p">{</span><spanclass="nx">name</span><spanclass="p">,</span><spanclass="nx">description</span><spanclass="p">,</span><spanclass="nx">action</span><spanclass="p">}</span></pre></div></td></tr><trid="section-6"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-6">#</a></div><p>Define an option that the Cakefile accepts. The parsed options hash,
<p>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.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">option: </span><spanclass="p">(</span><spanclass="nx">letter</span><spanclass="p">,</span><spanclass="nx">flag</span><spanclass="p">,</span><spanclass="nx">description</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">switches</span><spanclass="p">.</span><spanclass="nx">push</span><spanclass="p">[</span><spanclass="nx">letter</span><spanclass="p">,</span><spanclass="nx">flag</span><spanclass="p">,</span><spanclass="nx">description</span><spanclass="p">]</span></pre></div></td></tr><trid="section-7"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-7">#</a></div><p>Invoke another task in the current Cakefile.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">invoke: </span><spanclass="p">(</span><spanclass="nx">name</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="p">}</span></pre></div></td></tr><trid="section-8"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-8">#</a></div><p>Run <code>cake</code>. 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.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.run: </span><spanclass="o">-></span>
<spanclass="k">throw</span><spanclass="k">new</span><spanclass="nb">Error</span><spanclass="p">(</span><spanclass="s2">"Cakefile not found in ${process.cwd()}"</span><spanclass="p">)</span><spanclass="nx">unless</span><spanclass="nx">exists</span>
<spanclass="nx">invoke</span><spanclass="nx">arg</span><spanclass="k">for</span><spanclass="nx">arg</span><spanclass="k">in</span><spanclass="nx">options</span><spanclass="p">.</span><spanclass="nx">arguments</span></pre></div></td></tr><trid="section-9"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-9">#</a></div><p>Display the list of Cake tasks in a format similar to <code>rake -T</code></p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">printTasks: </span><spanclass="o">-></span>
<spanclass="nx">puts</span><spanclass="nx">oparse</span><spanclass="p">.</span><spanclass="nx">help</span><spanclass="p">()</span><spanclass="k">if</span><spanclass="nx">switches</span><spanclass="p">.</span><spanclass="nx">length</span></pre></div></td></tr><trid="section-10"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-10">#</a></div><p>Print an error and exit when attempting to all an undefined task.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">missingTask: </span><spanclass="p">(</span><spanclass="nx">task</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">puts</span><spanclass="s2">"No such task: \"$task\""</span>
<spanclass="hljs-built_in">console</span>.log <spanclass="hljs-string">"<spanclass="hljs-subst">#{cakefilePath}</span> defines the following tasks:\n"</span>
<spanclass="hljs-keyword">return</span> cakefileDirectory parent <spanclass="hljs-keyword">unless</span> parent <spanclass="hljs-keyword">is</span> dir
<spanclass="hljs-keyword">throw</span><spanclass="hljs-keyword">new</span> Error <spanclass="hljs-string">"Cakefile not found in <spanclass="hljs-subst">#{process.cwd()}</span>"</span></pre></div></div>
<!DOCTYPE html><html><head><title>coffee-script.coffee</title><metahttp-equiv="content-type"content="text/html; charset=UTF-8"><linkrel="stylesheet"media="all"href="docco.css"/></head><body><divid="container"><divid="background"></div><divid="jump_to"> Jump To …<divid="jump_wrapper"><divid="jump_page"><aclass="source"href="cake.html"> cake.coffee </a><aclass="source"href="coffee-script.html"> coffee-script.coffee </a><aclass="source"href="command.html"> command.coffee </a><aclass="source"href="grammar.html"> grammar.coffee </a><aclass="source"href="helpers.html"> helpers.coffee </a><aclass="source"href="index.html"> index.coffee </a><aclass="source"href="lexer.html"> lexer.coffee </a><aclass="source"href="nodes.html"> nodes.coffee </a><aclass="source"href="optparse.html"> optparse.coffee </a><aclass="source"href="repl.html"> repl.coffee </a><aclass="source"href="rewriter.html"> rewriter.coffee </a><aclass="source"href="scope.html"> scope.coffee </a></div></div></div><tablecellpadding="0"cellspacing="0"><thead><tr><thclass="docs"><h1> coffee-script.coffee </h1></th><thclass="code"></th></tr></thead><tbody><trid="section-1"><tdclass="docs"><divclass="octowrap"><aclass="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>
<!DOCTYPE html>
<p>If included on a webpage, it will automatically sniff out, compile, and
execute all scripts present in <code>text/coffeescript</code> tags.</p></td><tdclass="code"><divclass="highlight"><pre></pre></div></td></tr><trid="section-2"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-2">#</a></div><p>Set up dependencies correctly for both the server and the browser.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="k">if</span><spanclass="nx">process</span><spanclass="o">?</span>
<spanclass="nv">helpers: </span><spanclass="k">this</span><spanclass="p">.</span><spanclass="nx">helpers</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>The current CoffeeScript version number.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.VERSION: </span><spanclass="s1">'0.7.0'</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>Instantiate a Lexer for our use here.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">lexer: </span><spanclass="k">new</span><spanclass="nx">Lexer</span><spanclass="p">()</span></pre></div></td></tr><trid="section-5"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-5">#</a></div><p>Compile a string of CoffeeScript code to JavaScript, using the Coffee/Jison
<spanclass="k">throw</span><spanclass="nx">err</span></pre></div></td></tr><trid="section-6"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-6">#</a></div><p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.tokens: </span><spanclass="p">(</span><spanclass="nx">code</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">lexer</span><spanclass="p">.</span><spanclass="nx">tokenize</span><spanclass="nx">code</span></pre></div></td></tr><trid="section-7"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-7">#</a></div><p>Tokenize and parse a string of CoffeeScript code, and return the AST. You can
then compile it by calling <code>.compile()</code> on the root, or traverse it by using
<code>.traverse()</code> with a callback.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.nodes: </span><spanclass="p">(</span><spanclass="nx">code</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">parser</span><spanclass="p">.</span><spanclass="nx">parse</span><spanclass="nx">lexer</span><spanclass="p">.</span><spanclass="nx">tokenize</span><spanclass="nx">code</span></pre></div></td></tr><trid="section-8"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-8">#</a></div><p>Compile and execute a string of CoffeeScript (on the server), correctly
setting <code>__filename</code>, <code>__dirname</code>, and relative <code>require()</code>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.run: </span><spanclass="p">((</span><spanclass="nx">code</span><spanclass="p">,</span><spanclass="nx">options</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="p">)</span></pre></div></td></tr><trid="section-9"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-9">#</a></div><p>The real Lexer produces a generic stream of tokens. This object provides a
_require[r] = <spanclass="hljs-built_in">require</span>[r] <spanclass="hljs-keyword">for</span> r <spanclass="hljs-keyword">in</span> Object.getOwnPropertyNames <spanclass="hljs-built_in">require</span><spanclass="hljs-keyword">when</span> r <spanclass="hljs-keyword">isnt</span><spanclass="hljs-string">'paths'</span></pre></div></div>
</li>
<liid="section-18">
<divclass="annotation">
<divclass="pilwrap ">
<aclass="pilcrow"href="#section-18">¶</a>
</div>
<p>use the same hack node currently uses for their own REPL</p>
<spanclass="p">}</span></pre></div></td></tr><trid="section-10"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-10">#</a></div><p>Activate CoffeeScript in the browser by having it compile and evaluate
all script tags with a content-type of <code>text/coffeescript</code>. This happens
on page load. Unfortunately, the text contents of remote scripts cannot be
accessed from the browser, so only inline script tags will work.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="k">if</span><spanclass="nb">document</span><spanclass="o">?</span><spanclass="o">and</span><spanclass="nb">document</span><spanclass="p">.</span><spanclass="nx">getElementsByTagName</span>
<p>Based on <ahref="http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js">http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js</a>
<spanclass="p">{</span><spanclass="nx">spawn</span><spanclass="p">,</span><spanclass="nx">exec</span><spanclass="p">}</span><spanclass="o">:</span><spanclass="nx">require</span><spanclass="p">(</span><spanclass="s1">'child_process'</span><spanclass="p">)</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>The help banner that is printed when <code>coffee</code> is called without arguments.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">BANNER: </span><spanclass="s1">'''</span>
<spanclass="s1"> coffee compiles CoffeeScript source files into JavaScript.</span>
<spanclass="s1">'''</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>The list of all the valid option flags that <code>coffee</code> knows how to handle.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">SWITCHES: </span><spanclass="p">[</span>
<spanclass="p">[</span><spanclass="s1">'-c'</span><spanclass="p">,</span><spanclass="s1">'--compile'</span><spanclass="p">,</span><spanclass="s1">'compile to JavaScript and save as .js files'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-i'</span><spanclass="p">,</span><spanclass="s1">'--interactive'</span><spanclass="p">,</span><spanclass="s1">'run an interactive CoffeeScript REPL'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-o'</span><spanclass="p">,</span><spanclass="s1">'--output [DIR]'</span><spanclass="p">,</span><spanclass="s1">'set the directory for compiled JavaScript'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-w'</span><spanclass="p">,</span><spanclass="s1">'--watch'</span><spanclass="p">,</span><spanclass="s1">'watch scripts for changes, and recompile'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-p'</span><spanclass="p">,</span><spanclass="s1">'--print'</span><spanclass="p">,</span><spanclass="s1">'print the compiled JavaScript to stdout'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-l'</span><spanclass="p">,</span><spanclass="s1">'--lint'</span><spanclass="p">,</span><spanclass="s1">'pipe the compiled JavaScript through JSLint'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-s'</span><spanclass="p">,</span><spanclass="s1">'--stdio'</span><spanclass="p">,</span><spanclass="s1">'listen for and compile scripts over stdio'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-e'</span><spanclass="p">,</span><spanclass="s1">'--eval'</span><spanclass="p">,</span><spanclass="s1">'compile a string from the command line'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'--no-wrap'</span><spanclass="p">,</span><spanclass="s1">'compile without the top-level function wrapper'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-t'</span><spanclass="p">,</span><spanclass="s1">'--tokens'</span><spanclass="p">,</span><spanclass="s1">'print the tokens that the lexer produces'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-n'</span><spanclass="p">,</span><spanclass="s1">'--nodes'</span><spanclass="p">,</span><spanclass="s1">'print the parse tree that Jison produces'</span><spanclass="p">]</span>
<spanclass="p">[</span><spanclass="s1">'-h'</span><spanclass="p">,</span><spanclass="s1">'--help'</span><spanclass="p">,</span><spanclass="s1">'display this help message'</span><spanclass="p">]</span>
<spanclass="p">]</span></pre></div></td></tr><trid="section-5"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-5">#</a></div><p>Top-level objects shared by all the functions.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">options: </span><spanclass="p">{}</span>
<spanclass="nv">optionParser: </span><spanclass="kc">null</span></pre></div></td></tr><trid="section-6"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-6">#</a></div><p>Run <code>coffee</code> by parsing passed options and determining what action to take.
[<spanclass="hljs-string">'-b'</span>, <spanclass="hljs-string">'--bare'</span>, <spanclass="hljs-string">'compile without a top-level function wrapper'</span>]
[<spanclass="hljs-string">'-c'</span>, <spanclass="hljs-string">'--compile'</span>, <spanclass="hljs-string">'compile to JavaScript and save as .js files'</span>]
[<spanclass="hljs-string">'-e'</span>, <spanclass="hljs-string">'--eval'</span>, <spanclass="hljs-string">'pass a string from the command line as input'</span>]
[<spanclass="hljs-string">'-h'</span>, <spanclass="hljs-string">'--help'</span>, <spanclass="hljs-string">'display this help message'</span>]
[<spanclass="hljs-string">'-i'</span>, <spanclass="hljs-string">'--interactive'</span>, <spanclass="hljs-string">'run an interactive CoffeeScript REPL'</span>]
[<spanclass="hljs-string">'-j'</span>, <spanclass="hljs-string">'--join [FILE]'</span>, <spanclass="hljs-string">'concatenate the source CoffeeScript before compiling'</span>]
[<spanclass="hljs-string">'-m'</span>, <spanclass="hljs-string">'--map'</span>, <spanclass="hljs-string">'generate source map and save as .js.map files'</span>]
[<spanclass="hljs-string">'-n'</span>, <spanclass="hljs-string">'--nodes'</span>, <spanclass="hljs-string">'print out the parse tree that the parser produces'</span>]
[ <spanclass="hljs-string">'--nodejs [ARGS]'</span>, <spanclass="hljs-string">'pass options directly to the "node" binary'</span>]
[ <spanclass="hljs-string">'--no-header'</span>, <spanclass="hljs-string">'suppress the "Generated by" header'</span>]
[<spanclass="hljs-string">'-o'</span>, <spanclass="hljs-string">'--output [DIR]'</span>, <spanclass="hljs-string">'set the output directory for compiled JavaScript'</span>]
[<spanclass="hljs-string">'-p'</span>, <spanclass="hljs-string">'--print'</span>, <spanclass="hljs-string">'print out the compiled JavaScript'</span>]
[<spanclass="hljs-string">'-s'</span>, <spanclass="hljs-string">'--stdio'</span>, <spanclass="hljs-string">'listen for and compile scripts over stdio'</span>]
[<spanclass="hljs-string">'-l'</span>, <spanclass="hljs-string">'--literate'</span>, <spanclass="hljs-string">'treat stdio as literate style coffee-script'</span>]
[<spanclass="hljs-string">'-t'</span>, <spanclass="hljs-string">'--tokens'</span>, <spanclass="hljs-string">'print out the tokens that the lexer/rewriter produce'</span>]
[<spanclass="hljs-string">'-v'</span>, <spanclass="hljs-string">'--version'</span>, <spanclass="hljs-string">'display the version number'</span>]
[<spanclass="hljs-string">'-w'</span>, <spanclass="hljs-string">'--watch'</span>, <spanclass="hljs-string">'watch scripts for changes and rerun commands'</span>]
]</pre></div></div>
</li>
<liid="section-6">
<divclass="annotation">
<divclass="pilwrap ">
<aclass="pilcrow"href="#section-6">¶</a>
</div>
<p>Top-level objects shared by all the functions.</p>
<p>Run <code>coffee</code> by parsing passed options and determining what action to take.
Many flags cause us to divert before compiling anything. Flags passed after
<code>--</code> will be passed verbatim to your script as arguments in <code>process.argv</code></p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.run: </span><spanclass="o">-></span>
<spanclass="nx">compileScripts</span><spanclass="p">()</span></pre></div></td></tr><trid="section-7"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-7">#</a></div><p>Asynchronously read in each CoffeeScript in a list of source files and
compile them. If a directory is passed, recursively compile all
'.coffee' extension source files in it and all subdirectories.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">compileScripts: </span><spanclass="o">-></span>
<spanclass="k">throw</span><spanclass="k">new</span><spanclass="nb">Error</span><spanclass="s2">"File not found: $source"</span><spanclass="nx">unless</span><spanclass="nx">exists</span>
<spanclass="nx">compile</span><spanclass="nx">source</span><spanclass="p">,</span><spanclass="kc">true</span></pre></div></td></tr><trid="section-8"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">compileScript: </span><spanclass="p">(</span><spanclass="nx">source</span><spanclass="p">,</span><spanclass="nx">code</span><spanclass="p">,</span><spanclass="nx">base</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">puts</span><spanclass="nx">err</span><spanclass="p">.</span><spanclass="nx">message</span></pre></div></td></tr><trid="section-9"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-9">#</a></div><p>Attach the appropriate listeners to compile scripts incoming over <strong>stdin</strong>,
and write them back to <strong>stdout</strong>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">compileStdio: </span><spanclass="o">-></span>
<spanclass="nx">compileScript</span><spanclass="s1">'stdio'</span><spanclass="p">,</span><spanclass="nx">code</span></pre></div></td></tr><trid="section-10"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">watch: </span><spanclass="p">(</span><spanclass="nx">source</span><spanclass="p">,</span><spanclass="nx">base</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">fs</span><spanclass="p">.</span><spanclass="nx">readFile</span><spanclass="nx">source</span><spanclass="p">,</span><spanclass="p">(</span><spanclass="nx">err</span><spanclass="p">,</span><spanclass="nx">code</span><spanclass="p">)</span><spanclass="o">-></span><spanclass="nx">compileScript</span><spanclass="p">(</span><spanclass="nx">source</span><spanclass="p">,</span><spanclass="nx">code</span><spanclass="p">.</span><spanclass="nx">toString</span><spanclass="p">(),</span><spanclass="nx">base</span><spanclass="p">)</span></pre></div></td></tr><trid="section-11"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">writeJs: </span><spanclass="p">(</span><spanclass="nx">source</span><spanclass="p">,</span><spanclass="nx">js</span><spanclass="p">,</span><spanclass="nx">base</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="k">if</span><spanclass="nx">exists</span><spanclass="k">then</span><spanclass="nx">compile</span><spanclass="p">()</span><spanclass="k">else</span><spanclass="nx">exec</span><spanclass="s2">"mkdir -p $dir"</span><spanclass="p">,</span><spanclass="nx">compile</span></pre></div></td></tr><trid="section-12"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">lint: </span><spanclass="p">(</span><spanclass="nx">js</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">jsl</span><spanclass="p">.</span><spanclass="nx">stdin</span><spanclass="p">.</span><spanclass="nx">end</span><spanclass="p">()</span></pre></div></td></tr><trid="section-13"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-13">#</a></div><p>Pretty-print a stream of tokens.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">printTokens: </span><spanclass="p">(</span><spanclass="nx">tokens</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">puts</span><spanclass="nx">strings</span><spanclass="p">.</span><spanclass="nx">join</span><spanclass="p">(</span><spanclass="s1">''</span><spanclass="p">)</span></pre></div></td></tr><trid="section-14"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-14">#</a></div><p>Use the <ahref="optparse.html">OptionParser module</a> to extract all options from
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">parseOptions: </span><spanclass="o">-></span>
<spanclass="nv">sources: </span><spanclass="nx">options</span><spanclass="p">.</span><spanclass="nx">arguments</span><spanclass="p">[</span><spanclass="mi">2</span><spanclass="p">...</span><spanclass="nx">options</span><spanclass="p">.</span><spanclass="nx">arguments</span><spanclass="p">.</span><spanclass="nx">length</span><spanclass="p">]</span></pre></div></td></tr><trid="section-15"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-15">#</a></div><p>The compile-time options to pass to the CoffeeScript compiler.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">compileOptions: </span><spanclass="p">(</span><spanclass="nx">source</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">o</span></pre></div></td></tr><trid="section-16"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-16">#</a></div><p>Print the <code>--help</code> usage message and exit.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">usage: </span><spanclass="o">-></span>
<spanclass="nx">process</span><spanclass="p">.</span><spanclass="nx">exit</span><spanclass="mi">0</span></pre></div></td></tr><trid="section-17"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-17">#</a></div><p>Print the <code>--version</code> message and exit.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">version: </span><spanclass="o">-></span>
<spanclass="nx">puts</span><spanclass="s2">"CoffeeScript version $CoffeeScript.VERSION"</span>
<spanclass="hljs-built_in">console</span>.error <spanclass="hljs-string">"Missing index.coffee or index.litcoffee in <spanclass="hljs-subst">#{source}</span>"</span>
<!DOCTYPE html><html><head><title>helpers.coffee</title><metahttp-equiv="content-type"content="text/html; charset=UTF-8"><linkrel="stylesheet"media="all"href="docco.css"/></head><body><divid="container"><divid="background"></div><divid="jump_to"> Jump To …<divid="jump_wrapper"><divid="jump_page"><aclass="source"href="cake.html"> cake.coffee </a><aclass="source"href="coffee-script.html"> coffee-script.coffee </a><aclass="source"href="command.html"> command.coffee </a><aclass="source"href="grammar.html"> grammar.coffee </a><aclass="source"href="helpers.html"> helpers.coffee </a><aclass="source"href="index.html"> index.coffee </a><aclass="source"href="lexer.html"> lexer.coffee </a><aclass="source"href="nodes.html"> nodes.coffee </a><aclass="source"href="optparse.html"> optparse.coffee </a><aclass="source"href="repl.html"> repl.coffee </a><aclass="source"href="rewriter.html"> rewriter.coffee </a><aclass="source"href="scope.html"> scope.coffee </a></div></div></div><tablecellpadding="0"cellspacing="0"><thead><tr><thclass="docs"><h1> helpers.coffee </h1></th><thclass="code"></th></tr></thead><tbody><trid="section-1"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre></pre></div></td></tr><trid="section-2"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-2">#</a></div><p>Set up exported variables for both <strong>Node.js</strong> and the browser.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="k">this</span><spanclass="p">.</span><spanclass="nv">exports: </span><spanclass="k">this</span><spanclass="nx">unless</span><spanclass="nx">process</span><spanclass="o">?</span>
<spanclass="nv">helpers: exports.helpers: </span><spanclass="p">{}</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>Cross-browser indexOf, so that IE can join the party.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.indexOf: indexOf: </span><spanclass="p">(</span><spanclass="nx">array</span><spanclass="p">,</span><spanclass="nx">item</span><spanclass="p">,</span><spanclass="nx">from</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="o">-</span><spanclass="mi">1</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>Does a list include a value?</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.include: include: </span><spanclass="p">(</span><spanclass="nx">list</span><spanclass="p">,</span><spanclass="nx">value</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">indexOf</span><spanclass="p">(</span><spanclass="nx">list</span><spanclass="p">,</span><spanclass="nx">value</span><spanclass="p">)</span><spanclass="o">>=</span><spanclass="mi">0</span></pre></div></td></tr><trid="section-5"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-5">#</a></div><p>Peek at the beginning of a given string to see if it matches a sequence.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.starts: starts: </span><spanclass="p">(</span><spanclass="nx">string</span><spanclass="p">,</span><spanclass="nx">literal</span><spanclass="p">,</span><spanclass="nx">start</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">string</span><spanclass="p">.</span><spanclass="nx">substring</span><spanclass="p">(</span><spanclass="nx">start</span><spanclass="p">,</span><spanclass="p">(</span><spanclass="nx">start</span><spanclass="o">or</span><spanclass="mi">0</span><spanclass="p">)</span><spanclass="o">+</span><spanclass="nx">literal</span><spanclass="p">.</span><spanclass="nx">length</span><spanclass="p">)</span><spanclass="o">is</span><spanclass="nx">literal</span></pre></div></td></tr><trid="section-6"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-6">#</a></div><p>Trim out all falsy values from an array.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.compact: compact: </span><spanclass="p">(</span><spanclass="nx">array</span><spanclass="p">)</span><spanclass="o">-></span><spanclass="nx">item</span><spanclass="k">for</span><spanclass="nx">item</span><spanclass="k">in</span><spanclass="nx">array</span><spanclass="k">when</span><spanclass="nx">item</span></pre></div></td></tr><trid="section-7"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-7">#</a></div><p>Count the number of occurences of a character in a string.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.count: count: </span><spanclass="p">(</span><spanclass="nx">string</span><spanclass="p">,</span><spanclass="nx">letter</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">num</span></pre></div></td></tr><trid="section-8"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.merge: merge: </span><spanclass="p">(</span><spanclass="nx">options</span><spanclass="p">,</span><spanclass="nx">overrides</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">fresh</span></pre></div></td></tr><trid="section-9"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.extend: extend: </span><spanclass="p">(</span><spanclass="nx">object</span><spanclass="p">,</span><spanclass="nx">properties</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="p">(</span><spanclass="nx">object</span><spanclass="p">[</span><spanclass="nx">key</span><spanclass="p">]</span><spanclass="o">:</span><spanclass="nx">val</span><spanclass="p">)</span><spanclass="k">for</span><spanclass="nx">key</span><spanclass="p">,</span><spanclass="nx">val</span><spanclass="k">of</span><spanclass="nx">properties</span></pre></div></td></tr><trid="section-10"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.flatten: flatten: </span><spanclass="p">(</span><spanclass="nx">array</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">memo</span></pre></div></td></tr><trid="section-11"><tdclass="docs"><divclass="octowrap"><aclass="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><tdclass="code"><divclass="highlight"><pre><spanclass="nv">helpers.del: del: </span><spanclass="p">(</span><spanclass="nx">obj</span><spanclass="p">,</span><spanclass="nx">key</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="hljs-keyword">return</span><spanclass="hljs-literal">true</span><spanclass="hljs-keyword">for</span> e <spanclass="hljs-keyword">in</span><spanclass="hljs-keyword">this</span><spanclass="hljs-keyword">when</span> fn e
<aclass="large"href="javascript:void(0);">Jump To …</a>
<aclass="small"href="javascript:void(0);">+</a>
<divid="jump_wrapper">
<divid="jump_page_wrapper">
<divid="jump_page">
<aclass="source"href="browser.html">
browser.coffee
</a>
<aclass="source"href="cake.html">
cake.coffee
</a>
<aclass="source"href="coffee-script.html">
coffee-script.coffee
</a>
<aclass="source"href="command.html">
command.coffee
</a>
<aclass="source"href="grammar.html">
grammar.coffee
</a>
<aclass="source"href="helpers.html">
helpers.coffee
</a>
<aclass="source"href="index.html">
index.coffee
</a>
<aclass="source"href="lexer.html">
lexer.coffee
</a>
<aclass="source"href="nodes.html">
nodes.coffee
</a>
<aclass="source"href="optparse.html">
optparse.coffee
</a>
<aclass="source"href="register.html">
register.coffee
</a>
<aclass="source"href="repl.html">
repl.coffee
</a>
<aclass="source"href="rewriter.html">
rewriter.coffee
</a>
<aclass="source"href="scope.html">
scope.litcoffee
</a>
<aclass="source"href="sourcemap.html">
sourcemap.litcoffee
</a>
</div>
</div>
</li>
</ul>
<ulclass="sections">
<liid="title">
<divclass="annotation">
<h1>index.coffee</h1>
</div>
</li>
<liid="section-1">
<divclass="annotation">
<divclass="pilwrap ">
<aclass="pilcrow"href="#section-1">¶</a>
</div>
<p>Loader for CoffeeScript as a Node.js library.</p>
</div>
<divclass="content"><divclass='highlight'><pre>exports[key] = val <spanclass="hljs-keyword">for</span> key, val <spanclass="hljs-keyword">of</span><spanclass="hljs-built_in">require</span><spanclass="hljs-string">'./coffee-script'</span></pre></div></div>
</code></pre><p>The first non-option is considered to be the start of the file (and file
option) list, and all subsequent arguments are left unparsed.</p>
<pre><code>parser: new OptionParser switches, helpBanner
options: parser.parse process.argv
</code></pre></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">exports.OptionParser:</span><spanclass="nx">class</span><spanclass="nx">OptionParser</span></pre></div></td></tr><trid="section-2"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-2">#</a></div><p>Initialize with a list of valid options, in the form:</p>
<p>Initialize with a list of valid options, in the form:</p>
<pre><code>[short-flag, long-flag, description]
</code></pre>
</code></pre><p>Along with an an optional banner for the usage help.</p>
<p>Along with an an optional banner for the usage help.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">constructor: </span><spanclass="p">(</span><spanclass="nx">rules</span><spanclass="p">,</span><spanclass="nx">banner</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="vi">@rules: </span><spanclass="nx">buildRules</span><spanclass="p">(</span><spanclass="nx">rules</span><spanclass="p">)</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>Parse the list of arguments, populating an <code>options</code> object with all of the
specified options, and returning it. <code>options.arguments</code>will be an array
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.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">parse: </span><spanclass="p">(</span><spanclass="nx">args</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">options</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>Return the help text for this <strong>OptionParser</strong>, listing and describing all
of the valid options, for <code>--help</code> and such.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">help: </span><spanclass="o">-></span>
<spanclass="nv">OPTIONAL: </span><spanclass="sr">/\[(.+)\]/</span></pre></div></td></tr><trid="section-7"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-7">#</a></div><p>Build and return the list of option rules. If the optional <em>short-flag</em> is
unspecified, leave it out by padding with <code>null</code>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">buildRules: </span><spanclass="p">(</span><spanclass="nx">rules</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">buildRule</span><spanclass="nx">tuple</span><spanclass="p">...</span></pre></div></td></tr><trid="section-8"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-8">#</a></div><p>Build a rule from a <code>-o</code> short flag, a <code>--output [DIR]</code> long flag, and the
description of what the option does.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">buildRule: </span><spanclass="p">(</span><spanclass="nx">shortFlag</span><spanclass="p">,</span><spanclass="nx">longFlag</span><spanclass="p">,</span><spanclass="nx">description</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="p">}</span></pre></div></td></tr><trid="section-9"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-9">#</a></div><p>Normalize arguments by expanding merged flags into multiple flags. This allows
you to have <code>-wl</code> be the same as <code>--watch --lint</code>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">normalizeArguments: </span><spanclass="p">(</span><spanclass="nx">args</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="hljs-keyword">if</span> match = arg.match MULTI_FLAG
result.push <spanclass="hljs-string">'-'</span> + l <spanclass="hljs-keyword">for</span> l <spanclass="hljs-keyword">in</span> match[<spanclass="hljs-number">1</span>].split <spanclass="hljs-string">''</span>
<!DOCTYPE html><html><head><title>repl.coffee</title><metahttp-equiv="content-type"content="text/html; charset=UTF-8"><linkrel="stylesheet"media="all"href="docco.css"/></head><body><divid="container"><divid="background"></div><divid="jump_to"> Jump To …<divid="jump_wrapper"><divid="jump_page"><aclass="source"href="cake.html"> cake.coffee </a><aclass="source"href="coffee-script.html"> coffee-script.coffee </a><aclass="source"href="command.html"> command.coffee </a><aclass="source"href="grammar.html"> grammar.coffee </a><aclass="source"href="helpers.html"> helpers.coffee </a><aclass="source"href="index.html"> index.coffee </a><aclass="source"href="lexer.html"> lexer.coffee </a><aclass="source"href="nodes.html"> nodes.coffee </a><aclass="source"href="optparse.html"> optparse.coffee </a><aclass="source"href="repl.html"> repl.coffee </a><aclass="source"href="rewriter.html"> rewriter.coffee </a><aclass="source"href="scope.html"> scope.coffee </a></div></div></div><tablecellpadding="0"cellspacing="0"><thead><tr><thclass="docs"><h1> repl.coffee </h1></th><thclass="code"></th></tr></thead><tbody><trid="section-1"><tdclass="docs"><divclass="octowrap"><aclass="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>
<!DOCTYPE html>
<pre><code>coffee> puts "$num bottles of beer" for num in [99..1]
</code></pre></td><tdclass="code"><divclass="highlight"><pre></pre></div></td></tr><trid="section-2"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-2">#</a></div><p>Require the <strong>coffee-script</strong> module to get access to the compiler.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">CoffeeScript: </span><spanclass="nx">require</span><spanclass="s1">'./coffee-script'</span>
<spanclass="nv">readline: </span><spanclass="nx">require</span><spanclass="s1">'readline'</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>Start by opening up <strong>stdio</strong>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">stdio: </span><spanclass="nx">process</span><spanclass="p">.</span><spanclass="nx">openStdin</span><spanclass="p">()</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>Quick alias for quitting the REPL.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nx">helpers</span><spanclass="p">.</span><spanclass="nx">extend</span><spanclass="nx">global</span><spanclass="p">,</span><spanclass="p">{</span>
<spanclass="p">}</span></pre></div></td></tr><trid="section-5"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-5">#</a></div><p>The main REPL function. <strong>run</strong> is called every time a line of code is entered.
Attempt to evaluate the command. If there's an exception, print it out instead
of exiting.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">run: </span><spanclass="p">(</span><spanclass="nx">buffer</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">repl</span><spanclass="p">.</span><spanclass="nx">prompt</span><spanclass="p">()</span></pre></div></td></tr><trid="section-6"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-6">#</a></div><p>Create the REPL by listening to <strong>stdin</strong>.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">repl: </span><spanclass="nx">readline</span><spanclass="p">.</span><spanclass="nx">createInterface</span><spanclass="nx">stdio</span>
<spanclass="hljs-keyword">if</span> major <spanclass="hljs-keyword">is</span><spanclass="hljs-number">0</span><spanclass="hljs-keyword">and</span> minor <<spanclass="hljs-number">8</span>
<spanclass="hljs-built_in">console</span>.warn <spanclass="hljs-string">"Node 0.8.0+ required for CoffeeScript REPL"</span>
<divclass="content"><divclass='highlight'><pre> repl.commands[getCommandId(repl, <spanclass="hljs-string">'load'</span>)].help = <spanclass="hljs-string">'Load code from a file into this REPL session'</span>
<aclass="large"href="javascript:void(0);">Jump To …</a>
<aclass="small"href="javascript:void(0);">+</a>
<divid="jump_wrapper">
<divid="jump_page_wrapper">
<divid="jump_page">
<aclass="source"href="browser.html">
browser.coffee
</a>
<aclass="source"href="cake.html">
cake.coffee
</a>
<aclass="source"href="coffee-script.html">
coffee-script.coffee
</a>
<aclass="source"href="command.html">
command.coffee
</a>
<aclass="source"href="grammar.html">
grammar.coffee
</a>
<aclass="source"href="helpers.html">
helpers.coffee
</a>
<aclass="source"href="index.html">
index.coffee
</a>
<aclass="source"href="lexer.html">
lexer.coffee
</a>
<aclass="source"href="nodes.html">
nodes.coffee
</a>
<aclass="source"href="optparse.html">
optparse.coffee
</a>
<aclass="source"href="register.html">
register.coffee
</a>
<aclass="source"href="repl.html">
repl.coffee
</a>
<aclass="source"href="rewriter.html">
rewriter.coffee
</a>
<aclass="source"href="scope.html">
scope.litcoffee
</a>
<aclass="source"href="sourcemap.html">
sourcemap.litcoffee
</a>
</div>
</div>
</li>
</ul>
<ulclass="sections">
<liid="title">
<divclass="annotation">
<h1>scope.litcoffee</h1>
</div>
</li>
<liid="section-1">
<divclass="annotation">
<divclass="pilwrap ">
<aclass="pilcrow"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
variables are new and need to be declared with <code>var</code>, and which are shared
with the outside.</p></td><tdclass="code"><divclass="highlight"><pre></pre></div></td></tr><trid="section-2"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-2">#</a></div><p>Set up exported variables for both <strong>Node.js</strong> and the browser.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="k">this</span><spanclass="p">.</span><spanclass="nv">exports: </span><spanclass="k">this</span><spanclass="nx">unless</span><spanclass="nx">process</span><spanclass="o">?</span>
with external scopes.</p>
<p>Import the helpers we plan to use.</p>
<spanclass="nv">exports.Scope: </span><spanclass="nx">class</span><spanclass="nx">Scope</span></pre></div></td></tr><trid="section-3"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-3">#</a></div><p>The top-level <strong>Scope</strong> object.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="vi">@root: </span><spanclass="kc">null</span></pre></div></td></tr><trid="section-4"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-4">#</a></div><p>Initialize a scope with its parent, for lookups up the chain,
as well as a reference to the <strong>Expressions</strong> node is belongs to, which is
where it should declare its variables, and a reference to the function that
it wraps.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">constructor: </span><spanclass="p">(</span><spanclass="nx">parent</span><spanclass="p">,</span><spanclass="nx">expressions</span><spanclass="p">,</span><spanclass="nx">method</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="vi">@tempVar: </span><spanclass="s1">'_a'</span></pre></div></td></tr><trid="section-5"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-5">#</a></div><p>Look up a variable name in lexical scope, and declare it if it does not
<spanclass="kc">false</span></pre></div></td></tr><trid="section-6"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-6">#</a></div><p>Test variables and return true the first time fn(v, k) returns true</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">any: </span><spanclass="p">(</span><spanclass="nx">fn</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="k">return</span><spanclass="kc">false</span></pre></div></td></tr><trid="section-7"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-7">#</a></div><p>Reserve a variable name as originating from a function parameter for this
scope. No <code>var</code> required for internal references.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">parameter: </span><spanclass="p">(</span><spanclass="nx">name</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">@variables</span><spanclass="p">[</span><spanclass="nx">name</span><spanclass="p">]</span><spanclass="o">:</span><spanclass="s1">'param'</span></pre></div></td></tr><trid="section-8"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-8">#</a></div><p>Just check to see if a variable has already been declared, without reserving.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">check: </span><spanclass="p">(</span><spanclass="nx">name</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="o">!!</span><spanclass="p">(</span><spanclass="nx">@parent</span><spanclass="o">and</span><spanclass="nx">@parent</span><spanclass="p">.</span><spanclass="nx">check</span><spanclass="p">(</span><spanclass="nx">name</span><spanclass="p">))</span></pre></div></td></tr><trid="section-9"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-9">#</a></div><p>If we need to store an intermediate result, find an available name for a
compiler-generated variable. <code>_a</code>, <code>_b</code>, and so on...</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">freeVariable: </span><spanclass="o">-></span>
<spanclass="nx">@tempVar</span></pre></div></td></tr><trid="section-10"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-10">#</a></div><p>Ensure that an assignment is made at the top of this scope
(or at the top-level scope, if requested).</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">assign: </span><spanclass="p">(</span><spanclass="nx">name</span><spanclass="p">,</span><spanclass="nx">value</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">@variables</span><spanclass="p">[</span><spanclass="nx">name</span><spanclass="p">]</span><spanclass="o">:</span><spanclass="p">{</span><spanclass="nv">value: </span><spanclass="nx">value</span><spanclass="p">,</span><spanclass="nv">assigned: </span><spanclass="kc">true</span><spanclass="p">}</span></pre></div></td></tr><trid="section-11"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-11">#</a></div><p>Does this scope reference any variables that need to be declared in the
given function body?</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">hasDeclarations: </span><spanclass="p">(</span><spanclass="nx">body</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">body</span><spanclass="o">is</span><spanclass="nx">@expressions</span><spanclass="o">and</span><spanclass="nx">@any</span><spanclass="p">(</span><spanclass="nx">k</span><spanclass="p">,</span><spanclass="nx">val</span><spanclass="p">)</span><spanclass="o">-></span><spanclass="nx">val</span><spanclass="o">is</span><spanclass="s1">'var'</span></pre></div></td></tr><trid="section-12"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-12">#</a></div><p>Does this scope reference any assignments that need to be declared at the
top of the given function body?</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">hasAssignments: </span><spanclass="p">(</span><spanclass="nx">body</span><spanclass="p">)</span><spanclass="o">-></span>
<spanclass="nx">body</span><spanclass="o">is</span><spanclass="nx">@expressions</span><spanclass="o">and</span><spanclass="nx">@any</span><spanclass="p">(</span><spanclass="nx">k</span><spanclass="p">,</span><spanclass="nx">val</span><spanclass="p">)</span><spanclass="o">-></span><spanclass="nx">val</span><spanclass="p">.</span><spanclass="nx">assigned</span></pre></div></td></tr><trid="section-13"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-13">#</a></div><p>Return the list of variables first declared in this scope.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">declaredVariables: </span><spanclass="o">-></span>
<spanclass="p">(</span><spanclass="nx">key</span><spanclass="k">for</span><spanclass="nx">key</span><spanclass="p">,</span><spanclass="nx">val</span><spanclass="k">of</span><spanclass="nx">@variables</span><spanclass="k">when</span><spanclass="nx">val</span><spanclass="o">is</span><spanclass="s1">'var'</span><spanclass="p">).</span><spanclass="nx">sort</span><spanclass="p">()</span></pre></div></td></tr><trid="section-14"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-14">#</a></div><p>Return the list of assignments that are supposed to be made at the top
of this scope.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">assignedVariables: </span><spanclass="o">-></span>
<spanclass="s2">"$key = $val.value"</span><spanclass="k">for</span><spanclass="nx">key</span><spanclass="p">,</span><spanclass="nx">val</span><spanclass="k">of</span><spanclass="nx">@variables</span><spanclass="k">when</span><spanclass="nx">val</span><spanclass="p">.</span><spanclass="nx">assigned</span></pre></div></td></tr><trid="section-15"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-15">#</a></div><p>Compile the JavaScript for all of the variable declarations in this scope.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">compiledDeclarations: </span><spanclass="o">-></span>
<spanclass="nx">@declaredVariables</span><spanclass="p">().</span><spanclass="nx">join</span><spanclass="s1">', '</span></pre></div></td></tr><trid="section-16"><tdclass="docs"><divclass="octowrap"><aclass="octothorpe"href="#section-16">#</a></div><p>Compile the JavaScript for all of the variable assignments in this scope.</p></td><tdclass="code"><divclass="highlight"><pre><spanclass="nv">compiledAssignments: </span><spanclass="o">-></span>
<spanclass="hljs-keyword">return</span><spanclass="hljs-literal">yes</span><spanclass="hljs-keyword">if</span><spanclass="hljs-property">@check</span> name
<spanclass="hljs-string">'_'</span> + name + <spanclass="hljs-keyword">if</span> index ><spanclass="hljs-number">1</span><spanclass="hljs-keyword">then</span> index - <spanclass="hljs-number">1</span><spanclass="hljs-keyword">else</span><spanclass="hljs-string">''</span>
<spanclass="hljs-keyword">return</span> v.type <spanclass="hljs-keyword">for</span> v <spanclass="hljs-keyword">in</span><spanclass="hljs-property">@variables</span><spanclass="hljs-keyword">when</span> v.name <spanclass="hljs-keyword">is</span> name
<spanclass="hljs-keyword">for</span> v <spanclass="hljs-keyword">in</span><spanclass="hljs-property">@variables</span><spanclass="hljs-keyword">when</span> v.type <spanclass="hljs-keyword">is</span><spanclass="hljs-string">'var'</span>
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.