Compare commits

..

149 Commits
1.8.0 ... 1.9.1

Author SHA1 Message Date
Jeremy Ashkenas
533ad8afe9 CoffeeScript 1.9.1 2015-02-18 15:43:33 -05:00
Jeremy Ashkenas
1961f06e08 Merge pull request #3861 from lydell/heredoc-undefined
Fix single-line heredocs starting with "undefined"
2015-02-18 14:06:09 -05:00
Simon Lydell
4503e2716e Fix single-line heredocs starting with "undefined" 2015-02-18 17:40:40 +01:00
Jeremy Ashkenas
e4d81005be Merge pull request #3854 from alubbe/fixyieldreturn
fixed yield return producing incorrect output when used outside of the last line
2015-02-17 15:47:24 -05:00
Andreas Lubbe
b6012c4617 improved yield return test 2015-02-17 19:11:06 +01:00
Andreas Lubbe
feee6954a6 fixed yield return producing incorrect output when used outside of the last line 2015-02-17 19:11:06 +01:00
Jeremy Ashkenas
fea058c53a Merge pull request #3858 from alubbe/master
fixed overly fragile repl test to work with 0.12
2015-02-17 10:49:43 -05:00
Andreas Lubbe
25d97aa136 fixed overly fragile repl test to work with 0.12, see https://github.com/jashkenas/coffeescript/issues/3855 2015-02-17 11:36:24 +01:00
Michael Ficarra
7c8849cc21 Merge pull request #3852 from alubbe/moretests
added a lot of ES6 generator tests
2015-02-15 11:46:10 -08:00
Andreas Lubbe
b362bd672c added a lot of ES6 generator tests 2015-02-15 20:35:22 +01:00
Michael Ficarra
a4f510501c Merge pull request #3853 from alubbe/fixyieldthrow
fixed being unable to use 'yield throw'
2015-02-15 10:55:17 -08:00
Andreas Lubbe
e3f6e19950 fixed being unable to use 'yield throw' 2015-02-15 19:01:00 +01:00
Jeremy Ashkenas
b49b41320e Merge pull request #3758 from DiThi/master
Prevent writing the same file several times (fixes #3753)
2015-02-12 14:27:06 -05:00
Alberto Torres Ruiz
6bc3157793 Prevent writing the same file several times (fixes #3753) 2015-02-12 20:20:35 +01:00
Jeremy Ashkenas
dc8a2b17d0 Merge pull request #3849 from lydell/regex-end-invalid-escape
Fix error message for invalid escape at end of regex
2015-02-12 13:55:10 -05:00
Jeremy Ashkenas
c3ae2328af Merge pull request #3850 from lydell/implicit-object-start-token
Fix #3846: Fix odd start token of implicit objects
2015-02-12 13:54:38 -05:00
Simon Lydell
57846ea5c0 Fix #3846: Fix odd start token of implicit objects
Now the same hack as for reserved identifier tokens in the lexer is used
instead.
2015-02-12 19:41:12 +01:00
Simon Lydell
3da88b9b3f Fix error message for invalid escape at end of regex 2015-02-12 19:26:41 +01:00
Jeremy Ashkenas
8130e63e43 Merge pull request #3802 from mapmeld/multiline_comment_fix
Allow multiline comment at end of an object definition [Fixes #3761]
2015-02-10 23:56:01 -05:00
Nick Doiron
dc44ebbdaa allow multiline comment inside of an object definition [Fixes #3761]
use more CoffeeScript syntax
2015-02-10 23:35:39 -05:00
Jeremy Ashkenas
88ad059d54 Merge pull request #3840 from lydell/dynakeys
Fix #3597: Allow interpolations in object keys
2015-02-10 10:43:26 -05:00
Simon Lydell
76c076db55 Fix #3597: Allow interpolations in object keys
The following is now allowed:

    o =
      a: 1
      b: 2
      "#{'c'}": 3
      "#{'d'}": 4
      e: 5
      "#{'f'}": 6
      g: 7

It compiles to:

    o = (
      obj = {
        a: 1,
        b: 2
      },
      obj["" + 'c'] = 3,
      obj["" + 'd'] = 4,
      obj.e = 5,
      obj["" + 'f'] = 6,
      obj.g = 7,
      obj
    );

- Closes #3039. Empty interpolations in object keys are now _supposed_ to be
  allowed.
- Closes #1131. No need to improve error messages for attempted key
  interpolation anymore.
- Implementing this required fixing the following bug: `("" + a): 1` used to
  error out on the colon, saying "unexpected colon". But really, it is the
  attempted object key that is unexpected. Now the error is on the opening
  parenthesis instead.
- However, the above fix broke some error message tests for regexes. The easiest
  way to fix this was to make a seemingly unrelated change: The error messages
  for unexpected identifiers, numbers, strings and regexes now say for example
  'unexpected string' instead of 'unexpected """some #{really long} string"""'.
  In other words, the tag _name_ is used instead of the tag _value_.
  This was way easier to implement, and is more helpful to the user. Using the
  tag value is good for operators, reserved words and the like, but not for
  tokens which can contain any text. For example, 'unexpected identifier' is
  better than 'unexpected expected' (if a variable called 'expected' was used
  erraneously).
- While writing tests for the above point I found a few minor bugs with string
  locations which have been fixed.
2015-02-09 17:32:37 +01:00
Michael Ficarra
5698e6c72a Merge pull request #3842 from arianf/master
Fixed copyright range to be updated to 2015
2015-02-08 13:56:05 -08:00
Arian Faurtosh
e0e4967ad8 Fixed copyright range to be updated to 2015 2015-02-08 11:28:51 -08:00
Michael Ficarra
53c7891599 Merge pull request #3841 from lydell/last
Replace `last array` helper with `[..., last] = array`
2015-02-08 10:22:09 -08:00
Simon Lydell
94a17cb74a Replace last array helper with [..., last] = array 2015-02-07 21:50:41 +01:00
Jeremy Ashkenas
5d139596f8 Merge pull request #3834 from lydell/better-lexer-errors
Improve lexer error messages
2015-02-06 12:17:26 -05:00
Simon Lydell
213225418a Improve lexer error messages
- Erraneous tokens are now fully underlined with ^:s.
- The error messages are now a bit more consistent.
2015-02-06 10:52:02 +01:00
Jeremy Ashkenas
3b3e52097a Merge pull request #3833 from lydell/escapes
Fix #3795: Never generate invalid strings and regexes
2015-02-05 11:32:00 -05:00
Simon Lydell
72ceec5680 Fix #3795: Never generate invalid strings and regexes
- Invalid `\x` and `\u` escapes now throw errors.
- U+2028 and U+2029 (which JavaScript treats as newline characters) are now
  escaped to `\u2028` and `\u2029`, respectively.
- Octal escapes are now forbidden not only in strings, but in regexes as well.
- `\0` escapes are now escaped if needed (so that they do not form an octal
  literal by mistake). Note that `\01` is an octal escape in a regex, while `\1`
  is a backreference. (Added a test for backreferences while at it.)
- Fixed a bug where newlines in strings weren't removed if preceded by an
  escaped character.
2015-02-05 17:23:03 +01:00
Michael Ficarra
5a220d4e13 Merge pull request #3830 from swang/fix_incorrect_token
Fix incorrect token representation
2015-02-04 21:40:45 -08:00
Shuan Wang
92e5ab2857 Fix incorrect token representation
The third element in a token should just be an object containing line
number and column info. This PR fixes the problem with one of the tokens
being set incorrectly.
2015-02-04 21:02:44 -08:00
Jeremy Ashkenas
64632e3332 Merge pull request #3827 from lydell/unexpected-regex
Improve error messages for unexpected regexes
2015-02-03 15:10:29 -05:00
Jeremy Ashkenas
c0e1f23f23 Merge pull request #3785 from lydell/super
Allow super in methods with dynamic names
2015-02-03 15:09:31 -05:00
Simon Lydell
ee8f889cbd Allow super in methods with dynamic names
As discussed in https://github.com/jashkenas/coffeescript/issues/3039#issuecomment-68916918.
This is the first step to implement dynamic object literal keys (see #3597).

This also fixes #1392.

In short, `super` is now allowed:

    # in class definitions:
    class A
      instanceMethod: -> super
      @staticMethod: -> super
      @staticMethod2 = -> super

    # in assignment where the next to last access is 'prototype':
    A::m = -> super
    A.prototype.m = -> super
    a.b()[5]::m = -> super
    A::[x()] = -> super
    class B
      @::m = -> super
2015-02-03 20:46:37 +01:00
Simon Lydell
ffa25aae77 Improve error messages for unexpected regexes 2015-02-03 20:42:50 +01:00
Jeremy Ashkenas
04b30a6cc4 Merge pull request #3786 from lydell/loop-safety
Fix #3778: Make for loops more consistent
2015-02-03 13:08:33 -05:00
Simon Lydell
996a171a4e Fix #3778: Make for loops more consistent
The following two lines might seem equivalent:

    for n in [1, 2, 3] by  a then a = 4; n
    for n in [1, 2, 3] by +a then a = 4; n

But they used not to be, because `+a` was cached into a `ref`, while the plain
`a` wasn’t. Now even simple identifiers are cached, making the two lines
equivalent as expected.
2015-02-03 19:05:07 +01:00
Jeremy Ashkenas
17a271af06 Merge pull request #3826 from lydell/string-locations
Fix #3822: Include delimiters in string/regex locations
2015-02-03 12:58:46 -05:00
Simon Lydell
f8c366c479 Fix #3822: Include delimiters in string/regex locations 2015-02-03 18:55:38 +01:00
Jeremy Ashkenas
934bd2acc7 Merge branch 'master' of github.com:jashkenas/coffeescript 2015-02-03 11:31:44 -05:00
Jeremy Ashkenas
dd0ec84ebe redoc 2015-02-03 11:31:43 -05:00
Jeremy Ashkenas
e9a372dff5 Merge pull request #3821 from lydell/no-underscore
Name generated variables without leading underscore
2015-01-30 14:56:22 -05:00
Simon Lydell
4d7a0d2470 Name generated variables without leading underscore
For example, `ref` not `_ref`. It's cleaner.

This also fixes #3816.
2015-01-30 20:33:03 +01:00
Jeremy Ashkenas
c2abe253a1 Revert "move changelog"
This reverts commit 3ddd3115eb.
2015-01-30 13:44:42 -05:00
Jeremy Ashkenas
3ddd3115eb move changelog 2015-01-30 11:43:05 -05:00
Jeremy Ashkenas
a3096eab91 #3819 changelog docs 2015-01-30 11:14:03 -05:00
Jeremy Ashkenas
3fd004b852 Fixes #3816 -- prettier internal variable names. 2015-01-29 16:24:30 -05:00
Jeremy Ashkenas
0a9c7a3257 docs 2015-01-29 14:58:49 -05:00
Jeremy Ashkenas
f7692c92ce more text tweaks 2015-01-29 12:25:25 -05:00
Jeremy Ashkenas
cdf69eb5bc Merge branch 'gh-pages' 2015-01-29 12:22:26 -05:00
Jeremy Ashkenas
9aeecf582b text tweak 2015-01-29 12:22:16 -05:00
Jeremy Ashkenas
e0ec8a51e4 CoffeeScript 1.9.0 2015-01-29 12:20:46 -05:00
Jeremy Ashkenas
a62e49311e removing the mkdirp test 2015-01-29 11:39:18 -05:00
Jeremy Ashkenas
9a38486d08 Merge pull request #3800 from ysmood/decouple_mkdirp
Decouple "mkdirp".
2015-01-29 11:38:27 -05:00
Jeremy Ashkenas
06e8be5d94 rebuilt browser just for testing 2015-01-29 11:16:01 -05:00
Yad Smood
90a1cbac49 Optimize the mkdirp test 2015-01-29 03:49:40 +08:00
Yad Smood
3d58b4cda1 Add test for mkdirp 2015-01-29 00:44:28 +08:00
Michael Ficarra
2f0724f0ad Merge pull request #3812 from xfq/patch-1
Update index.html.js
2015-01-27 20:39:47 -08:00
Xue Fuqiao
f288d20409 Update index.html.js
Node comes with npm installed and "npm" is not an abbreviation for "Node Package Manager".
2015-01-28 08:52:08 +08:00
Michael Ficarra
dca915af60 Merge pull request #3808 from lydell/api-break-fix
Fix broken CoffeeScript APIs
2015-01-26 09:43:04 -08:00
Simon Lydell
54a4560340 Fix broken CoffeeScript APIs
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.
2015-01-26 18:21:02 +01:00
Michael Ficarra
518d7c16b7 Merge pull request #3807 from lydell/repl-fix
Fix #3804: Provide list of referenced vars to REPL
2015-01-26 08:35:38 -08:00
Simon Lydell
8ed691e266 Fix #3804: Provide list of referenced vars to REPL
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 ]
2015-01-26 17:18:35 +01:00
Yad Smood
74fc7128ab Decouple "mkdirp"
Make coffee completely independent.
2015-01-22 04:20:34 +08:00
Michael Ficarra
68c0e2dc0f Merge pull request #3798 from ogennadi/patch-1
Fixed broken link
2015-01-20 18:21:55 -08:00
Oge Nnadi
42dde38842 Fixed broken link 2015-01-20 12:45:27 -08:00
Michael Ficarra
7d6f6174d5 Merge pull request #3787 from lydell/single-token-interpolation
Fix #1316: Interpolate interpolations safely
2015-01-16 08:43:05 -08:00
Simon Lydell
05b3707506 Fix #1316: Interpolate interpolations safely
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.
2015-01-16 17:19:42 +01:00
Michael Ficarra
5d1d1b7999 Merge pull request #3792 from lydell/issue-3194
Fix #3194: Make strings always uncallable
2015-01-15 22:34:57 -08:00
Simon Lydell
3db029f2c1 Make regexes always uncallable
No matter if they have interpolations or not.
2015-01-15 19:44:14 +01:00
Michael Ficarra
67aaa8b57f Merge pull request #3794 from lydell/jison-update
Make CoffeeScript work with jison 0.4.14+
2015-01-15 09:03:27 -08:00
Simon Lydell
28c07d30cb Make CoffeeScript work with jison 0.4.14+
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.
2015-01-15 17:47:07 +01:00
Simon Lydell
fce502ac98 Fix #3194: Make strings always uncallable
No matter if they have interpolations or not.
2015-01-14 21:27:24 +01:00
Michael Ficarra
669e7fed10 Merge pull request #3791 from lydell/issue-3502
Fix #3502: Define param variables when expansion
2015-01-13 20:00:32 -08:00
Michael Ficarra
4bf45ff894 Merge pull request #3790 from lydell/scope-root
Get rid of `Scope.root` hack
2015-01-13 12:53:03 -08:00
Simon Lydell
4c2c472e07 Fix #3502: Define param variables when expansion 2015-01-13 21:26:11 +01:00
Simon Lydell
22f19522ff Get rid of Scope.root hack
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.
2015-01-13 20:21:45 +01:00
Michael Ficarra
9fa77af576 Merge pull request #3784 from lydell/unique-generated-vars
Unique generated vars
2015-01-12 21:14:44 -08:00
Michael Ficarra
efd7ebb066 Merge pull request #3788 from lydell/unexpected-call-end
Better error message for unexpected CALL_END
2015-01-12 20:55:25 -08:00
Simon Lydell
62712060c0 Better error message for unexpected CALL_END 2015-01-12 20:40:59 +01:00
Simon Lydell
a46978640b Allow variables named like helper functions 2015-01-11 12:12:40 +01:00
Simon Lydell
8ab15d7372 Fix #1500, #1574, #3318: Name generated vars uniquely
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.
2015-01-10 23:25:01 +01:00
Joshua Peek
23a691ae87 Add test for reserved keywords as parameters 2015-01-10 23:23:26 +01:00
Michael Ficarra
bec8f27e8a Merge pull request #3782 from lydell/regex
Fix #3410, #3182: Allow regex to start with space or =
2015-01-10 07:52:02 -08:00
Michael Ficarra
ac2e540e1b Merge pull request #3777 from lydell/unary-plus-minus-refs
Fix #3598: Make unary + and - generate _refs
2015-01-09 18:12:52 -08:00
Michael Ficarra
e0ad0d795d Merge pull request #3783 from lydell/issue-3671
Fix #3671: Allow step in optimized range comprehensions
2015-01-09 17:54:55 -08:00
Simon Lydell
a63009fccb Fix #3671: Allow step in optimized range comprehensions
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.
2015-01-10 02:31:56 +01:00
Simon Lydell
8fd6258a46 Fix #3410, #3182: Allow regex to start with space or =
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.
2015-01-10 01:48:00 +01:00
Simon Lydell
24398774fc Fix #3598: Make unary + and - generate _refs
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.
2015-01-09 18:12:10 +01:00
Jeremy Ashkenas
e769423d52 Merge pull request #3774 from lydell/unicode-spaces
Fix #2516, #3560: Unicode space handling
2015-01-06 16:10:59 -05:00
Simon Lydell
9ec427ba80 Fix #2516, #3560: Unicode space handling
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.
2015-01-06 21:32:14 +01:00
Jeremy Ashkenas
c478f283f4 Merge pull request #3771 from mbrio/master
Fix issue #3498
2015-01-05 15:51:26 -05:00
Michael Diolosa
8e299b09cc Fix issue #3498 2015-01-05 15:40:04 -05:00
Michael Ficarra
b70f6571bd Merge pull request #3770 from lydell/interpolations
Refactor interpolation (and string and regex) handling in lexer
2015-01-04 12:12:56 -08:00
Simon Lydell
ae6df88c5c Point "missing )/}/]" errors to the unclosed (/{/[
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).
2015-01-04 07:51:53 +01:00
Simon Lydell
0dcff507fb Refactor interpolation (and string and regex) handling in lexer
- 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.
2015-01-04 07:47:09 +01:00
Jeremy Ashkenas
8e4fb1b937 Merge pull request #3748 from sscotth/master
Include logo .svg files
2014-12-03 10:20:32 -05:00
Scott
931b74e449 include logo .svg files 2014-12-02 18:33:07 -06:00
Jeremy Ashkenas
4199f4f325 Merge pull request #3734 from alubbe/master
fixed yield keyword not working in switch & for loop expressions
2014-11-21 18:38:11 -05:00
alubbe
5950d6328d added tests for yield in switch & for loop expressions 2014-11-21 23:14:53 +01:00
alubbe
a9fbf14adf fixed yield keyword not working in switch & for loop expressions 2014-11-21 22:52:09 +01:00
Jeremy Ashkenas
485aa8efcf add Die Alternative to books section 2014-11-17 13:43:41 -05:00
Jeremy Ashkenas
a563e8f8fe Merge pull request #3703 from bigtunacan/master
Add bower.json configuration
2014-10-29 17:05:25 -04:00
Joiey Seeley
4035e7caab Removed "mkdirp": "~0.3.5" from bower.json 2014-10-29 15:10:57 -05:00
Joiey Seeley
2c6e6ca870 Added an initial bower.json configuration file 2014-10-29 14:23:31 -05:00
Jeremy Ashkenas
f2a3f7507e Merge pull request #3521 from gscottolson/master
Retina favicon.ico
2014-10-27 17:18:33 -04:00
Jeremy Ashkenas
4f82e5912e Merge pull request #3677 from alubbe/master
implemented proper precedence for 'yield'
2014-10-13 11:41:36 -04:00
alubbe
dd5da7f5f2 implemented proper precedence for 'yield' 2014-10-13 03:32:02 +02:00
Anatoly Ressin
ec44aba71a Improved test readability + fixed integer divison 2014-10-12 22:32:02 +03:00
Anatoly Ressin
e8a4e93a72 Added failing test case for the yield precedence 2014-10-12 20:08:28 +03:00
Jeremy Ashkenas
158ca0d869 Merge pull request #3638 from lbeschastny/issue3638
Invalid block comments compilation
2014-09-23 14:52:03 -04:00
Jeremy Ashkenas
a78cbe78a1 Merge pull request #3240 from alubbe/master
using 'yield' automatically turns functions into generators
2014-09-19 16:38:41 -04:00
Leonid Beschastny
77d5b95260 Added test for jashkenas/coffee-script#3638 2014-09-17 15:02:18 +04:00
Leonid Beschastny
55e3b6b3c3 Fixed jashkenas/coffeescript#3638 - invalid block comments compilation 2014-09-17 15:02:10 +04:00
Andreas Lubbe
efca2861a6 added tests for yield, yield from, yield return and yield in if statements 2014-09-06 17:25:44 +02:00
Andreas Lubbe
781ea22d57 always wrap 'yield' in () to allow composability with all other operators 2014-09-06 17:12:25 +02:00
Andreas Lubbe
437b9ed65c added 'yield return' 2014-09-06 15:40:53 +02:00
Andreas Lubbe
c72556619f added 'yield from' 2014-09-06 13:53:21 +02:00
Andreas Lubbe
565d78f00b removed support for '->*" and '=>*' 2014-09-06 13:38:04 +02:00
Andreas Lubbe
75900660fd Merge remote-tracking branch 'A/master' 2014-09-06 11:32:25 +02:00
Michael Ficarra
b407a59baf Merge pull request #3618 from josh/update-site-example-projects
Refresh site Examples section
2014-08-28 00:40:35 -04:00
Joshua Peek
9dfd71b0e4 Add Atom to Examples 2014-08-27 21:24:42 -07:00
Joshua Peek
872092f6de Remove josh/nack from Examples 2014-08-27 21:21:25 -07:00
Michael Ficarra
8b066f125d Merge pull request #3616 from epmatsw/spelling
Quick spelling fixes
2014-08-26 19:46:34 -07:00
Will Stamper
94c467b520 Quick spelling fixes 2014-08-26 20:41:32 -05:00
Jeremy Ashkenas
53aa50f785 merged 2014-08-26 12:28:39 -04:00
Nami-Doc
e8c96de269 Fix the "Examples" link on coffeescript.org
It now points to the "Trending repositories" of the month.
2014-07-23 22:21:14 +02:00
Nami-Doc
1157b32413 Update link to "CoffeeScript Ristretto", fixes #3489 2014-06-26 17:08:31 +02:00
G. Scott Olson
ba4157b5e2 Retina favicon.ico 2014-06-23 11:11:54 -04:00
Jeremy Ashkenas
6ae21ae461 merged 2014-05-08 15:09:40 -04:00
Andreas Lubbe
f375394381 Merge https://github.com/jashkenas/coffee-script
Conflicts:
	lib/coffee-script/lexer.js
	lib/coffee-script/parser.js
	lib/coffee-script/rewriter.js
	src/lexer.coffee
	src/rewriter.coffee
2014-01-25 19:37:35 -08:00
Andreas Lubbe
1e377ed59b 'yield*' now works as expected 2013-12-27 22:12:04 -08:00
Andreas Lubbe
64e78a2bec updated lexer to allow 'yield*' 2013-12-26 01:16:02 -08:00
Andreas Lubbe
25b1eee293 first attempt at including 'yield*' 2013-12-23 19:32:25 -08:00
Andreas Lubbe
dab4ae9416 '->*' and '=>*' now produce generators 2013-12-19 18:08:25 -08:00
Andreas Lubbe
56b04a58dc first attempt at using '->*" and '=>*' for generators 2013-12-19 14:21:14 -08:00
Andreas Lubbe
e1000205fd Merge github.com:jashkenas/coffee-script 2013-12-05 11:56:34 -08:00
Andreas Lubbe
c02a403f2e fixed misspelling in Cakefile 2013-12-04 21:49:17 -08:00
Andreas Lubbe
f4b850d59c further improved readability of cakefile generator check 2013-12-02 23:33:16 -08:00
Andreas Lubbe
85c7fffd1a improved readability of cakefile generator check 2013-11-30 20:51:53 -08:00
Andreas Lubbe
9d29a830df entire generator test file is now ignored if generators are not available 2013-11-30 12:26:32 -08:00
Andreas Lubbe
74a92db173 improved readability of generator test 2013-11-30 11:45:19 -08:00
Andreas Lubbe
d712a6c0f4 npm run-script test-harmony executes generator tests 2013-11-29 20:59:22 -08:00
Andreas Lubbe
7906a2b6c1 removed yield from the reserved words 2013-11-29 20:58:43 -08:00
Andreas Lubbe
f11ca9888f added a test for generators 2013-11-29 20:58:26 -08:00
Andreas Lubbe
9941050120 using 'yield' automatically turns functions into generators 2013-11-15 22:19:31 +01:00
Andreas Lubbe
dafc7bdea5 added 'yield' to the unary keywords 2013-11-15 22:16:28 +01:00
Andreas Lubbe
f51cbd7117 removed 'yield' from the reserved keywords 2013-11-15 22:15:31 +01:00
123 changed files with 6022 additions and 5507 deletions

View File

@@ -276,6 +276,12 @@ runTests = (CoffeeScript) ->
# Run every test in the `test` folder, recording failures.
files = fs.readdirSync 'test'
# Ignore generators test file if generators are not available
generatorsAreAvailable = '--harmony' in process.execArgv or
'--harmony-generators' in process.execArgv
files.splice files.indexOf('generators.coffee'), 1 if not generatorsAreAvailable
for file in files when helpers.isCoffee file
literate = helpers.isLiterate file
currentFile = filename = path.join 'test', file

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2014 Jeremy Ashkenas
Copyright (c) 2009-2015 Jeremy Ashkenas
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

27
bower.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "coffee-script",
"version": "1.9.1",
"main": [
"lib/coffee-script/coffee-script.js"
],
"description": "Unfancy JavaScript",
"keywords": [
"javascript",
"language",
"coffeescript",
"compiler"
],
"devDependencies": {
"uglify-js": "~2.2",
"jison": ">=0.2.0",
"highlight.js": "~8.0.0",
"underscore": "~1.5.2",
"docco": "~0.6.2"
},
"author": {
"name": "Jeremy Ashkenas"
},
"ignore": [
"test"
]
}

View File

@@ -0,0 +1,8 @@
perfectSquares = ->
num = 0
loop
num += 1
yield num * num
return
window.ps or= perfectSquares()

View File

@@ -144,7 +144,7 @@ SourceMap = <span class="hljs-built_in">require</span> <span class="hljs-str
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.VERSION = <span class="hljs-string">'1.8.0'</span>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.VERSION = <span class="hljs-string">'1.9.1'</span>
<span class="hljs-built_in">exports</span>.FILE_EXTENSIONS = [<span class="hljs-string">'.coffee'</span>, <span class="hljs-string">'.litcoffee'</span>, <span class="hljs-string">'.coffee.md'</span>]</pre></div></div>
@@ -210,7 +210,27 @@ lookups.</p>
<span class="hljs-keyword">if</span> options.sourceMap
map = <span class="hljs-keyword">new</span> SourceMap
fragments = parser.parse(lexer.tokenize code, options).compileToFragments options
tokens = lexer.tokenize code, options</pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">&#182;</a>
</div>
<p>Pass a list of referenced variables, so that generated variables wont get
the same name.</p>
</div>
<div class="content"><div class='highlight'><pre> options.referencedVars = (
token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token.variable
)
fragments = parser.parse(tokens).compileToFragments options
currentLine = <span class="hljs-number">0</span>
currentLine += <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> options.header
@@ -222,11 +242,11 @@ lookups.</p>
</li>
<li id="section-6">
<li id="section-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">&#182;</a>
<a class="pilcrow" href="#section-7">&#182;</a>
</div>
<p>Update the sourcemap with data from each fragment</p>
@@ -248,11 +268,11 @@ lookups.</p>
</li>
<li id="section-7">
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">&#182;</a>
<a class="pilcrow" href="#section-8">&#182;</a>
</div>
<p>Copy the code from each fragment into the final JavaScript.</p>
@@ -275,11 +295,11 @@ lookups.</p>
</li>
<li id="section-8">
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
<a class="pilcrow" href="#section-9">&#182;</a>
</div>
<p>Tokenize a string of CoffeeScript code, and return the array of tokens.</p>
@@ -291,11 +311,11 @@ lookups.</p>
</li>
<li id="section-9">
<li id="section-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</a>
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>Parse a string of CoffeeScript code or an array of lexed tokens, and
return the AST. You can then compile it by calling <code>.compile()</code> on the root,
@@ -312,11 +332,11 @@ or traverse it by using <code>.traverseChildren()</code> with a callback.</p>
</li>
<li id="section-10">
<li id="section-11">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
<a class="pilcrow" href="#section-11">&#182;</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>
@@ -329,11 +349,11 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
</li>
<li id="section-11">
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#182;</a>
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>Set the filename.</p>
@@ -345,11 +365,11 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
</li>
<li id="section-12">
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>Clear the module cache.</p>
@@ -360,11 +380,11 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
</li>
<li id="section-13">
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
<a class="pilcrow" href="#section-14">&#182;</a>
</div>
<p>Assign paths for node_modules loading</p>
@@ -379,11 +399,11 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
</li>
<li id="section-14">
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
<a class="pilcrow" href="#section-15">&#182;</a>
</div>
<p>Compile.</p>
@@ -398,11 +418,11 @@ setting <code>__filename</code>, <code>__dirname</code>, and relative <code>requ
</li>
<li id="section-15">
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>Compile and evaluate a string of CoffeeScript (in a Node.js-like environment).
The CoffeeScript REPL uses this to run the input.</p>
@@ -411,13 +431,17 @@ The CoffeeScript REPL uses this to run the input.</p>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.<span class="hljs-function"><span class="hljs-title">eval</span> = <span class="hljs-params">(code, options = {})</span> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> code = code.trim()
Script = vm.Script
<span class="hljs-keyword">if</span> Script
createContext = vm.Script.createContext ? vm.createContext
isContext = vm.isContext ? <span class="hljs-function"><span class="hljs-params">(ctx)</span> -&gt;</span>
options.sandbox <span class="hljs-keyword">instanceof</span> createContext().constructor
<span class="hljs-keyword">if</span> createContext
<span class="hljs-keyword">if</span> options.sandbox?
<span class="hljs-keyword">if</span> options.sandbox <span class="hljs-keyword">instanceof</span> Script.createContext().constructor
<span class="hljs-keyword">if</span> isContext options.sandbox
sandbox = options.sandbox
<span class="hljs-keyword">else</span>
sandbox = Script.createContext()
sandbox = createContext()
sandbox[k] = v <span class="hljs-keyword">for</span> own k, v <span class="hljs-keyword">of</span> options.sandbox
sandbox.<span class="hljs-built_in">global</span> = sandbox.root = sandbox.GLOBAL = sandbox
<span class="hljs-keyword">else</span>
@@ -428,11 +452,11 @@ The CoffeeScript REPL uses this to run the input.</p>
</li>
<li id="section-16">
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>define module/require only if they chose not to specify their own</p>
@@ -448,11 +472,11 @@ The CoffeeScript REPL uses this to run the input.</p>
</li>
<li id="section-17">
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<p>use the same hack node currently uses for their own REPL</p>
@@ -474,11 +498,11 @@ The CoffeeScript REPL uses this to run the input.</p>
</li>
<li id="section-18">
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>Throw error with deprecation warning when depending upon implicit <code>require.extensions</code> registration</p>
@@ -502,11 +526,11 @@ The CoffeeScript REPL uses this to run the input.</p>
</li>
<li id="section-19">
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>As the filename and code of a dynamically loaded file will be different
from the original file compiled with CoffeeScript.run, add that
@@ -521,11 +545,11 @@ information to error so it can be pretty-printed later.</p>
</li>
<li id="section-20">
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>Instantiate a Lexer for our use here.</p>
@@ -536,11 +560,11 @@ information to error so it can be pretty-printed later.</p>
</li>
<li id="section-21">
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>The real Lexer produces a generic stream of tokens. This object provides a
thin wrapper around it, compatible with the Jison API. We can then pass it
@@ -550,16 +574,17 @@ directly as a “Jison lexer”.</p>
<div class="content"><div class='highlight'><pre>parser.lexer =
<span class="hljs-attribute">lex</span>:<span class="hljs-function"> -&gt;</span>
token = <span class="hljs-property">@tokens</span>[<span class="hljs-property">@pos</span>++]
token = parser.tokens[<span class="hljs-property">@pos</span>++]
<span class="hljs-keyword">if</span> token
[tag, <span class="hljs-property">@yytext</span>, <span class="hljs-property">@yylloc</span>] = token
<span class="hljs-property">@errorToken</span> = token.origin <span class="hljs-keyword">or</span> token
parser.errorToken = token.origin <span class="hljs-keyword">or</span> token
<span class="hljs-property">@yylineno</span> = <span class="hljs-property">@yylloc</span>.first_line
<span class="hljs-keyword">else</span>
tag = <span class="hljs-string">''</span>
tag
<span class="hljs-attribute">setInput</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@tokens</span>)</span> -&gt;</span>
<span class="hljs-attribute">setInput</span>: <span class="hljs-function"><span class="hljs-params">(tokens)</span> -&gt;</span>
parser.tokens = tokens
<span class="hljs-property">@pos</span> = <span class="hljs-number">0</span>
<span class="hljs-attribute">upcomingInput</span>:<span class="hljs-function"> -&gt;</span>
<span class="hljs-string">""</span></pre></div></div>
@@ -567,32 +592,17 @@ directly as a “Jison lexer”.</p>
</li>
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>Make all the AST nodes visible to the parser.</p>
</div>
<div class="content"><div class='highlight'><pre>parser.yy = <span class="hljs-built_in">require</span> <span class="hljs-string">'./nodes'</span></pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>Override Jisons default error handling function.</p>
<p>Make all the AST nodes visible to the parser.</p>
</div>
<div class="content"><div class='highlight'><pre>parser.yy.<span class="hljs-function"><span class="hljs-title">parseError</span> = <span class="hljs-params">(message, {token})</span> -&gt;</span></pre></div></div>
<div class="content"><div class='highlight'><pre>parser.yy = <span class="hljs-built_in">require</span> <span class="hljs-string">'./nodes'</span></pre></div></div>
</li>
@@ -603,21 +613,11 @@ directly as a “Jison lexer”.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>Disregard Jisons message, it contains redundant line numer information.
Disregard the token, we take its value directly from the lexer in case
the error is caused by a generated token which might refer to its origin.</p>
<p>Override Jisons default error handling function.</p>
</div>
<div class="content"><div class='highlight'><pre> {errorToken, tokens} = parser.lexer
[errorTag, errorText, errorLoc] = errorToken
errorText = <span class="hljs-keyword">if</span> errorToken <span class="hljs-keyword">is</span> tokens[tokens.length - <span class="hljs-number">1</span>]
<span class="hljs-string">'end of input'</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'OUTDENT'</span>]
<span class="hljs-string">'indentation'</span>
<span class="hljs-keyword">else</span>
helpers.nameWhitespaceCharacter errorText</pre></div></div>
<div class="content"><div class='highlight'><pre>parser.yy.<span class="hljs-function"><span class="hljs-title">parseError</span> = <span class="hljs-params">(message, {token})</span> -&gt;</span></pre></div></div>
</li>
@@ -628,6 +628,34 @@ the error is caused by a generated token which might refer to its origin.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>Disregard Jisons message, it contains redundant line numer information.
Disregard the token, we take its value directly from the lexer in case
the error is caused by a generated token which might refer to its origin.</p>
</div>
<div class="content"><div class='highlight'><pre> {errorToken, tokens} = parser
[errorTag, errorText, errorLoc] = errorToken
errorText = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> errorToken <span class="hljs-keyword">is</span> tokens[tokens.length - <span class="hljs-number">1</span>]
<span class="hljs-string">'end of input'</span>
<span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'OUTDENT'</span>]
<span class="hljs-string">'indentation'</span>
<span class="hljs-keyword">when</span> errorTag <span class="hljs-keyword">in</span> [<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'STRING_START'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'REGEX_START'</span>]
errorTag.replace(<span class="hljs-regexp">/_START$/</span>, <span class="hljs-string">''</span>).toLowerCase()
<span class="hljs-keyword">else</span>
helpers.nameWhitespaceCharacter errorText</pre></div></div>
</li>
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#182;</a>
</div>
<p>The second argument has a <code>loc</code> property, which should have the location
data for this token. Unfortunately, Jison seems to send an outdated <code>loc</code>
(from the previous token), so we take the location information directly
@@ -640,11 +668,11 @@ from the lexer.</p>
</li>
<li id="section-26">
<li id="section-27">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#182;</a>
<a class="pilcrow" href="#section-27">&#182;</a>
</div>
<p>Based on <a href="http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js">http://v8.googlecode.com/svn/branches/bleeding_edge/src/messages.js</a>
Modified to handle sourceMap</p>
@@ -672,11 +700,11 @@ Modified to handle sourceMap</p>
</li>
<li id="section-27">
<li id="section-28">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-27">&#182;</a>
<a class="pilcrow" href="#section-28">&#182;</a>
</div>
<p>Check for a sourceMap position</p>
@@ -717,11 +745,11 @@ Modified to handle sourceMap</p>
</li>
<li id="section-28">
<li id="section-29">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">&#182;</a>
<a class="pilcrow" href="#section-29">&#182;</a>
</div>
<p>Map of filenames -&gt; sourceMap object.</p>
@@ -732,11 +760,11 @@ Modified to handle sourceMap</p>
</li>
<li id="section-29">
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-29">&#182;</a>
<a class="pilcrow" href="#section-30">&#182;</a>
</div>
<p>Generates the source map for a coffee file and stores it in the local cache variable.</p>
@@ -751,11 +779,11 @@ Modified to handle sourceMap</p>
</li>
<li id="section-30">
<li id="section-31">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">&#182;</a>
<a class="pilcrow" href="#section-31">&#182;</a>
</div>
<p>Based on <a href="http://goo.gl/ZTx1p">michaelficarra/CoffeeScriptRedux</a>
NodeJS / V8 have no support for transforming positions in stack traces using

View File

@@ -141,7 +141,6 @@ path = <span class="hljs-built_in">require</span> <span class="hljs-st
helpers = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span>
optparse = <span class="hljs-built_in">require</span> <span class="hljs-string">'./optparse'</span>
CoffeeScript = <span class="hljs-built_in">require</span> <span class="hljs-string">'./coffee-script'</span>
mkdirp = <span class="hljs-built_in">require</span> <span class="hljs-string">'mkdirp'</span>
{spawn, exec} = <span class="hljs-built_in">require</span> <span class="hljs-string">'child_process'</span>
{EventEmitter} = <span class="hljs-built_in">require</span> <span class="hljs-string">'events'</span>
@@ -237,7 +236,8 @@ sources = []
sourceCode = []
notSources = {}
watchedDirs = {}
optionParser = <span class="hljs-literal">null</span></pre></div></div>
optionParser = <span class="hljs-literal">null</span>
jsToSources = {}</pre></div></div>
</li>
@@ -639,6 +639,32 @@ the compiled JS version as well.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>Recursively mkdir, like <code>mkdir -p</code>.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">mkdirp</span> = <span class="hljs-params">(dir, fn)</span> -&gt;</span>
mode = <span class="hljs-number">0</span>o777 &amp; ~process.umask()
<span class="hljs-keyword">do</span> <span class="hljs-function"><span class="hljs-title">mkdirs</span> = <span class="hljs-params">(p = dir, fn)</span> -&gt;</span>
fs.exists p, <span class="hljs-function"><span class="hljs-params">(exists)</span> -&gt;</span>
<span class="hljs-keyword">if</span> exists
fn()
<span class="hljs-keyword">else</span>
mkdirs path.dirname(p),<span class="hljs-function"> -&gt;</span>
fs.mkdir p, mode, <span class="hljs-function"><span class="hljs-params">(err)</span> -&gt;</span>
<span class="hljs-keyword">return</span> fn err <span class="hljs-keyword">if</span> err
fn()</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</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>
@@ -650,6 +676,12 @@ same directory as the <code>.js</code> file.</p>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">writeJs</span> = <span class="hljs-params">(base, sourcePath, js, jsPath, generatedSourceMap = <span class="hljs-literal">null</span>)</span> -&gt;</span>
sourceMapPath = outputPath sourcePath, base, <span class="hljs-string">".js.map"</span>
jsDir = path.dirname jsPath
<span class="hljs-keyword">if</span> jsPath <span class="hljs-keyword">of</span> jsToSources
printLine <span class="hljs-string">"Error: The two following source files have the same output file:"</span>
printLine <span class="hljs-string">" "</span> + jsToSources[jsPath]
printLine <span class="hljs-string">" "</span> + sourcePath
process.exit <span class="hljs-number">1</span>
jsToSources[jsPath] = sourcePath
<span class="hljs-function"><span class="hljs-title">compile</span> = -&gt;</span>
<span class="hljs-keyword">if</span> opts.compile
js = <span class="hljs-string">' '</span> <span class="hljs-keyword">if</span> js.length &lt;= <span class="hljs-number">0</span>
@@ -671,11 +703,11 @@ same directory as the <code>.js</code> file.</p>
</li>
<li id="section-18">
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>Convenience for cleaner setTimeouts.</p>
@@ -686,11 +718,11 @@ same directory as the <code>.js</code> file.</p>
</li>
<li id="section-19">
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>When watching scripts, its useful to log changes with the timestamp.</p>
@@ -702,11 +734,11 @@ same directory as the <code>.js</code> file.</p>
</li>
<li id="section-20">
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>Pretty-print a stream of tokens, sans location data.</p>
@@ -722,11 +754,11 @@ same directory as the <code>.js</code> file.</p>
</li>
<li id="section-21">
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>Use the <a href="optparse.html">OptionParser module</a> to extract all options from
<code>process.argv</code> that are specified in <code>SWITCHES</code>.</p>
@@ -743,11 +775,11 @@ same directory as the <code>.js</code> file.</p>
</li>
<li id="section-22">
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>The compile-time options to pass to the CoffeeScript compiler.</p>
@@ -782,11 +814,11 @@ same directory as the <code>.js</code> file.</p>
</li>
<li id="section-23">
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>Start up a new Node.js instance with the arguments in <code>--nodejs</code> passed to
the <code>node</code> binary, preserving the other options.</p>
@@ -806,11 +838,11 @@ the <code>node</code> binary, preserving the other options.</p>
</li>
<li id="section-24">
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>Print the <code>--help</code> usage message and exit. Deprecated switches are not
shown.</p>
@@ -823,11 +855,11 @@ shown.</p>
</li>
<li id="section-25">
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
<a class="pilcrow" href="#section-26">&#182;</a>
</div>
<p>Print the <code>--version</code> message and exit.</p>

View File

@@ -21,11 +21,11 @@
}
@font-face {
font-family: 'novecento-bold';
src: url('public/fonts/novecento-bold.eot');
src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
url('public/fonts/novecento-bold.woff') format('woff'),
url('public/fonts/novecento-bold.ttf') format('truetype');
font-family: 'roboto-black';
src: url('public/fonts/roboto-black.eot');
src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'),
url('public/fonts/roboto-black.woff') format('woff'),
url('public/fonts/roboto-black.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@@ -67,7 +67,7 @@ h1, h2, h3, h4, h5, h6 {
color: #112233;
line-height: 1em;
font-weight: normal;
font-family: "novecento-bold";
font-family: "roboto-black";
text-transform: uppercase;
margin: 30px 0 15px 0;
}
@@ -75,6 +75,9 @@ h1, h2, h3, h4, h5, h6 {
h1 {
margin-top: 40px;
}
h2 {
font-size: 1.26em;
}
hr {
border: 0;

View File

@@ -460,7 +460,17 @@ they can also serve as keys in object literals.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">AlphaNumeric</span>: [
o <span class="hljs-string">'NUMBER'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>
o <span class="hljs-string">'String'</span>
]
<span class="hljs-attribute">String</span>: [
o <span class="hljs-string">'STRING'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>
o <span class="hljs-string">'STRING_START Body STRING_END'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Parens $<span class="hljs-number">2</span>
]
<span class="hljs-attribute">Regex</span>: [
o <span class="hljs-string">'REGEX'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>
o <span class="hljs-string">'REGEX_START Invocation REGEX_END'</span>,<span class="hljs-function"> -&gt;</span> $<span class="hljs-number">2</span>
]</pre></div></div>
</li>
@@ -480,7 +490,7 @@ through and printed to JavaScript.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">Literal</span>: [
o <span class="hljs-string">'AlphaNumeric'</span>
o <span class="hljs-string">'JS'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>
o <span class="hljs-string">'REGEX'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>
o <span class="hljs-string">'Regex'</span>
o <span class="hljs-string">'DEBUGGER'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Literal $<span class="hljs-number">1</span>
o <span class="hljs-string">'UNDEFINED'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Undefined
o <span class="hljs-string">'NULL'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Null
@@ -1247,7 +1257,8 @@ or postfix, with a single expression.</p>
]
<span class="hljs-attribute">ForBody</span>: [
o <span class="hljs-string">'FOR Range'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-attribute">source</span>: LOC(<span class="hljs-number">2</span>) <span class="hljs-keyword">new</span> Value($<span class="hljs-number">2</span>)
o <span class="hljs-string">'FOR Range'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-attribute">source</span>: (LOC(<span class="hljs-number">2</span>) <span class="hljs-keyword">new</span> Value($<span class="hljs-number">2</span>))
o <span class="hljs-string">'FOR Range BY Expression'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-attribute">source</span>: (LOC(<span class="hljs-number">2</span>) <span class="hljs-keyword">new</span> Value($<span class="hljs-number">2</span>)), <span class="hljs-attribute">step</span>: $<span class="hljs-number">4</span>
o <span class="hljs-string">'ForStart ForSource'</span>,<span class="hljs-function"> -&gt;</span> $<span class="hljs-number">2.</span>own = $<span class="hljs-number">1.</span>own; $<span class="hljs-number">2.</span>name = $<span class="hljs-number">1</span>[<span class="hljs-number">0</span>]; $<span class="hljs-number">2.</span>index = $<span class="hljs-number">1</span>[<span class="hljs-number">1</span>]; $<span class="hljs-number">2</span>
]
@@ -1416,6 +1427,9 @@ rules are necessary.</p>
o <span class="hljs-string">'UNARY_MATH Expression'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span> , $<span class="hljs-number">2</span>
o <span class="hljs-string">'- Expression'</span>, (<span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'-'</span>, $<span class="hljs-number">2</span>), <span class="hljs-attribute">prec</span>: <span class="hljs-string">'UNARY_MATH'</span>
o <span class="hljs-string">'+ Expression'</span>, (<span class="hljs-function">-&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'+'</span>, $<span class="hljs-number">2</span>), <span class="hljs-attribute">prec</span>: <span class="hljs-string">'UNARY_MATH'</span>
o <span class="hljs-string">'YIELD Statement'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span> , $<span class="hljs-number">2</span>
o <span class="hljs-string">'YIELD Expression'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1</span> , $<span class="hljs-number">2</span>
o <span class="hljs-string">'YIELD FROM Expression'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Op $<span class="hljs-number">1.</span>concat($<span class="hljs-number">2</span>) , $<span class="hljs-number">3</span>
o <span class="hljs-string">'-- SimpleAssignable'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'--'</span>, $<span class="hljs-number">2</span>
o <span class="hljs-string">'++ SimpleAssignable'</span>,<span class="hljs-function"> -&gt;</span> <span class="hljs-keyword">new</span> Op <span class="hljs-string">'++'</span>, $<span class="hljs-number">2</span>
@@ -1517,6 +1531,7 @@ down. Following these rules is what makes <code>2 + 3 * 4</code> parse as:</p>
[<span class="hljs-string">'left'</span>, <span class="hljs-string">'COMPARE'</span>]
[<span class="hljs-string">'left'</span>, <span class="hljs-string">'LOGIC'</span>]
[<span class="hljs-string">'nonassoc'</span>, <span class="hljs-string">'INDENT'</span>, <span class="hljs-string">'OUTDENT'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'YIELD'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">':'</span>, <span class="hljs-string">'COMPOUND_ASSIGN'</span>, <span class="hljs-string">'RETURN'</span>, <span class="hljs-string">'THROW'</span>, <span class="hljs-string">'EXTENDS'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'FORIN'</span>, <span class="hljs-string">'FOROF'</span>, <span class="hljs-string">'BY'</span>, <span class="hljs-string">'WHEN'</span>]
[<span class="hljs-string">'right'</span>, <span class="hljs-string">'IF'</span>, <span class="hljs-string">'ELSE'</span>, <span class="hljs-string">'FOR'</span>, <span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'UNTIL'</span>, <span class="hljs-string">'LOOP'</span>, <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'CLASS'</span>]

View File

@@ -311,21 +311,6 @@ looking for a particular method in an options hash.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>Gets the last item of an array(-like) object.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.last = <span class="hljs-function"><span class="hljs-title">last</span> = <span class="hljs-params">(array, back)</span> -&gt;</span> array[array.length - (back <span class="hljs-keyword">or</span> <span class="hljs-number">0</span>) - <span class="hljs-number">1</span>]</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>Typical Array::some</p>
</div>
@@ -337,11 +322,11 @@ looking for a particular method in an options hash.</p>
</li>
<li id="section-14">
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>Simple function for inverting Literate CoffeeScript code by putting the
documentation in comments, producing a string of CoffeeScript code that
@@ -363,11 +348,11 @@ can be compiled “normally”.</p>
</li>
<li id="section-15">
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
<a class="pilcrow" href="#section-14">&#182;</a>
</div>
<p>Merge two jison-style location data objects together.
If <code>last</code> is not provided, this will simply return <code>first</code>.</p>
@@ -386,11 +371,11 @@ If <code>last</code> is not provided, this will simply return <code>first</code>
</li>
<li id="section-16">
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
<a class="pilcrow" href="#section-15">&#182;</a>
</div>
<p>This returns a function which takes an object as a parameter, and if that
object is an AST node, updates that objects locationData.
@@ -408,11 +393,11 @@ The object is returned either way.</p>
</li>
<li id="section-17">
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>Convert jison location data to a string.
<code>obj</code> can be a token, or a locationData.</p>
@@ -432,11 +417,11 @@ The object is returned either way.</p>
</li>
<li id="section-18">
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>A <code>.coffee.md</code> compatible version of <code>basename</code>, that returns the file sans-extension.</p>
@@ -455,11 +440,11 @@ The object is returned either way.</p>
</li>
<li id="section-19">
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<p>Determine if a filename represents a CoffeeScript file.</p>
@@ -470,11 +455,11 @@ The object is returned either way.</p>
</li>
<li id="section-20">
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>Determine if a filename represents a Literate CoffeeScript file.</p>
@@ -485,11 +470,11 @@ The object is returned either way.</p>
</li>
<li id="section-21">
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>Throws a SyntaxError from a given location.
The errors <code>toString</code> will return an error message following the “standard”
@@ -506,11 +491,11 @@ marker showing where the error is.</p>
</li>
<li id="section-22">
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>Instead of showing the compilers stacktrace, show our custom error message
(this is useful when the error bubbles up in Node.js applications that
@@ -525,11 +510,11 @@ compile CoffeeScript for example).</p>
</li>
<li id="section-23">
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>Update a compiler SyntaxError with source code information if it didnt have
it already.</p>
@@ -541,11 +526,11 @@ it already.</p>
</li>
<li id="section-24">
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>Avoid screwing up the <code>stack</code> property of other errors (i.e. possible bugs).</p>
@@ -571,11 +556,11 @@ it already.</p>
</li>
<li id="section-25">
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">&#182;</a>
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>Show only the first line on multi-line errors.</p>
@@ -587,11 +572,11 @@ it already.</p>
</li>
<li id="section-26">
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">&#182;</a>
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>Check to see if were running on a color-enabled TTY.</p>

File diff suppressed because it is too large Load Diff

View File

@@ -141,7 +141,7 @@ Error.stackTraceLimit = Infinity
</div>
<div class="content"><div class='highlight'><pre>{compact, flatten, extend, merge, del, starts, ends, last, some,
<div class="content"><div class='highlight'><pre>{compact, flatten, extend, merge, del, starts, ends, some,
addLocationDataFn, locationDataToString, throwSyntaxError} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span></pre></div></div>
</li>
@@ -327,7 +327,11 @@ object with their parent closure, to preserve the expected lexical scope.</p>
<span class="hljs-keyword">else</span>
meth = <span class="hljs-string">'call'</span>
func = <span class="hljs-keyword">new</span> Value func, [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal meth]
(<span class="hljs-keyword">new</span> Call func, args).compileNode o</pre></div></div>
parts = (<span class="hljs-keyword">new</span> Call func, args).compileNode o
<span class="hljs-keyword">if</span> func.isGenerator
parts.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"(yield* "</span>
parts.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">")"</span>
parts</pre></div></div>
</li>
@@ -347,14 +351,15 @@ the two values are raw nodes which have not been compiled.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">cache</span>: <span class="hljs-function"><span class="hljs-params">(o, level, reused)</span> -&gt;</span>
<span class="hljs-keyword">unless</span> <span class="hljs-property">@isComplex</span>()
ref = <span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> <span class="hljs-property">@compileToFragments</span> o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span>
[ref, ref]
<span class="hljs-keyword">else</span>
ref = <span class="hljs-keyword">new</span> Literal reused <span class="hljs-keyword">or</span> o.scope.freeVariable <span class="hljs-string">'ref'</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">cache</span>: <span class="hljs-function"><span class="hljs-params">(o, level, isComplex)</span> -&gt;</span>
complex = <span class="hljs-keyword">if</span> isComplex? <span class="hljs-keyword">then</span> isComplex <span class="hljs-keyword">this</span> <span class="hljs-keyword">else</span> <span class="hljs-property">@isComplex</span>()
<span class="hljs-keyword">if</span> complex
ref = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'ref'</span>
sub = <span class="hljs-keyword">new</span> Assign ref, <span class="hljs-keyword">this</span>
<span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> [sub.compileToFragments(o, level), [<span class="hljs-property">@makeCode</span>(ref.value)]] <span class="hljs-keyword">else</span> [sub, ref]
<span class="hljs-keyword">else</span>
ref = <span class="hljs-keyword">if</span> level <span class="hljs-keyword">then</span> <span class="hljs-property">@compileToFragments</span> o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">this</span>
[ref, ref]
<span class="hljs-attribute">cacheToCodeFragments</span>: <span class="hljs-function"><span class="hljs-params">(cacheValues)</span> -&gt;</span>
[fragmentsToText(cacheValues[<span class="hljs-number">0</span>]), fragmentsToText(cacheValues[<span class="hljs-number">1</span>])]</pre></div></div>
@@ -829,7 +834,7 @@ clean up obvious double-parentheses.</p>
o.indent = <span class="hljs-keyword">if</span> o.bare <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> TAB
o.level = LEVEL_TOP
<span class="hljs-property">@spaced</span> = <span class="hljs-literal">yes</span>
o.scope = <span class="hljs-keyword">new</span> Scope <span class="hljs-literal">null</span>, <span class="hljs-keyword">this</span>, <span class="hljs-literal">null</span></pre></div></div>
o.scope = <span class="hljs-keyword">new</span> Scope <span class="hljs-literal">null</span>, <span class="hljs-keyword">this</span>, <span class="hljs-literal">null</span>, o.referencedVars ? []</pre></div></div>
</li>
@@ -1043,7 +1048,8 @@ make sense.</p>
<span class="hljs-keyword">if</span> expr <span class="hljs-keyword">and</span> expr <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Return <span class="hljs-keyword">then</span> expr.compileToFragments o, level <span class="hljs-keyword">else</span> <span class="hljs-keyword">super</span> o, level
<span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
answer = []</pre></div></div>
answer = []
exprIsYieldReturn = <span class="hljs-property">@expression</span>?.isYieldReturn?()</pre></div></div>
</li>
@@ -1058,10 +1064,11 @@ make sense.</p>
</div>
<div class="content"><div class='highlight'><pre> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-property">@tab</span> + <span class="hljs-string">"return<span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-property">@expression</span> <span class="hljs-keyword">then</span> <span class="hljs-string">" "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>}</span>"</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">unless</span> exprIsYieldReturn
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-property">@tab</span> + <span class="hljs-string">"return<span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-property">@expression</span> <span class="hljs-keyword">then</span> <span class="hljs-string">" "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>}</span>"</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@expression</span>
answer = answer.concat <span class="hljs-property">@expression</span>.compileToFragments o, LEVEL_PAREN
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">";"</span>
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">";"</span> <span class="hljs-keyword">unless</span> exprIsYieldReturn
<span class="hljs-keyword">return</span> answer</pre></div></div>
</li>
@@ -1161,10 +1168,11 @@ or vanilla.</p>
(<span class="hljs-property">@base</span> <span class="hljs-keyword">instanceof</span> Obj) <span class="hljs-keyword">and</span> (<span class="hljs-keyword">not</span> onlyGenerated <span class="hljs-keyword">or</span> <span class="hljs-property">@base</span>.generated)
<span class="hljs-attribute">isSplice</span>:<span class="hljs-function"> -&gt;</span>
last(<span class="hljs-property">@properties</span>) <span class="hljs-keyword">instanceof</span> Slice
[..., lastProp] = <span class="hljs-property">@properties</span>
lastProp <span class="hljs-keyword">instanceof</span> Slice
<span class="hljs-attribute">looksStatic</span>: <span class="hljs-function"><span class="hljs-params">(className)</span> -&gt;</span>
<span class="hljs-property">@base</span>.value <span class="hljs-keyword">is</span> className <span class="hljs-keyword">and</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">and</span>
<span class="hljs-property">@base</span>.value <span class="hljs-keyword">is</span> className <span class="hljs-keyword">and</span> <span class="hljs-property">@properties</span>.length <span class="hljs-keyword">is</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span>
<span class="hljs-property">@properties</span>[<span class="hljs-number">0</span>].name?.value <span class="hljs-keyword">isnt</span> <span class="hljs-string">'prototype'</span></pre></div></div>
</li>
@@ -1200,7 +1208,7 @@ We cache them separately for compiling complex expressions.
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">cacheReference</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
name = last <span class="hljs-property">@properties</span>
[..., name] = <span class="hljs-property">@properties</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@properties</span>.length &lt; <span class="hljs-number">2</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@base</span>.isComplex() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> name?.isComplex()
<span class="hljs-keyword">return</span> [<span class="hljs-keyword">this</span>, <span class="hljs-keyword">this</span>] <span class="hljs-comment"># `a` `a.b`</span>
base = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@base</span>, <span class="hljs-property">@properties</span>[...-<span class="hljs-number">1</span>]
@@ -1303,7 +1311,7 @@ at the same position.</p>
<span class="hljs-attribute">makeReturn</span>: THIS
<span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o, level)</span> -&gt;</span>
comment = <span class="hljs-property">@comment</span>.replace <span class="hljs-regexp">/^(\s*)#/gm</span>, <span class="hljs-string">"$1 *"</span>
comment = <span class="hljs-property">@comment</span>.replace <span class="hljs-regexp">/^(\s*)# /gm</span>, <span class="hljs-string">"$1 * "</span>
code = <span class="hljs-string">"/*<span class="hljs-subst">#{multident comment, <span class="hljs-property">@tab</span>}</span><span class="hljs-subst">#{<span class="hljs-keyword">if</span> <span class="hljs-string">'\n'</span> <span class="hljs-keyword">in</span> comment <span class="hljs-keyword">then</span> <span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>"</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>}</span> */"</span>
code = o.indent + code <span class="hljs-keyword">if</span> (level <span class="hljs-keyword">or</span> o.level) <span class="hljs-keyword">is</span> LEVEL_TOP
[<span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>), <span class="hljs-property">@makeCode</span>(code)]</pre></div></div>
@@ -1383,10 +1391,21 @@ method.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">superReference</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
method = o.scope.namedMethod()
<span class="hljs-keyword">if</span> method?.klass
accesses = [<span class="hljs-keyword">new</span> Access(<span class="hljs-keyword">new</span> Literal <span class="hljs-string">'__super__'</span>)]
{klass, name, variable} = method
<span class="hljs-keyword">if</span> klass.isComplex()
bref = <span class="hljs-keyword">new</span> Literal o.scope.parent.freeVariable <span class="hljs-string">'base'</span>
base = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Parens <span class="hljs-keyword">new</span> Assign bref, klass
variable.base = base
variable.properties.splice <span class="hljs-number">0</span>, klass.properties.length
<span class="hljs-keyword">if</span> name.isComplex() <span class="hljs-keyword">or</span> (name <span class="hljs-keyword">instanceof</span> Index <span class="hljs-keyword">and</span> name.index.isAssignable())
nref = <span class="hljs-keyword">new</span> Literal o.scope.parent.freeVariable <span class="hljs-string">'name'</span>
name = <span class="hljs-keyword">new</span> Index <span class="hljs-keyword">new</span> Assign nref, name.index
variable.properties.pop()
variable.properties.push name
accesses = [<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'__super__'</span>]
accesses.push <span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'constructor'</span> <span class="hljs-keyword">if</span> method.static
accesses.push <span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal method.name
(<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal method.klass), accesses).compile o
accesses.push <span class="hljs-keyword">if</span> nref? <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Index nref <span class="hljs-keyword">else</span> name
(<span class="hljs-keyword">new</span> Value bref ? klass, accesses).compile o
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> method?.ctor
<span class="hljs-string">"<span class="hljs-subst">#{method.name}</span>.__super__.constructor"</span>
<span class="hljs-keyword">else</span>
@@ -1588,7 +1607,7 @@ After <code>goog.inherits</code> from the
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileToFragments</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">new</span> Call(<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'extends'</span>), [<span class="hljs-property">@child</span>, <span class="hljs-property">@parent</span>]).compileToFragments o</pre></div></div>
<span class="hljs-keyword">new</span> Call(<span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'extend'</span>, o), [<span class="hljs-property">@child</span>, <span class="hljs-property">@parent</span>]).compileToFragments o</pre></div></div>
</li>
@@ -1724,9 +1743,10 @@ But only if they need to be cached to avoid double evaluation.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileVariables</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
o = merge o, <span class="hljs-attribute">top</span>: <span class="hljs-literal">true</span>
[<span class="hljs-property">@fromC</span>, <span class="hljs-property">@fromVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@from</span>.cache o, LEVEL_LIST
[<span class="hljs-property">@toC</span>, <span class="hljs-property">@toVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@to</span>.cache o, LEVEL_LIST
[<span class="hljs-property">@step</span>, <span class="hljs-property">@stepVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> step.cache o, LEVEL_LIST <span class="hljs-keyword">if</span> step = del o, <span class="hljs-string">'step'</span>
isComplex = del o, <span class="hljs-string">'isComplex'</span>
[<span class="hljs-property">@fromC</span>, <span class="hljs-property">@fromVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@from</span>.cache o, LEVEL_LIST, isComplex
[<span class="hljs-property">@toC</span>, <span class="hljs-property">@toVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@to</span>.cache o, LEVEL_LIST, isComplex
[<span class="hljs-property">@step</span>, <span class="hljs-property">@stepVar</span>] = <span class="hljs-property">@cacheToCodeFragments</span> step.cache o, LEVEL_LIST, isComplex <span class="hljs-keyword">if</span> step = del o, <span class="hljs-string">'step'</span>
[<span class="hljs-property">@fromNum</span>, <span class="hljs-property">@toNum</span>] = [<span class="hljs-property">@fromVar</span>.match(NUMBER), <span class="hljs-property">@toVar</span>.match(NUMBER)]
<span class="hljs-property">@stepNum</span> = <span class="hljs-property">@stepVar</span>.match(NUMBER) <span class="hljs-keyword">if</span> <span class="hljs-property">@stepVar</span></pre></div></div>
@@ -1855,7 +1875,7 @@ needed to iterate over the values in the range. Used by comprehensions.</p>
range.pop() <span class="hljs-keyword">if</span> <span class="hljs-property">@exclusive</span>
<span class="hljs-keyword">return</span> [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"[<span class="hljs-subst">#{ range.join(<span class="hljs-string">', '</span>) }</span>]"</span>]
idt = <span class="hljs-property">@tab</span> + TAB
i = o.scope.freeVariable <span class="hljs-string">'i'</span>
i = o.scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span>
result = o.scope.freeVariable <span class="hljs-string">'results'</span>
pre = <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{result}</span> = [];"</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@fromNum</span> <span class="hljs-keyword">and</span> <span class="hljs-property">@toNum</span>
@@ -1984,35 +2004,54 @@ is the index of the beginning.</p>
<span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
props = <span class="hljs-property">@properties</span>
<span class="hljs-keyword">return</span> [<span class="hljs-property">@makeCode</span>(<span class="hljs-keyword">if</span> <span class="hljs-property">@front</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'({})'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'{}'</span>)] <span class="hljs-keyword">unless</span> props.length
<span class="hljs-keyword">if</span> <span class="hljs-property">@generated</span>
<span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> node <span class="hljs-keyword">instanceof</span> Value
node.error <span class="hljs-string">'cannot have an implicit value in an implicit object'</span>
<span class="hljs-keyword">break</span> <span class="hljs-keyword">for</span> prop, dynamicIndex <span class="hljs-keyword">in</span> props <span class="hljs-keyword">when</span> (prop.variable <span class="hljs-keyword">or</span> prop).base <span class="hljs-keyword">instanceof</span> Parens
hasDynamic = dynamicIndex &lt; props.length
idt = o.indent += TAB
lastNoncom = <span class="hljs-property">@lastNonComment</span> <span class="hljs-property">@properties</span>
answer = []
<span class="hljs-keyword">if</span> hasDynamic
oref = o.scope.freeVariable <span class="hljs-string">'obj'</span>
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"(\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{oref}</span> = "</span>
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"{<span class="hljs-subst">#{<span class="hljs-keyword">if</span> props.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> dynamicIndex <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'}'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'\n'</span>}</span>"</span>
<span class="hljs-keyword">for</span> prop, i <span class="hljs-keyword">in</span> props
join = <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> props.length - <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> dynamicIndex
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n<span class="hljs-subst">#{idt}</span>}"</span> <span class="hljs-keyword">unless</span> i <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">',\n'</span>
join = <span class="hljs-keyword">if</span> i <span class="hljs-keyword">is</span> props.length - <span class="hljs-number">1</span> <span class="hljs-keyword">or</span> i <span class="hljs-keyword">is</span> dynamicIndex - <span class="hljs-number">1</span>
<span class="hljs-string">''</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">is</span> lastNoncom <span class="hljs-keyword">or</span> prop <span class="hljs-keyword">instanceof</span> Comment
<span class="hljs-string">'\n'</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">',\n'</span>
indent = <span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Comment <span class="hljs-keyword">then</span> <span class="hljs-string">''</span> <span class="hljs-keyword">else</span> idt
indent += TAB <span class="hljs-keyword">if</span> hasDynamic <span class="hljs-keyword">and</span> i &lt; dynamicIndex
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign <span class="hljs-keyword">and</span> prop.variable <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> prop.variable.hasProperties()
prop.variable.error <span class="hljs-string">'Invalid object key'</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> prop.<span class="hljs-keyword">this</span>
prop = <span class="hljs-keyword">new</span> Assign prop.properties[<span class="hljs-number">0</span>].name, prop, <span class="hljs-string">'object'</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Comment
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Assign
prop = <span class="hljs-keyword">new</span> Assign prop, prop, <span class="hljs-string">'object'</span>
(prop.variable.base <span class="hljs-keyword">or</span> prop.variable).asKey = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">if</span> i &lt; dynamicIndex
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Assign
prop = <span class="hljs-keyword">new</span> Assign prop, prop, <span class="hljs-string">'object'</span>
(prop.variable.base <span class="hljs-keyword">or</span> prop.variable).asKey = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">if</span> prop <span class="hljs-keyword">instanceof</span> Assign
key = prop.variable
value = prop.value
<span class="hljs-keyword">else</span>
[key, value] = prop.base.cache o
prop = <span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal oref), [<span class="hljs-keyword">new</span> Access key]), value
<span class="hljs-keyword">if</span> indent <span class="hljs-keyword">then</span> answer.push <span class="hljs-property">@makeCode</span> indent
answer.push prop.compileToFragments(o, LEVEL_TOP)...
<span class="hljs-keyword">if</span> join <span class="hljs-keyword">then</span> answer.push <span class="hljs-property">@makeCode</span> join
answer.unshift <span class="hljs-property">@makeCode</span> <span class="hljs-string">"{<span class="hljs-subst">#{ props.length <span class="hljs-keyword">and</span> <span class="hljs-string">'\n'</span> }</span>"</span>
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"<span class="hljs-subst">#{ props.length <span class="hljs-keyword">and</span> <span class="hljs-string">'\n'</span> + <span class="hljs-property">@tab</span> }</span>}"</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@front</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> answer <span class="hljs-keyword">else</span> answer
<span class="hljs-keyword">if</span> hasDynamic
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">",\n<span class="hljs-subst">#{idt}</span><span class="hljs-subst">#{oref}</span>\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>)"</span>
<span class="hljs-keyword">else</span>
answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">"\n<span class="hljs-subst">#{<span class="hljs-property">@tab</span>}</span>}"</span> <span class="hljs-keyword">unless</span> props.length <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@front</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> hasDynamic <span class="hljs-keyword">then</span> <span class="hljs-property">@wrapInBraces</span> answer <span class="hljs-keyword">else</span> answer
<span class="hljs-attribute">assigns</span>: <span class="hljs-function"><span class="hljs-params">(name)</span> -&gt;</span>
<span class="hljs-keyword">for</span> prop <span class="hljs-keyword">in</span> <span class="hljs-property">@properties</span> <span class="hljs-keyword">when</span> prop.assigns name <span class="hljs-keyword">then</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span>
@@ -2124,7 +2163,8 @@ list of prototype property assignments.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">determineName</span>:<span class="hljs-function"> -&gt;</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@variable</span>
decl = <span class="hljs-keyword">if</span> tail = last <span class="hljs-property">@variable</span>.properties
[..., tail] = <span class="hljs-property">@variable</span>.properties
decl = <span class="hljs-keyword">if</span> tail
tail <span class="hljs-keyword">instanceof</span> Access <span class="hljs-keyword">and</span> tail.name.value
<span class="hljs-keyword">else</span>
<span class="hljs-property">@variable</span>.base.value
@@ -2152,7 +2192,6 @@ list of prototype property assignments.</p>
<span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">is</span> <span class="hljs-string">'this'</span>
node.value = name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Code
node.klass = name
node.context = name <span class="hljs-keyword">if</span> node.bound</pre></div></div>
</li>
@@ -2172,7 +2211,7 @@ constructor.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">addBoundFunctions</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
<span class="hljs-keyword">for</span> bvar <span class="hljs-keyword">in</span> <span class="hljs-property">@boundFuncs</span>
lhs = (<span class="hljs-keyword">new</span> Value (<span class="hljs-keyword">new</span> Literal <span class="hljs-string">"this"</span>), [<span class="hljs-keyword">new</span> Access bvar]).compile o
<span class="hljs-property">@ctor</span>.body.unshift <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{lhs}</span> = <span class="hljs-subst">#{utility <span class="hljs-string">'bind'</span>}</span>(<span class="hljs-subst">#{lhs}</span>, this)"</span>
<span class="hljs-property">@ctor</span>.body.unshift <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{lhs}</span> = <span class="hljs-subst">#{utility <span class="hljs-string">'bind'</span>, o}</span>(<span class="hljs-subst">#{lhs}</span>, this)"</span>
<span class="hljs-keyword">return</span></pre></div></div>
</li>
@@ -2210,7 +2249,8 @@ on the class.</p>
<span class="hljs-keyword">if</span> assign.variable.<span class="hljs-keyword">this</span>
func.static = <span class="hljs-literal">yes</span>
<span class="hljs-keyword">else</span>
assign.variable = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal(name), [(<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'prototype'</span>), <span class="hljs-keyword">new</span> Access base])
acc = <span class="hljs-keyword">if</span> base.isComplex() <span class="hljs-keyword">then</span> <span class="hljs-keyword">new</span> Index base <span class="hljs-keyword">else</span> <span class="hljs-keyword">new</span> Access base
assign.variable = <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Literal(name), [(<span class="hljs-keyword">new</span> Access <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'prototype'</span>), acc])
<span class="hljs-keyword">if</span> func <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> func.bound
<span class="hljs-property">@boundFuncs</span>.push base
func.bound = <span class="hljs-literal">no</span>
@@ -2331,7 +2371,7 @@ constructor, property assignments, and inheritance getting built out below.</p>
<span class="hljs-property">@body</span>.expressions.push lname
<span class="hljs-keyword">if</span> <span class="hljs-property">@parent</span>
superClass = <span class="hljs-keyword">new</span> Literal o.classScope.freeVariable <span class="hljs-string">'super'</span>, <span class="hljs-literal">no</span>
superClass = <span class="hljs-keyword">new</span> Literal o.classScope.freeVariable <span class="hljs-string">'superClass'</span>, <span class="hljs-attribute">reserve</span>: <span class="hljs-literal">no</span>
<span class="hljs-property">@body</span>.expressions.unshift <span class="hljs-keyword">new</span> Extends lname, superClass
func.params.push <span class="hljs-keyword">new</span> Param superClass
args.push <span class="hljs-property">@parent</span>
@@ -2410,21 +2450,28 @@ has not been seen yet within the current scope, declare it.</p>
<span class="hljs-keyword">return</span> <span class="hljs-property">@compileSplice</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</span>.isSplice()
<span class="hljs-keyword">return</span> <span class="hljs-property">@compileConditional</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'||='</span>, <span class="hljs-string">'&amp;&amp;='</span>, <span class="hljs-string">'?='</span>]
<span class="hljs-keyword">return</span> <span class="hljs-property">@compileSpecialMath</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'**='</span>, <span class="hljs-string">'//='</span>, <span class="hljs-string">'%%='</span>]
compiledName = <span class="hljs-property">@variable</span>.compileToFragments o, LEVEL_LIST
name = fragmentsToText compiledName
<span class="hljs-keyword">if</span> <span class="hljs-property">@value</span> <span class="hljs-keyword">instanceof</span> Code
<span class="hljs-keyword">if</span> <span class="hljs-property">@value</span>.static
<span class="hljs-property">@value</span>.klass = <span class="hljs-property">@variable</span>.base
<span class="hljs-property">@value</span>.name = <span class="hljs-property">@variable</span>.properties[<span class="hljs-number">0</span>]
<span class="hljs-property">@value</span>.variable = <span class="hljs-property">@variable</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@variable</span>.properties?.length &gt;= <span class="hljs-number">2</span>
[properties..., prototype, name] = <span class="hljs-property">@variable</span>.properties
<span class="hljs-keyword">if</span> prototype.name?.value <span class="hljs-keyword">is</span> <span class="hljs-string">'prototype'</span>
<span class="hljs-property">@value</span>.klass = <span class="hljs-keyword">new</span> Value <span class="hljs-property">@variable</span>.base, properties
<span class="hljs-property">@value</span>.name = name
<span class="hljs-property">@value</span>.variable = <span class="hljs-property">@variable</span>
<span class="hljs-keyword">unless</span> <span class="hljs-property">@context</span>
varBase = <span class="hljs-property">@variable</span>.unwrapAll()
<span class="hljs-keyword">unless</span> varBase.isAssignable()
<span class="hljs-property">@variable</span>.error <span class="hljs-string">"\"<span class="hljs-subst">#{<span class="hljs-property">@variable</span>.compile o}</span>\" cannot be assigned"</span>
<span class="hljs-keyword">unless</span> varBase.hasProperties?()
<span class="hljs-keyword">if</span> <span class="hljs-property">@param</span>
o.scope.add name, <span class="hljs-string">'var'</span>
o.scope.add varBase.value, <span class="hljs-string">'var'</span>
<span class="hljs-keyword">else</span>
o.scope.find name
<span class="hljs-keyword">if</span> <span class="hljs-property">@value</span> <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> match = METHOD_DEF.exec name
<span class="hljs-property">@value</span>.klass = match[<span class="hljs-number">1</span>] <span class="hljs-keyword">if</span> match[<span class="hljs-number">2</span>]
<span class="hljs-property">@value</span>.name = match[<span class="hljs-number">3</span>] ? match[<span class="hljs-number">4</span>] ? match[<span class="hljs-number">5</span>]
o.scope.find varBase.value
val = <span class="hljs-property">@value</span>.compileToFragments o, LEVEL_LIST
compiledName = <span class="hljs-property">@variable</span>.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">return</span> (compiledName.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">": "</span>), val) <span class="hljs-keyword">if</span> <span class="hljs-property">@context</span> <span class="hljs-keyword">is</span> <span class="hljs-string">'object'</span>
answer = compiledName.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">" <span class="hljs-subst">#{ <span class="hljs-property">@context</span> <span class="hljs-keyword">or</span> <span class="hljs-string">'='</span> }</span> "</span>), val
<span class="hljs-keyword">if</span> o.level &lt;= LEVEL_LIST <span class="hljs-keyword">then</span> answer <span class="hljs-keyword">else</span> <span class="hljs-property">@wrapInBraces</span> answer</pre></div></div>
@@ -2558,9 +2605,9 @@ for details.</p>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> expandedIdx <span class="hljs-keyword">and</span> obj <span class="hljs-keyword">instanceof</span> Splat
name = obj.name.unwrap().value
obj = obj.unwrap()
val = <span class="hljs-string">"<span class="hljs-subst">#{olen}</span> &lt;= <span class="hljs-subst">#{vvarText}</span>.length ? <span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span> }</span>.call(<span class="hljs-subst">#{vvarText}</span>, <span class="hljs-subst">#{i}</span>"</span>
val = <span class="hljs-string">"<span class="hljs-subst">#{olen}</span> &lt;= <span class="hljs-subst">#{vvarText}</span>.length ? <span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call(<span class="hljs-subst">#{vvarText}</span>, <span class="hljs-subst">#{i}</span>"</span>
<span class="hljs-keyword">if</span> rest = olen - i - <span class="hljs-number">1</span>
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span>
val += <span class="hljs-string">", <span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>) : (<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{i}</span>, [])"</span>
<span class="hljs-keyword">else</span>
val += <span class="hljs-string">") : []"</span>
@@ -2571,7 +2618,7 @@ for details.</p>
<span class="hljs-keyword">if</span> rest <span class="hljs-keyword">is</span> <span class="hljs-number">1</span>
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{vvarText}</span>.length - 1"</span>
<span class="hljs-keyword">else</span>
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>
ivar = o.scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span>
val = <span class="hljs-keyword">new</span> Literal <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span> = <span class="hljs-subst">#{vvarText}</span>.length - <span class="hljs-subst">#{rest}</span>"</span>
expandedIdx = <span class="hljs-string">"<span class="hljs-subst">#{ivar}</span>++"</span>
assigns.push val.compileToFragments o, LEVEL_LIST
@@ -2717,9 +2764,11 @@ has no <em>children</em> — theyre within the inner scope.</p>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Code = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Code</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Base</span></span>
<span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(params, body, tag)</span> -&gt;</span>
<span class="hljs-property">@params</span> = params <span class="hljs-keyword">or</span> []
<span class="hljs-property">@body</span> = body <span class="hljs-keyword">or</span> <span class="hljs-keyword">new</span> Block
<span class="hljs-property">@bound</span> = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'boundfunc'</span>
<span class="hljs-property">@params</span> = params <span class="hljs-keyword">or</span> []
<span class="hljs-property">@body</span> = body <span class="hljs-keyword">or</span> <span class="hljs-keyword">new</span> Block
<span class="hljs-property">@bound</span> = tag <span class="hljs-keyword">is</span> <span class="hljs-string">'boundfunc'</span>
<span class="hljs-property">@isGenerator</span> = !!<span class="hljs-property">@body</span>.contains <span class="hljs-function"><span class="hljs-params">(node)</span> -&gt;</span>
node <span class="hljs-keyword">instanceof</span> Op <span class="hljs-keyword">and</span> node.operator <span class="hljs-keyword">in</span> [<span class="hljs-string">'yield'</span>, <span class="hljs-string">'yield*'</span>]
<span class="hljs-attribute">children</span>: [<span class="hljs-string">'params'</span>, <span class="hljs-string">'body'</span>]
@@ -2781,9 +2830,8 @@ a closure.</p>
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <span class="hljs-keyword">when</span> param <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion
o.scope.parameter param.asReference o
<span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <span class="hljs-keyword">when</span> param.splat <span class="hljs-keyword">or</span> param <span class="hljs-keyword">instanceof</span> Expansion
<span class="hljs-keyword">for</span> {<span class="hljs-attribute">name</span>: p} <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <span class="hljs-keyword">when</span> param <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion
<span class="hljs-keyword">if</span> p.<span class="hljs-keyword">this</span> <span class="hljs-keyword">then</span> p = p.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">if</span> p.value <span class="hljs-keyword">then</span> o.scope.add p.value, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span>
<span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span> <span class="hljs-keyword">when</span> p <span class="hljs-keyword">not</span> <span class="hljs-keyword">instanceof</span> Expansion <span class="hljs-keyword">and</span> p.name.value
o.scope.add p.name.value, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span>
splats = <span class="hljs-keyword">new</span> Assign <span class="hljs-keyword">new</span> Value(<span class="hljs-keyword">new</span> Arr(p.asReference o <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> <span class="hljs-property">@params</span>)),
<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'arguments'</span>
<span class="hljs-keyword">break</span>
@@ -2807,12 +2855,13 @@ a closure.</p>
o.scope.parameter fragmentsToText params[i]
uniqs = []
<span class="hljs-property">@eachParamName</span> <span class="hljs-function"><span class="hljs-params">(name, node)</span> -&gt;</span>
node.error <span class="hljs-string">"multiple parameters named '<span class="hljs-subst">#{name}</span>'"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> uniqs
node.error <span class="hljs-string">"multiple parameters named <span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name <span class="hljs-keyword">in</span> uniqs
uniqs.push name
<span class="hljs-property">@body</span>.makeReturn() <span class="hljs-keyword">unless</span> wasEmpty <span class="hljs-keyword">or</span> <span class="hljs-property">@noReturn</span>
code = <span class="hljs-string">'function'</span>
code += <span class="hljs-string">' '</span> + <span class="hljs-property">@name</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@ctor</span>
code += <span class="hljs-string">'('</span>
code = <span class="hljs-string">'function'</span>
code += <span class="hljs-string">'*'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@isGenerator</span>
code += <span class="hljs-string">' '</span> + <span class="hljs-property">@name</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@ctor</span>
code += <span class="hljs-string">'('</span>
answer = [<span class="hljs-property">@makeCode</span>(code)]
<span class="hljs-keyword">for</span> p, i <span class="hljs-keyword">in</span> params
<span class="hljs-keyword">if</span> i <span class="hljs-keyword">then</span> answer.push <span class="hljs-property">@makeCode</span> <span class="hljs-string">", "</span>
@@ -2886,9 +2935,9 @@ as well as be a splat, gathering up a group of parameters into an array.</p>
<span class="hljs-keyword">return</span> <span class="hljs-property">@reference</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@reference</span>
node = <span class="hljs-property">@name</span>
<span class="hljs-keyword">if</span> node.<span class="hljs-keyword">this</span>
node = node.properties[<span class="hljs-number">0</span>].name
<span class="hljs-keyword">if</span> node.value.reserved
node = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable node.value
name = node.properties[<span class="hljs-number">0</span>].name.value
name = <span class="hljs-string">"_<span class="hljs-subst">#{name}</span>"</span> <span class="hljs-keyword">if</span> name.reserved
node = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable name
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> node.isComplex()
node = <span class="hljs-keyword">new</span> Literal o.scope.freeVariable <span class="hljs-string">'arg'</span>
node = <span class="hljs-keyword">new</span> Value node
@@ -2918,9 +2967,7 @@ to that name.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">eachName</span>: <span class="hljs-function"><span class="hljs-params">(iterator, name = <span class="hljs-property">@name</span>)</span>-&gt;</span>
<span class="hljs-function"><span class="hljs-title">atParam</span> = <span class="hljs-params">(obj)</span> -&gt;</span>
node = obj.properties[<span class="hljs-number">0</span>].name
iterator node.value, node <span class="hljs-keyword">unless</span> node.value.reserved</pre></div></div>
<span class="hljs-function"><span class="hljs-title">atParam</span> = <span class="hljs-params">(obj)</span> -&gt;</span> iterator <span class="hljs-string">"@<span class="hljs-subst">#{obj.properties[<span class="hljs-number">0</span>].name.value}</span>"</span>, obj</pre></div></div>
</li>
@@ -3117,12 +3164,12 @@ splats, to a proper array.</p>
node = list[<span class="hljs-number">0</span>]
fragments = node.compileToFragments o, LEVEL_LIST
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> apply
<span class="hljs-keyword">return</span> [].concat node.makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span> }</span>.call("</span>), fragments, node.makeCode(<span class="hljs-string">")"</span>)
<span class="hljs-keyword">return</span> [].concat node.makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call("</span>), fragments, node.makeCode(<span class="hljs-string">")"</span>)
args = list[index..]
<span class="hljs-keyword">for</span> node, i <span class="hljs-keyword">in</span> args
compiledNode = node.compileToFragments o, LEVEL_LIST
args[i] = <span class="hljs-keyword">if</span> node <span class="hljs-keyword">instanceof</span> Splat
<span class="hljs-keyword">then</span> [].concat node.makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span> }</span>.call("</span>), compiledNode, node.makeCode(<span class="hljs-string">")"</span>)
<span class="hljs-keyword">then</span> [].concat node.makeCode(<span class="hljs-string">"<span class="hljs-subst">#{ utility <span class="hljs-string">'slice'</span>, o }</span>.call("</span>), compiledNode, node.makeCode(<span class="hljs-string">")"</span>)
<span class="hljs-keyword">else</span> [].concat node.makeCode(<span class="hljs-string">"["</span>), compiledNode, node.makeCode(<span class="hljs-string">"]"</span>)
<span class="hljs-keyword">if</span> index <span class="hljs-keyword">is</span> <span class="hljs-number">0</span>
node = list[<span class="hljs-number">0</span>]
@@ -3131,7 +3178,8 @@ splats, to a proper array.</p>
base = (node.compileToFragments o, LEVEL_LIST <span class="hljs-keyword">for</span> node <span class="hljs-keyword">in</span> list[...index])
base = list[<span class="hljs-number">0</span>].joinFragmentArrays base, <span class="hljs-string">', '</span>
concatPart = list[index].joinFragmentArrays args, <span class="hljs-string">', '</span>
[].concat list[<span class="hljs-number">0</span>].makeCode(<span class="hljs-string">"["</span>), base, list[index].makeCode(<span class="hljs-string">"].concat("</span>), concatPart, (last list).makeCode(<span class="hljs-string">")"</span>)</pre></div></div>
[..., last] = list
[].concat list[<span class="hljs-number">0</span>].makeCode(<span class="hljs-string">"["</span>), base, list[index].makeCode(<span class="hljs-string">"].concat("</span>), concatPart, last.makeCode(<span class="hljs-string">")"</span>)</pre></div></div>
</li>
@@ -3318,9 +3366,10 @@ CoffeeScript operations into their JavaScript equivalents.</p>
</div>
<div class="content"><div class='highlight'><pre> CONVERSIONS =
<span class="hljs-string">'=='</span>: <span class="hljs-string">'==='</span>
<span class="hljs-string">'!='</span>: <span class="hljs-string">'!=='</span>
<span class="hljs-string">'of'</span>: <span class="hljs-string">'in'</span></pre></div></div>
<span class="hljs-string">'=='</span>: <span class="hljs-string">'==='</span>
<span class="hljs-string">'!='</span>: <span class="hljs-string">'!=='</span>
<span class="hljs-string">'of'</span>: <span class="hljs-string">'in'</span>
<span class="hljs-string">'yieldfrom'</span>: <span class="hljs-string">'yield*'</span></pre></div></div>
</li>
@@ -3343,11 +3392,18 @@ CoffeeScript operations into their JavaScript equivalents.</p>
<span class="hljs-attribute">isSimpleNumber</span>: NO
<span class="hljs-attribute">isYield</span>:<span class="hljs-function"> -&gt;</span>
<span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'yield'</span>, <span class="hljs-string">'yield*'</span>]
<span class="hljs-attribute">isYieldReturn</span>:<span class="hljs-function"> -&gt;</span>
<span class="hljs-property">@isYield</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Return
<span class="hljs-attribute">isUnary</span>:<span class="hljs-function"> -&gt;</span>
<span class="hljs-keyword">not</span> <span class="hljs-property">@second</span>
<span class="hljs-attribute">isComplex</span>:<span class="hljs-function"> -&gt;</span>
<span class="hljs-keyword">not</span> (<span class="hljs-property">@isUnary</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>]) <span class="hljs-keyword">or</span> <span class="hljs-property">@first</span>.isComplex()</pre></div></div>
<span class="hljs-keyword">not</span> (<span class="hljs-property">@isUnary</span>() <span class="hljs-keyword">and</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>] <span class="hljs-keyword">and</span>
<span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Value <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.isSimpleNumber())</pre></div></div>
</li>
@@ -3434,6 +3490,7 @@ as the chained expression is wrapped.</p>
<span class="hljs-property">@error</span> <span class="hljs-string">'delete operand may not be argument or var'</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@operator</span> <span class="hljs-keyword">in</span> [<span class="hljs-string">'--'</span>, <span class="hljs-string">'++'</span>] <span class="hljs-keyword">and</span> <span class="hljs-property">@first</span>.unwrapAll().value <span class="hljs-keyword">in</span> STRICT_PROSCRIBED
<span class="hljs-property">@error</span> <span class="hljs-string">"cannot increment/decrement \"<span class="hljs-subst">#{<span class="hljs-property">@first</span>.unwrapAll().value}</span>\""</span>
<span class="hljs-keyword">return</span> <span class="hljs-property">@compileYield</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@isYield</span>()
<span class="hljs-keyword">return</span> <span class="hljs-property">@compileUnary</span> o <span class="hljs-keyword">if</span> <span class="hljs-property">@isUnary</span>()
<span class="hljs-keyword">return</span> <span class="hljs-property">@compileChain</span> o <span class="hljs-keyword">if</span> isChain
<span class="hljs-keyword">switch</span> <span class="hljs-property">@operator</span>
@@ -3523,6 +3580,22 @@ used sequentially. For example:</p>
parts.reverse() <span class="hljs-keyword">if</span> <span class="hljs-property">@flip</span>
<span class="hljs-property">@joinFragmentArrays</span> parts, <span class="hljs-string">''</span>
<span class="hljs-attribute">compileYield</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
parts = []
op = <span class="hljs-property">@operator</span>
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> o.scope.parent?
<span class="hljs-property">@error</span> <span class="hljs-string">'yield statements must occur within a function generator.'</span>
<span class="hljs-keyword">if</span> <span class="hljs-string">'expression'</span> <span class="hljs-keyword">in</span> Object.keys(<span class="hljs-property">@first</span>) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (<span class="hljs-property">@first</span> <span class="hljs-keyword">instanceof</span> Throw)
<span class="hljs-keyword">if</span> <span class="hljs-property">@isYieldReturn</span>()
parts.push <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_TOP
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@first</span>.expression?
parts.push <span class="hljs-property">@first</span>.expression.compileToFragments o, LEVEL_OP
<span class="hljs-keyword">else</span>
parts.push [<span class="hljs-property">@makeCode</span> <span class="hljs-string">"(<span class="hljs-subst">#{op}</span> "</span>]
parts.push <span class="hljs-property">@first</span>.compileToFragments o, LEVEL_OP
parts.push [<span class="hljs-property">@makeCode</span> <span class="hljs-string">")"</span>]
<span class="hljs-property">@joinFragmentArrays</span> parts, <span class="hljs-string">''</span>
<span class="hljs-attribute">compilePower</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span></pre></div></div>
</li>
@@ -3547,7 +3620,7 @@ used sequentially. For example:</p>
<span class="hljs-keyword">new</span> Call(floor, [div]).compileToFragments o
<span class="hljs-attribute">compileModulo</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
mod = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'modulo'</span>
mod = <span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal utility <span class="hljs-string">'modulo'</span>, o
<span class="hljs-keyword">new</span> Call(mod, [<span class="hljs-property">@first</span>, <span class="hljs-property">@second</span>]).compileToFragments o
<span class="hljs-attribute">toString</span>: <span class="hljs-function"><span class="hljs-params">(idt)</span> -&gt;</span>
@@ -3606,7 +3679,7 @@ used sequentially. For example:</p>
<span class="hljs-attribute">compileLoopTest</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
[sub, ref] = <span class="hljs-property">@object</span>.cache o, LEVEL_LIST
fragments = [].concat <span class="hljs-property">@makeCode</span>(utility(<span class="hljs-string">'indexOf'</span>) + <span class="hljs-string">".call("</span>), <span class="hljs-property">@array</span>.compileToFragments(o, LEVEL_LIST),
fragments = [].concat <span class="hljs-property">@makeCode</span>(utility(<span class="hljs-string">'indexOf'</span>, o) + <span class="hljs-string">".call("</span>), <span class="hljs-property">@array</span>.compileToFragments(o, LEVEL_LIST),
<span class="hljs-property">@makeCode</span>(<span class="hljs-string">", "</span>), ref, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">") "</span> + <span class="hljs-keyword">if</span> <span class="hljs-property">@negated</span> <span class="hljs-keyword">then</span> <span class="hljs-string">'&lt; 0'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'&gt;= 0'</span>)
<span class="hljs-keyword">return</span> fragments <span class="hljs-keyword">if</span> fragmentsToText(sub) <span class="hljs-keyword">is</span> fragmentsToText(ref)
fragments = sub.concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">', '</span>), fragments
@@ -3913,29 +3986,30 @@ some cannot.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">compileNode</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span>
body = Block.wrap [<span class="hljs-property">@body</span>]
lastJumps = last(body.expressions)?.jumps()
<span class="hljs-property">@returns</span> = <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> lastJumps <span class="hljs-keyword">and</span> lastJumps <span class="hljs-keyword">instanceof</span> Return
source = <span class="hljs-keyword">if</span> <span class="hljs-property">@range</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@source</span>.base <span class="hljs-keyword">else</span> <span class="hljs-property">@source</span>
scope = o.scope
name = <span class="hljs-property">@name</span> <span class="hljs-keyword">and</span> (<span class="hljs-property">@name</span>.compile o, LEVEL_LIST) <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@pattern</span>
index = <span class="hljs-property">@index</span> <span class="hljs-keyword">and</span> (<span class="hljs-property">@index</span>.compile o, LEVEL_LIST)
body = Block.wrap [<span class="hljs-property">@body</span>]
[..., last] = body.expressions
<span class="hljs-property">@returns</span> = <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> last?.jumps() <span class="hljs-keyword">instanceof</span> Return
source = <span class="hljs-keyword">if</span> <span class="hljs-property">@range</span> <span class="hljs-keyword">then</span> <span class="hljs-property">@source</span>.base <span class="hljs-keyword">else</span> <span class="hljs-property">@source</span>
scope = o.scope
name = <span class="hljs-property">@name</span> <span class="hljs-keyword">and</span> (<span class="hljs-property">@name</span>.compile o, LEVEL_LIST) <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@pattern</span>
index = <span class="hljs-property">@index</span> <span class="hljs-keyword">and</span> (<span class="hljs-property">@index</span>.compile o, LEVEL_LIST)
scope.find(name) <span class="hljs-keyword">if</span> name <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@pattern</span>
scope.find(index) <span class="hljs-keyword">if</span> index
rvar = scope.freeVariable <span class="hljs-string">'results'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@returns</span>
ivar = (<span class="hljs-property">@object</span> <span class="hljs-keyword">and</span> index) <span class="hljs-keyword">or</span> scope.freeVariable <span class="hljs-string">'i'</span>
kvar = (<span class="hljs-property">@range</span> <span class="hljs-keyword">and</span> name) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">or</span> ivar
kvarAssign = <span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> = "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>
rvar = scope.freeVariable <span class="hljs-string">'results'</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@returns</span>
ivar = (<span class="hljs-property">@object</span> <span class="hljs-keyword">and</span> index) <span class="hljs-keyword">or</span> scope.freeVariable <span class="hljs-string">'i'</span>, <span class="hljs-attribute">single</span>: <span class="hljs-literal">true</span>
kvar = (<span class="hljs-property">@range</span> <span class="hljs-keyword">and</span> name) <span class="hljs-keyword">or</span> index <span class="hljs-keyword">or</span> ivar
kvarAssign = <span class="hljs-keyword">if</span> kvar <span class="hljs-keyword">isnt</span> ivar <span class="hljs-keyword">then</span> <span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> = "</span> <span class="hljs-keyword">else</span> <span class="hljs-string">""</span>
<span class="hljs-keyword">if</span> <span class="hljs-property">@step</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@range</span>
[step, stepVar] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@step</span>.cache o, LEVEL_LIST
[step, stepVar] = <span class="hljs-property">@cacheToCodeFragments</span> <span class="hljs-property">@step</span>.cache o, LEVEL_LIST, isComplexOrAssignable
stepNum = stepVar.match NUMBER
name = ivar <span class="hljs-keyword">if</span> <span class="hljs-property">@pattern</span>
varPart = <span class="hljs-string">''</span>
guardPart = <span class="hljs-string">''</span>
defPart = <span class="hljs-string">''</span>
idt1 = <span class="hljs-property">@tab</span> + TAB
name = ivar <span class="hljs-keyword">if</span> <span class="hljs-property">@pattern</span>
varPart = <span class="hljs-string">''</span>
guardPart = <span class="hljs-string">''</span>
defPart = <span class="hljs-string">''</span>
idt1 = <span class="hljs-property">@tab</span> + TAB
<span class="hljs-keyword">if</span> <span class="hljs-property">@range</span>
forPartFragments = source.compileToFragments merge(o, {<span class="hljs-attribute">index</span>: ivar, name, <span class="hljs-property">@step</span>})
forPartFragments = source.compileToFragments merge o,
{<span class="hljs-attribute">index</span>: ivar, name, <span class="hljs-property">@step</span>, <span class="hljs-attribute">isComplex</span>: isComplexOrAssignable}
<span class="hljs-keyword">else</span>
svar = <span class="hljs-property">@source</span>.compile o, LEVEL_LIST
<span class="hljs-keyword">if</span> (name <span class="hljs-keyword">or</span> <span class="hljs-property">@own</span>) <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> IDENTIFIER.test svar
@@ -3977,7 +4051,7 @@ some cannot.</p>
varPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span><span class="hljs-subst">#{namePart}</span>;"</span> <span class="hljs-keyword">if</span> namePart
<span class="hljs-keyword">if</span> <span class="hljs-property">@object</span>
forPartFragments = [<span class="hljs-property">@makeCode</span>(<span class="hljs-string">"<span class="hljs-subst">#{kvar}</span> in <span class="hljs-subst">#{svar}</span>"</span>)]
guardPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span>if (!<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>}</span>.call(<span class="hljs-subst">#{svar}</span>, <span class="hljs-subst">#{kvar}</span>)) continue;"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@own</span>
guardPart = <span class="hljs-string">"\n<span class="hljs-subst">#{idt1}</span>if (!<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(<span class="hljs-subst">#{svar}</span>, <span class="hljs-subst">#{kvar}</span>)) continue;"</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@own</span>
bodyFragments = body.compileToFragments merge(o, <span class="hljs-attribute">indent</span>: idt1), LEVEL_TOP
<span class="hljs-keyword">if</span> bodyFragments <span class="hljs-keyword">and</span> (bodyFragments.length &gt; <span class="hljs-number">0</span>)
bodyFragments = [].concat <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>), bodyFragments, <span class="hljs-property">@makeCode</span>(<span class="hljs-string">"\n"</span>)
@@ -4264,10 +4338,10 @@ to the superclass for <code>super()</code> calls, and copies of any static prope
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">extends</span>:<span class="hljs-function"> -&gt;</span> <span class="hljs-string">"
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">extend</span>: <span class="hljs-function"><span class="hljs-params">(o)</span> -&gt;</span> <span class="hljs-string">"
function(child, parent) {
for (var key in parent) {
if (<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>}</span>.call(parent, key)) child[key] = parent[key];
if (<span class="hljs-subst">#{utility <span class="hljs-string">'hasProp'</span>, o}</span>.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
@@ -4378,23 +4452,13 @@ LEVEL_ACCESS = <span class="hljs-number">6</span> <span class="hljs-comment">#
<div class="content"><div class='highlight'><pre>TAB = <span class="hljs-string">' '</span>
IDENTIFIER_STR = <span class="hljs-string">"[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"</span>
IDENTIFIER = <span class="hljs-regexp">/// ^ <span class="hljs-subst">#{IDENTIFIER_STR}</span> $ ///</span>
IDENTIFIER = <span class="hljs-regexp">/// ^ (?!\d) [$\w\x7f-\uffff]+ $ ///</span>
SIMPLENUM = <span class="hljs-regexp">/^[+-]?\d+$/</span>
HEXNUM = <span class="hljs-regexp">/^[+-]?0x[\da-f]+/i</span>
NUMBER = <span class="hljs-regexp">///^[+-]?(?:
0x[\da-f]+ | <span class="hljs-comment"># hex</span>
\d*\.?\d+ (?:e[+-]?\d+)? <span class="hljs-comment"># decimal</span>
)$///</span>i
METHOD_DEF = <span class="hljs-regexp">/// ^
(<span class="hljs-subst">#{IDENTIFIER_STR}</span>)
(\.prototype)?
(?: \.(<span class="hljs-subst">#{IDENTIFIER_STR}</span>)
| \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\]
| \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\]
)
$ ///</span></pre></div></div>
)$///</span>i</pre></div></div>
</li>
@@ -4450,10 +4514,14 @@ IS_REGEX = <span class="hljs-regexp">/^\//</span></pre></div></div>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">utility</span> = <span class="hljs-params">(name)</span> -&gt;</span>
ref = <span class="hljs-string">"__<span class="hljs-subst">#{name}</span>"</span>
Scope.root.assign ref, UTILITIES[name]()
ref
<div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-title">utility</span> = <span class="hljs-params">(name, o)</span> -&gt;</span>
{root} = o.scope
<span class="hljs-keyword">if</span> name <span class="hljs-keyword">of</span> root.utilities
root.utilities[name]
<span class="hljs-keyword">else</span>
ref = root.freeVariable name
root.assign ref, UTILITIES[name] o
root.utilities[name] = ref
<span class="hljs-function"><span class="hljs-title">multident</span> = <span class="hljs-params">(code, tab)</span> -&gt;</span>
code = code.replace <span class="hljs-regexp">/\n/g</span>, <span class="hljs-string">'$&amp;'</span> + tab
@@ -4487,7 +4555,9 @@ Examples: 0, -1, 1, 2e3, 2e-3, -0xfe, 0xfe</p>
<span class="hljs-function"><span class="hljs-title">isLiteralThis</span> = <span class="hljs-params">(node)</span> -&gt;</span>
(node <span class="hljs-keyword">instanceof</span> Literal <span class="hljs-keyword">and</span> node.value <span class="hljs-keyword">is</span> <span class="hljs-string">'this'</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> node.asKey) <span class="hljs-keyword">or</span>
(node <span class="hljs-keyword">instanceof</span> Code <span class="hljs-keyword">and</span> node.bound) <span class="hljs-keyword">or</span>
(node <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> node.isSuper)</pre></div></div>
(node <span class="hljs-keyword">instanceof</span> Call <span class="hljs-keyword">and</span> node.isSuper)
<span class="hljs-function"><span class="hljs-title">isComplexOrAssignable</span> = <span class="hljs-params">(node)</span> -&gt;</span> node.isComplex() <span class="hljs-keyword">or</span> node.isAssignable?()</pre></div></div>
</li>

0
documentation/docs/public/fonts/aller-bold.eot Executable file → Normal file
View File

0
documentation/docs/public/fonts/aller-bold.ttf Executable file → Normal file
View File

0
documentation/docs/public/fonts/aller-bold.woff Executable file → Normal file
View File

0
documentation/docs/public/fonts/aller-light.eot Executable file → Normal file
View File

0
documentation/docs/public/fonts/aller-light.ttf Executable file → Normal file
View File

0
documentation/docs/public/fonts/aller-light.woff Executable file → Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -188,11 +188,11 @@ parens. Unwrap all that.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-5">&#182;</a>
</div>
<p>Generate the AST of the clean input.</p>
<p>Tokenize the clean input.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes input</pre></div></div>
<div class="content"><div class='highlight'><pre> tokens = CoffeeScript.tokens input</pre></div></div>
</li>
@@ -203,6 +203,38 @@ parens. Unwrap all that.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">&#182;</a>
</div>
<p>Collect referenced variable names just like in <code>CoffeeScript.compile</code>.</p>
</div>
<div class="content"><div class='highlight'><pre> referencedVars = (
token[<span class="hljs-number">1</span>] <span class="hljs-keyword">for</span> token <span class="hljs-keyword">in</span> tokens <span class="hljs-keyword">when</span> token.variable
)</pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">&#182;</a>
</div>
<p>Generate the AST of the tokens.</p>
</div>
<div class="content"><div class='highlight'><pre> ast = CoffeeScript.nodes tokens</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
</div>
<p>Add assignment to <code>_</code> variable to force the input to be an expression.</p>
</div>
@@ -210,7 +242,7 @@ parens. Unwrap all that.</p>
<div class="content"><div class='highlight'><pre> ast = <span class="hljs-keyword">new</span> Block [
<span class="hljs-keyword">new</span> Assign (<span class="hljs-keyword">new</span> Value <span class="hljs-keyword">new</span> Literal <span class="hljs-string">'_'</span>), ast, <span class="hljs-string">'='</span>
]
js = ast.compile <span class="hljs-attribute">bare</span>: <span class="hljs-literal">yes</span>, <span class="hljs-attribute">locals</span>: Object.keys(context)
js = ast.compile {<span class="hljs-attribute">bare</span>: <span class="hljs-literal">yes</span>, <span class="hljs-attribute">locals</span>: Object.keys(context), referencedVars}
result = <span class="hljs-keyword">if</span> context <span class="hljs-keyword">is</span> <span class="hljs-built_in">global</span>
vm.runInThisContext js, filename
<span class="hljs-keyword">else</span>
@@ -221,11 +253,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-7">
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">&#182;</a>
<a class="pilcrow" href="#section-9">&#182;</a>
</div>
<p>ASTs <code>compile</code> does not add source code information to syntax errors.</p>
@@ -240,11 +272,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-8">
<li id="section-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">&#182;</a>
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>Node 0.11.12 changed API, prompt is now _prompt.</p>
@@ -261,11 +293,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-9">
<li id="section-11">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">&#182;</a>
<a class="pilcrow" href="#section-11">&#182;</a>
</div>
<p>Proxy nodes line listener</p>
@@ -286,11 +318,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-10">
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>Handle Ctrl-v</p>
@@ -303,11 +335,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-11">
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#182;</a>
<a class="pilcrow" href="#section-13">&#182;</a>
</div>
<p>allow arbitrarily switching between modes any time before multiple lines are entered</p>
@@ -322,11 +354,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-12">
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
<a class="pilcrow" href="#section-14">&#182;</a>
</div>
<p>no-op unless the current line is empty</p>
@@ -337,11 +369,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-13">
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">&#182;</a>
<a class="pilcrow" href="#section-15">&#182;</a>
</div>
<p>eval, print, loop</p>
@@ -356,11 +388,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-14">
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">&#182;</a>
<a class="pilcrow" href="#section-16">&#182;</a>
</div>
<p>XXX: multiline hack</p>
@@ -378,11 +410,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-15">
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">&#182;</a>
<a class="pilcrow" href="#section-17">&#182;</a>
</div>
<p>Store and load command history from a file</p>
@@ -395,11 +427,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-16">
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">&#182;</a>
<a class="pilcrow" href="#section-18">&#182;</a>
</div>
<p>Get file info and at most maxSize of command history</p>
@@ -411,11 +443,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-17">
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">&#182;</a>
<a class="pilcrow" href="#section-19">&#182;</a>
</div>
<p>Read last <code>size</code> bytes from the file</p>
@@ -428,11 +460,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-18">
<li id="section-20">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">&#182;</a>
<a class="pilcrow" href="#section-20">&#182;</a>
</div>
<p>Set the history on the interpreter</p>
@@ -443,11 +475,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-19">
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">&#182;</a>
<a class="pilcrow" href="#section-21">&#182;</a>
</div>
<p>If the history file was truncated we should pop off a potential partial line</p>
@@ -458,11 +490,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-20">
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-20">&#182;</a>
<a class="pilcrow" href="#section-22">&#182;</a>
</div>
<p>Shift off the final blank newline</p>
@@ -480,11 +512,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-21">
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">&#182;</a>
<a class="pilcrow" href="#section-23">&#182;</a>
</div>
<p>Save the latest command in the file</p>
@@ -498,11 +530,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-22">
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">&#182;</a>
<a class="pilcrow" href="#section-24">&#182;</a>
</div>
<p>Add a command to show the history stack</p>
@@ -519,11 +551,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-23">
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">&#182;</a>
<a class="pilcrow" href="#section-25">&#182;</a>
</div>
<p>Node 0.11 changed API, a command such as .help is now stored as help</p>
@@ -551,11 +583,11 @@ parens. Unwrap all that.</p>
</li>
<li id="section-24">
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">&#182;</a>
<a class="pilcrow" href="#section-26">&#182;</a>
</div>
<p>Adapt help inherited from the node REPL</p>

View File

@@ -315,20 +315,20 @@ Match it with its paired close.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">&#182;</a>
</div>
<p>Match tags in token stream starting at i with pattern, skipping HERECOMMENTs
Pattern may consist of strings (equality), an array of strings (one of)
or null (wildcard)</p>
<p>Match tags in token stream starting at <code>i</code> with <code>pattern</code>, skipping HERECOMMENTs.
<code>pattern</code> may consist of strings (equality), an array of strings (one of)
or null (wildcard). Returns the index of the match or -1 if no match.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">matchTags</span>: <span class="hljs-function"><span class="hljs-params">(i, pattern...)</span> -&gt;</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">indexOfTag</span>: <span class="hljs-function"><span class="hljs-params">(i, pattern...)</span> -&gt;</span>
fuzz = <span class="hljs-number">0</span>
<span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> [<span class="hljs-number">0</span> ... pattern.length]
fuzz += <span class="hljs-number">2</span> <span class="hljs-keyword">while</span> <span class="hljs-property">@tag</span>(i + j + fuzz) <span class="hljs-keyword">is</span> <span class="hljs-string">'HERECOMMENT'</span>
<span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> pattern[j]?
pattern[j] = [pattern[j]] <span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> pattern[j] <span class="hljs-keyword">is</span> <span class="hljs-string">'string'</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">no</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@tag</span>(i + j + fuzz) <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> pattern[j]
<span class="hljs-literal">yes</span></pre></div></div>
<span class="hljs-keyword">return</span> -<span class="hljs-number">1</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@tag</span>(i + j + fuzz) <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> pattern[j]
i + j + fuzz - <span class="hljs-number">1</span></pre></div></div>
</li>
@@ -339,13 +339,22 @@ or null (wildcard)</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-11">&#182;</a>
</div>
<p>yes iff standing in front of something looking like
@<x>: or <x>:, skipping over HERECOMMENTs</p>
<p>Returns <code>yes</code> if standing in front of something looking like
<code>@&lt;x&gt;:</code>, <code>&lt;x&gt;:</code> or <code>&lt;EXPRESSION_START&gt;&lt;x&gt;...&lt;EXPRESSION_END&gt;:</code>,
skipping over HERECOMMENTs.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">looksObjectish</span>: <span class="hljs-function"><span class="hljs-params">(j)</span> -&gt;</span>
<span class="hljs-property">@matchTags</span>(j, <span class="hljs-string">'@'</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">':'</span>) <span class="hljs-keyword">or</span> <span class="hljs-property">@matchTags</span>(j, <span class="hljs-literal">null</span>, <span class="hljs-string">':'</span>)</pre></div></div>
<span class="hljs-keyword">return</span> <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> <span class="hljs-property">@indexOfTag</span>(j, <span class="hljs-string">'@'</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">':'</span>) &gt; -<span class="hljs-number">1</span> <span class="hljs-keyword">or</span> <span class="hljs-property">@indexOfTag</span>(j, <span class="hljs-literal">null</span>, <span class="hljs-string">':'</span>) &gt; -<span class="hljs-number">1</span>
index = <span class="hljs-property">@indexOfTag</span>(j, EXPRESSION_START)
<span class="hljs-keyword">if</span> index &gt; -<span class="hljs-number">1</span>
end = <span class="hljs-literal">null</span>
<span class="hljs-property">@detectEnd</span> index + <span class="hljs-number">1</span>, <span class="hljs-function"><span class="hljs-params">((token) -&gt; token[<span class="hljs-number">0</span>] <span class="hljs-keyword">in</span> EXPRESSION_END)</span>, <span class="hljs-params">((token, i) -&gt; end = i)</span>
<span class="hljs-title">return</span> <span class="hljs-title">yes</span> <span class="hljs-title">if</span> @<span class="hljs-title">tag</span><span class="hljs-params">(end + <span class="hljs-number">1</span>)</span> <span class="hljs-title">is</span> ':'
<span class="hljs-title">no</span>
</span></pre></div></div>
</li>
@@ -356,7 +365,7 @@ or null (wildcard)</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">&#182;</a>
</div>
<p>yes iff current line of tokens contain an element of tags on same
<p>Returns <code>yes</code> if current line of tokens contain an element of tags on same
expression level. Stop searching at LINEBREAKS or explicit start of
containing balanced expression.</p>
@@ -403,6 +412,7 @@ add them.</p>
</div>
<div class="content"><div class='highlight'><pre> stack = []
start = <span class="hljs-literal">null</span>
<span class="hljs-property">@scanTokens</span> <span class="hljs-function"><span class="hljs-params">(token, i, tokens)</span> -&gt;</span>
[tag] = token
@@ -468,13 +478,15 @@ class declaration or if-conditionals)</p>
<span class="hljs-function"><span class="hljs-title">endImplicitCall</span> = -&gt;</span>
stack.pop()
tokens.splice i, <span class="hljs-number">0</span>, generate <span class="hljs-string">'CALL_END'</span>, <span class="hljs-string">')'</span>
tokens.splice i, <span class="hljs-number">0</span>, generate <span class="hljs-string">'CALL_END'</span>, <span class="hljs-string">')'</span>, [<span class="hljs-string">''</span>, <span class="hljs-string">'end of input'</span>, token[<span class="hljs-number">2</span>]]
i += <span class="hljs-number">1</span>
<span class="hljs-function"><span class="hljs-title">startImplicitObject</span> = <span class="hljs-params">(j, startsLine = <span class="hljs-literal">yes</span>)</span> -&gt;</span>
idx = j ? i
stack.push [<span class="hljs-string">'{'</span>, idx, <span class="hljs-attribute">sameLine</span>: <span class="hljs-literal">yes</span>, <span class="hljs-attribute">startsLine</span>: startsLine, <span class="hljs-attribute">ours</span>: <span class="hljs-literal">yes</span>]
tokens.splice idx, <span class="hljs-number">0</span>, generate <span class="hljs-string">'{'</span>, generate(<span class="hljs-keyword">new</span> String(<span class="hljs-string">'{'</span>)), token
val = <span class="hljs-keyword">new</span> String <span class="hljs-string">'{'</span>
val.generated = <span class="hljs-literal">yes</span>
tokens.splice idx, <span class="hljs-number">0</span>, generate <span class="hljs-string">'{'</span>, val, token
i += <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> j?
<span class="hljs-function"><span class="hljs-title">endImplicitObject</span> = <span class="hljs-params">(j)</span> -&gt;</span>
@@ -564,7 +576,7 @@ class declaration or if-conditionals)</p>
endImplicitObject()
<span class="hljs-keyword">else</span>
stack.pop()
stack.pop()</pre></div></div>
start = stack.pop()</pre></div></div>
</li>
@@ -580,7 +592,7 @@ f a, f() b, f? c, h[0] d etc.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tag <span class="hljs-keyword">in</span> IMPLICIT_FUNC <span class="hljs-keyword">and</span> token.spaced <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> token.stringEnd <span class="hljs-keyword">or</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (tag <span class="hljs-keyword">in</span> IMPLICIT_FUNC <span class="hljs-keyword">and</span> token.spaced <span class="hljs-keyword">or</span>
tag <span class="hljs-keyword">is</span> <span class="hljs-string">'?'</span> <span class="hljs-keyword">and</span> i &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> tokens[i - <span class="hljs-number">1</span>].spaced) <span class="hljs-keyword">and</span>
(nextTag <span class="hljs-keyword">in</span> IMPLICIT_CALL <span class="hljs-keyword">or</span>
nextTag <span class="hljs-keyword">in</span> IMPLICIT_UNSPACED_CALL <span class="hljs-keyword">and</span>
@@ -619,7 +631,8 @@ that creates grammatical ambiguities.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> IMPLICIT_FUNC <span class="hljs-keyword">and</span> <span class="hljs-property">@matchTags</span>(i + <span class="hljs-number">1</span>, <span class="hljs-string">'INDENT'</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">':'</span>) <span class="hljs-keyword">and</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> tag <span class="hljs-keyword">in</span> IMPLICIT_FUNC <span class="hljs-keyword">and</span>
<span class="hljs-property">@indexOfTag</span>(i + <span class="hljs-number">1</span>, <span class="hljs-string">'INDENT'</span>, <span class="hljs-literal">null</span>, <span class="hljs-string">':'</span>) &gt; -<span class="hljs-number">1</span> <span class="hljs-keyword">and</span>
<span class="hljs-keyword">not</span> <span class="hljs-property">@findTagsBackwards</span>(i, [<span class="hljs-string">'CLASS'</span>, <span class="hljs-string">'EXTENDS'</span>, <span class="hljs-string">'IF'</span>, <span class="hljs-string">'CATCH'</span>,
<span class="hljs-string">'SWITCH'</span>, <span class="hljs-string">'LEADING_WHEN'</span>, <span class="hljs-string">'FOR'</span>, <span class="hljs-string">'WHILE'</span>, <span class="hljs-string">'UNTIL'</span>])
startImplicitCall i + <span class="hljs-number">1</span>
@@ -654,7 +667,10 @@ that creates grammatical ambiguities.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> <span class="hljs-property">@tag</span>(i - <span class="hljs-number">2</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'@'</span> <span class="hljs-keyword">then</span> s = i - <span class="hljs-number">2</span> <span class="hljs-keyword">else</span> s = i - <span class="hljs-number">1</span>
<div class="content"><div class='highlight'><pre> s = <span class="hljs-keyword">switch</span>
<span class="hljs-keyword">when</span> <span class="hljs-property">@tag</span>(i - <span class="hljs-number">1</span>) <span class="hljs-keyword">in</span> EXPRESSION_END <span class="hljs-keyword">then</span> start[<span class="hljs-number">1</span>]
<span class="hljs-keyword">when</span> <span class="hljs-property">@tag</span>(i - <span class="hljs-number">2</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'@'</span> <span class="hljs-keyword">then</span> i - <span class="hljs-number">2</span>
<span class="hljs-keyword">else</span> i - <span class="hljs-number">1</span>
s -= <span class="hljs-number">2</span> <span class="hljs-keyword">while</span> <span class="hljs-property">@tag</span>(s - <span class="hljs-number">2</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'HERECOMMENT'</span></pre></div></div>
</li>
@@ -758,7 +774,7 @@ return a: 1, b: 2 unless true</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> inImplicitObject() <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@insideForDeclaration</span> <span class="hljs-keyword">and</span> sameLine <span class="hljs-keyword">and</span>
tag <span class="hljs-keyword">isnt</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">':'</span> <span class="hljs-keyword">and</span>
tag <span class="hljs-keyword">isnt</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">':'</span>
endImplicitObject()</pre></div></div>
</li>
@@ -778,6 +794,7 @@ the continuation of an object.</p>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> inImplicitObject() <span class="hljs-keyword">and</span> tag <span class="hljs-keyword">is</span> <span class="hljs-string">'TERMINATOR'</span> <span class="hljs-keyword">and</span> prevTag <span class="hljs-keyword">isnt</span> <span class="hljs-string">','</span> <span class="hljs-keyword">and</span>
<span class="hljs-keyword">not</span> (startsLine <span class="hljs-keyword">and</span> <span class="hljs-property">@looksObjectish</span>(i + <span class="hljs-number">1</span>))
<span class="hljs-keyword">return</span> forward <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> nextTag <span class="hljs-keyword">is</span> <span class="hljs-string">'HERECOMMENT'</span>
endImplicitObject()
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">break</span></pre></div></div>
@@ -1032,6 +1049,8 @@ different precedence.</p>
[<span class="hljs-string">'CALL_START'</span>, <span class="hljs-string">'CALL_END'</span>]
[<span class="hljs-string">'PARAM_START'</span>, <span class="hljs-string">'PARAM_END'</span>]
[<span class="hljs-string">'INDEX_START'</span>, <span class="hljs-string">'INDEX_END'</span>]
[<span class="hljs-string">'STRING_START'</span>, <span class="hljs-string">'STRING_END'</span>]
[<span class="hljs-string">'REGEX_START'</span>, <span class="hljs-string">'REGEX_END'</span>]
]</pre></div></div>
</li>
@@ -1114,9 +1133,10 @@ EXPRESSION_END = []
</div>
<div class="content"><div class='highlight'><pre>IMPLICIT_CALL = [
<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'JS'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'NEW'</span>, <span class="hljs-string">'PARAM_START'</span>, <span class="hljs-string">'CLASS'</span>
<span class="hljs-string">'IF'</span>, <span class="hljs-string">'TRY'</span>, <span class="hljs-string">'SWITCH'</span>, <span class="hljs-string">'THIS'</span>, <span class="hljs-string">'BOOL'</span>, <span class="hljs-string">'NULL'</span>, <span class="hljs-string">'UNDEFINED'</span>, <span class="hljs-string">'UNARY'</span>,
<span class="hljs-string">'UNARY_MATH'</span>, <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'THROW'</span>, <span class="hljs-string">'@'</span>, <span class="hljs-string">'-&gt;'</span>, <span class="hljs-string">'=&gt;'</span>, <span class="hljs-string">'['</span>, <span class="hljs-string">'('</span>, <span class="hljs-string">'{'</span>, <span class="hljs-string">'--'</span>, <span class="hljs-string">'++'</span>
<span class="hljs-string">'IDENTIFIER'</span>, <span class="hljs-string">'NUMBER'</span>, <span class="hljs-string">'STRING'</span>, <span class="hljs-string">'STRING_START'</span>, <span class="hljs-string">'JS'</span>, <span class="hljs-string">'REGEX'</span>, <span class="hljs-string">'REGEX_START'</span>
<span class="hljs-string">'NEW'</span>, <span class="hljs-string">'PARAM_START'</span>, <span class="hljs-string">'CLASS'</span>, <span class="hljs-string">'IF'</span>, <span class="hljs-string">'TRY'</span>, <span class="hljs-string">'SWITCH'</span>, <span class="hljs-string">'THIS'</span>, <span class="hljs-string">'BOOL'</span>, <span class="hljs-string">'NULL'</span>
<span class="hljs-string">'UNDEFINED'</span>, <span class="hljs-string">'UNARY'</span>, <span class="hljs-string">'YIELD'</span>, <span class="hljs-string">'UNARY_MATH'</span>, <span class="hljs-string">'SUPER'</span>, <span class="hljs-string">'THROW'</span>
<span class="hljs-string">'@'</span>, <span class="hljs-string">'-&gt;'</span>, <span class="hljs-string">'=&gt;'</span>, <span class="hljs-string">'['</span>, <span class="hljs-string">'('</span>, <span class="hljs-string">'{'</span>, <span class="hljs-string">'--'</span>, <span class="hljs-string">'++'</span>
]
IMPLICIT_UNSPACED_CALL = [<span class="hljs-string">'+'</span>, <span class="hljs-string">'-'</span>]</pre></div></div>

View File

@@ -121,13 +121,10 @@ 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 external scopes.</p>
<p>Import the helpers we plan to use.</p>
</div>
<div class="content"><div class='highlight'><pre>{extend, last} = <span class="hljs-built_in">require</span> <span class="hljs-string">'./helpers'</span>
<span class="hljs-built_in">exports</span>.Scope = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Scope</span></span></pre></div></div>
<div class="content"><div class='highlight'><pre><span class="hljs-built_in">exports</span>.Scope = <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Scope</span></span></pre></div></div>
</li>
@@ -138,11 +135,18 @@ with external scopes.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">&#182;</a>
</div>
<p>The <code>root</code> is the top-level <strong>Scope</strong> object for a given file.</p>
<p>Initialize a scope with its parent, for lookups up the chain,
as well as a reference to the <strong>Block</strong> node it belongs to, which is
where it should declare its variables, a reference to the function that
it belongs to, and a list of variables referenced in the source code
and therefore should be avoided when generating variables.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-property">@root</span>: <span class="hljs-literal">null</span></pre></div></div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@parent</span>, <span class="hljs-property">@expressions</span>, <span class="hljs-property">@method</span>, <span class="hljs-property">@referencedVars</span>)</span> -&gt;</span>
<span class="hljs-property">@variables</span> = [{<span class="hljs-attribute">name</span>: <span class="hljs-string">'arguments'</span>, <span class="hljs-attribute">type</span>: <span class="hljs-string">'arguments'</span>}]
<span class="hljs-property">@positions</span> = {}
<span class="hljs-property">@utilities</span> = {} <span class="hljs-keyword">unless</span> <span class="hljs-property">@parent</span></pre></div></div>
</li>
@@ -153,17 +157,11 @@ with external scopes.</p>
<div class="pilwrap ">
<a class="pilcrow" href="#section-3">&#182;</a>
</div>
<p>Initialize a scope with its parent, for lookups up the chain,
as well as a reference to the <strong>Block</strong> node it belongs to, which is
where it should declare its variables, and a reference to the function that
it belongs to.</p>
<p>The <code>@root</code> is the top-level <strong>Scope</strong> object for a given file.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">constructor</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@parent</span>, <span class="hljs-property">@expressions</span>, <span class="hljs-property">@method</span>)</span> -&gt;</span>
<span class="hljs-property">@variables</span> = [{<span class="hljs-attribute">name</span>: <span class="hljs-string">'arguments'</span>, <span class="hljs-attribute">type</span>: <span class="hljs-string">'arguments'</span>}]
<span class="hljs-property">@positions</span> = {}
Scope.root = <span class="hljs-keyword">this</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@parent</span></pre></div></div>
<div class="content"><div class='highlight'><pre> <span class="hljs-property">@root</span> = <span class="hljs-property">@parent</span>?.root ? <span class="hljs-keyword">this</span></pre></div></div>
</li>
@@ -273,11 +271,11 @@ walks up to the root scope.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">temporary</span>: <span class="hljs-function"><span class="hljs-params">(name, index)</span> -&gt;</span>
<span class="hljs-keyword">if</span> name.length &gt; <span class="hljs-number">1</span>
<span class="hljs-string">'_'</span> + name + <span class="hljs-keyword">if</span> index &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">then</span> index - <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">temporary</span>: <span class="hljs-function"><span class="hljs-params">(name, index, single=<span class="hljs-literal">false</span>)</span> -&gt;</span>
<span class="hljs-keyword">if</span> single
(index + parseInt name, <span class="hljs-number">36</span>).toString(<span class="hljs-number">36</span>).replace <span class="hljs-regexp">/\d/g</span>, <span class="hljs-string">'a'</span>
<span class="hljs-keyword">else</span>
<span class="hljs-string">'_'</span> + (index + parseInt name, <span class="hljs-number">36</span>).toString(<span class="hljs-number">36</span>).replace <span class="hljs-regexp">/\d/g</span>, <span class="hljs-string">'a'</span></pre></div></div>
name + (index <span class="hljs-keyword">or</span> <span class="hljs-string">''</span>)</pre></div></div>
</li>
@@ -310,10 +308,13 @@ compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on…
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">freeVariable</span>: <span class="hljs-function"><span class="hljs-params">(name, reserve=<span class="hljs-literal">true</span>)</span> -&gt;</span>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">freeVariable</span>: <span class="hljs-function"><span class="hljs-params">(name, options={})</span> -&gt;</span>
index = <span class="hljs-number">0</span>
index++ <span class="hljs-keyword">while</span> <span class="hljs-property">@check</span>((temp = <span class="hljs-property">@temporary</span> name, index))
<span class="hljs-property">@add</span> temp, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> reserve
<span class="hljs-keyword">loop</span>
temp = <span class="hljs-property">@temporary</span> name, index, options.single
<span class="hljs-keyword">break</span> <span class="hljs-keyword">unless</span> <span class="hljs-property">@check</span>(temp) <span class="hljs-keyword">or</span> temp <span class="hljs-keyword">in</span> <span class="hljs-property">@root</span>.referencedVars
index++
<span class="hljs-property">@add</span> temp, <span class="hljs-string">'var'</span>, <span class="hljs-literal">yes</span> <span class="hljs-keyword">if</span> options.reserve ? <span class="hljs-literal">true</span>
temp</pre></div></div>
</li>
@@ -364,11 +365,7 @@ compiler-generated variable. <code>_var</code>, <code>_var2</code>, and so on…
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-attribute">declaredVariables</span>:<span class="hljs-function"> -&gt;</span>
realVars = []
tempVars = []
<span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> <span class="hljs-property">@variables</span> <span class="hljs-keyword">when</span> v.type <span class="hljs-keyword">is</span> <span class="hljs-string">'var'</span>
(<span class="hljs-keyword">if</span> v.name.charAt(<span class="hljs-number">0</span>) <span class="hljs-keyword">is</span> <span class="hljs-string">'_'</span> <span class="hljs-keyword">then</span> tempVars <span class="hljs-keyword">else</span> realVars).push v.name
realVars.sort().concat tempVars.sort()</pre></div></div>
(v.name <span class="hljs-keyword">for</span> v <span class="hljs-keyword">in</span> <span class="hljs-property">@variables</span> <span class="hljs-keyword">when</span> v.type <span class="hljs-keyword">is</span> <span class="hljs-string">'var'</span>).sort()</pre></div></div>
</li>

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-76 212 458 369" enable-background="new -76 212 458 369" xml:space="preserve">
<title>CoffeeScript Logo</title>
<g>
<g>
<path fill="#28334C" d="M106,228.6c0.5,2.3-0.9,4.4-5,6.5c-5.5-3.1-16.9-4.4-26.7-3.5c-10.4,0.9-19.4,4.2-17.9,11.3
c1.5,7.1,11.7,11,29.5,9.5c43.6-3.8,43.4-33.3,107.4-39c49.8-4.4,77.8,11,81.8,29.7c3.1,14.7-9.1,28.6-45.2,31.8
c-32,2.8-50.7-5.6-52.6-14.6c-1-4.5,1.8-11.3,17.2-13.1c1.5,7,10.6,14.4,31.1,12.6c14.8-1.3,27.6-6.6,25.9-14.9
c-1.8-8.6-17.7-13.7-42.6-11.5c-50.7,4.5-63.2,32.5-106.8,36.3c-30.8,2.7-55.9-8.5-59.4-25.1c-1.3-6.1-1.4-21,31.2-23.9
C91,219.2,104.6,222.2,106,228.6L106,228.6z M-56.4,402.5c-14.3,18-20.4,38.8-19.2,59.2c1.2,20.4,11.4,37.1,26.9,50.2
C-32,525-14,528.6,6.4,525c7.8-1.2,16.7-5.3,24.5-7.8c-16.7,0-31-5.3-44.9-16.7c-15.5-11.4-25.7-26.9-28.2-46.1
c-3.7-18,0-34.7,10.2-49c11.4-14.3,25.7-22,44.9-24.5c19.2-1.2,35.9,3.7,52.6,15.5c-3.7-5.3-9-9-14.3-14.3
c-16.7-11.4-34.7-16.7-56.7-11.4C-25.4,374.3-42.2,384.5-56.4,402.5z M167.2,306.2c-53.9,0-101.6-5.3-136.3-13.1
c-37.1-9-56.7-19.2-56.7-32.2c0-5.3,2.4-10.2,10.2-15.5c-23.3,9-35.9,16.7-35.9,28.2c1.2,13.1,22,25.7,64.5,35.9
c40,10.2,91.4,15.5,153,15.5c62.8,0,113-5.3,153-15.5c42.4-10.2,62.8-23.3,62.8-35.9c0-9-9-18-25.7-24.5c3.7,2.4,6.5,6.5,6.5,11.4
c0,13.1-19.2,23.3-57.9,32.2C268.7,300.9,222.6,306.2,167.2,306.2L167.2,306.2z M320.2,342.1c-40,9-91.4,15.5-153,15.5
c-62.8,0-114.2-6.5-154.2-15.5c-35.9-9-55.1-19.2-61.6-29.4c6.5,44.9,22,87.3,42.4,124.8c15.5,23.3,31,43.7,46.1,65.7
c6.5,13.1,11.4,25.7,14.3,38.8c10.2,14.3,24.5,23.3,42.4,28.2c22,7.8,44.9,11.4,68.1,10.2h2.4c23.3,1.2,47.7-2.4,70.6-10.2
c16.7-5.3,31-14.3,41.2-28.2h1.2c2.4-13.1,6.5-25.7,13.1-38.8c15.5-22,31-42.4,46.1-65.7c20.4-37.1,34.7-79.6,42.4-124.8
C374,324.1,354.8,334.3,320.2,342.1L320.2,342.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-22 347 566 100" enable-background="new -22 347 566 100" xml:space="preserve">
<title>CoffeeScript Logo</title>
<g>
<g>
<path id="Shape" fill="#28334C" d="M21.7,351.1c0.1,0.6-0.2,1.1-1.2,1.6c-1.3-0.7-4.1-1.1-6.4-0.9c-2.5,0.2-4.6,1-4.3,2.7
c0.4,1.7,2.8,2.7,7.1,2.3c10.5-0.9,10.4-8,25.8-9.4c12-1.1,18.7,2.6,19.6,7.1c0.7,3.5-2.2,6.9-10.9,7.6
c-7.7,0.7-12.2-1.4-12.6-3.5c-0.2-1.1,0.4-2.7,4.1-3.1c0.4,1.7,2.5,3.5,7.5,3c3.6-0.3,6.6-1.6,6.2-3.6c-0.4-2.1-4.2-3.3-10.2-2.8
c-12.2,1.1-15.2,7.8-25.6,8.7c-7.4,0.7-13.4-2-14.2-6c-0.3-1.5-0.3-5,7.5-5.7C18.1,348.8,21.3,349.5,21.7,351.1z M-17.3,392.9
c-3.4,4.3-4.9,9.3-4.6,14.2c0.3,4.9,2.7,8.9,6.5,12c4,3.1,8.3,4,13.2,3.1c1.9-0.3,4-1.3,5.9-1.9c-4,0-7.4-1.3-10.8-4
c-3.7-2.7-6.2-6.5-6.8-11.1c-0.9-4.3,0-8.3,2.4-11.8c2.7-3.4,6.2-5.3,10.8-5.9c4.6-0.3,8.6,0.9,12.6,3.7c-0.9-1.3-2.2-2.2-3.4-3.4
c-4-2.7-8.3-4-13.6-2.7C-9.9,386.1-13.9,388.6-17.3,392.9z M36.3,369.8c-12.9,0-24.4-1.3-32.7-3.1c-8.9-2.2-13.6-4.6-13.6-7.7
c0-1.3,0.6-2.4,2.4-3.7c-5.6,2.2-8.6,4-8.6,6.8c0.3,3.1,5.3,6.2,15.5,8.6c9.6,2.4,21.9,3.7,36.7,3.7c15.1,0,27.1-1.3,36.7-3.7
c10.2-2.4,15.1-5.6,15.1-8.6c0-2.2-2.2-4.3-6.2-5.9c0.9,0.6,1.6,1.6,1.6,2.7c0,3.1-4.6,5.6-13.9,7.7
C60.7,368.5,49.7,369.8,36.3,369.8z M73.1,378.4c-9.6,2.2-21.9,3.7-36.7,3.7c-15.1,0-27.4-1.6-37-3.7c-8.6-2.2-13.2-4.6-14.8-7.1
c1.6,10.8,5.3,21,10.2,30c3.7,5.6,7.4,10.5,11.1,15.8c1.6,3.1,2.7,6.2,3.4,9.3c2.4,3.4,5.9,5.6,10.2,6.8
c5.3,1.9,10.8,2.7,16.4,2.4h0.6c5.6,0.3,11.5-0.6,16.9-2.4c4-1.3,7.4-3.4,9.9-6.8h0.3c0.6-3.1,1.6-6.2,3.1-9.3
c3.7-5.3,7.4-10.2,11.1-15.8c4.9-8.9,8.3-19.1,10.2-30C86,374.1,81.4,376.5,73.1,378.4z"/>
<g>
<path fill="#28334C" d="M179.3,408.5c-4.8,12.1-17.6,16.9-25.9,16.9c-13.4,0-19.9-6-19.9-22.3c0-16.5,7.9-47.3,31.7-47.3
c8.5,0,15.2,3.3,15.2,12.1c0,4.8-1.8,8.3-6.4,8.3c-1.5,0-3.4-0.4-5.2-2.4c2.2-1.1,4.2-4.9,4.2-8.3c0-2.9-1.5-5.6-5.6-5.6
c-10,0-18.9,23.9-18.9,42.4c0,8.3,2.2,14.2,10.9,14.2c7.1,0,13.5-3.4,17.7-9.1L179.3,408.5z M212.2,392.2c0.4,0.2,0.7,0.2,1,0.2
c4.2,0,10.1-2.7,14-5.5l0.8,2.4c-3.4,3.7-9.5,6.5-16.1,7.5c-1.5,16.8-10.6,27.3-21.7,27.3c-8.4,0-14.5-4-14.5-14.4
c0-10.5,6.2-32.2,24.9-32.2C208.4,377.8,212.2,382.8,212.2,392.2z M204.5,397.2c-1.9-0.5-2.4-2-2.4-3.8c0-2.5,1.2-4.2,2.8-4.9
c-0.2-3.8-1.1-5.3-3.4-5.3c-6.5,0-12,16.6-12,25.6c0,6,1.2,7.3,4.6,7.3C198.3,416.2,203,408.1,204.5,397.2L204.5,397.2z
M197.9,436.9c0-8.3,7.1-11,15.8-13.6l10.9-51.9c2.7-13,10.6-15.5,16.5-15.5c4.1,0,8,2.2,9.7,5.7c3.6-4.6,8.4-5.7,12.4-5.7
c5.6,0,10.8,3.9,10.8,9.8c0,1.5-0.1,2.6-0.3,3.7h-4.3c0.1-0.9,0.2-1.7,0.2-2.4c0-2.1-1.7-3.1-3.4-3.1c-2,0-4.8,1.1-6.2,7.1
l-1.7,7.4h9.1l-0.8,3.6h-9l-10.3,49.1c-2.7,13-10.6,15.5-16.5,15.5c-5.2,0-8.3-2.3-9.8-5.7c-3.5,4.6-8.3,5.7-12.3,5.7
C203.1,446.7,197.9,442.8,197.9,436.9L197.9,436.9z M207,438.7c1.9,0,4.2-1.8,5.4-7.1l1.1-5.3c-5.7,2-10.1,4.4-10.1,9.4
C203.4,436.9,205.1,438.7,207,438.7z M228.7,438.7c1.9,0,4.2-1.8,5.4-7.1l2.2-10.4l-9.4,1.8l-1.8,8.3c-0.5,2.1-1.1,4-1.8,5.6
C224.2,438.2,226.3,438.7,228.7,438.7L228.7,438.7z M227.3,420.7l9.4-1.7l7.7-36.8h-9L227.3,420.7L227.3,420.7z M243.9,364
c-2,0-4.8,1.1-6.2,7.1l-1.7,7.4h9l2.1-9.5c0.2-0.7,0.2-1.3,0.2-2C247.4,365,245.8,364,243.9,364z M281.8,417
c7.1,0,11.6-4,16.1-9.2h3.1c-5.2,8.3-12.9,16.8-25,16.8c-8.5,0-14.2-4.2-14.2-14.5c0-10.5,5.9-32.3,24.6-32.3
c8.1,0,10,4.2,10,8.7c0,10.5-10,18.5-20.9,19.2c-0.1,1.3-0.2,2.5-0.2,3.6C275.3,415.5,277.5,417,281.8,417z M287.1,382.6
c-4.6,0-9.1,9.7-10.9,18.7c7-0.5,13.2-7.4,13.2-15C289.4,384.1,288.9,382.6,287.1,382.6L287.1,382.6z M315.7,416
c3.4,0,7.8-2.3,10.8-4.8c-2,10.4-8.4,13.4-15.8,13.4c-8.4,0-14.1-4.2-14.1-14.5c0-10.5,5.9-32.3,24.6-32.3c8.1,0,10,4.2,10,8.7
c0,10.6-10,18.5-20.9,19.2c-0.1,0.9-0.2,2-0.2,2.7C310.1,414.1,312.6,416,315.7,416z M321.9,382.6c-4.5,0-9.1,10.1-11,18.7
c7.1-0.4,13.3-7.3,13.3-15C324.2,384.1,323.6,382.6,321.9,382.6z M373.2,375.9c-1.7,0-3-0.6-4.2-1.9c2.4-1.5,4.1-4.8,4.1-7.8
c0-3.1-1.8-6.1-6.8-6.1s-8.3,2.8-8.3,8.2c0,13.3,20.5,15.2,20.5,34.8c0,15.3-12.3,22.7-25.6,22.7c-10.4,0-19.3-4.5-19.3-15.7
c0-9.8,7-14.9,13.3-14.9c3.1,0,7.7,1.3,8,6c-4.9,0-10.7,2.3-10.7,8.5c0,4.5,2.9,8.7,8.7,8.7c6.1,0,10.6-4.4,10.6-12
c0-15.6-18.6-21.1-18.6-34.5c0-9.5,9.3-16.3,21-16.3c4.3,0,14.6,0.9,14.6,10.9C380.6,372,377.7,375.9,373.2,375.9L373.2,375.9z
M409.4,386.2c0-2.3-0.8-3.7-2.5-3.7c-5.7,0-11.7,16.6-11.7,26.7c0,6.2,2.2,7.6,6.6,7.6c7.1,0,11.6-4,16.1-9.2h3.1
c-5.2,8.3-12.9,16.8-25,16.8c-8.5,0-14.2-4.2-14.2-14.5c0-10.6,6-32.3,24.5-32.3c8.1,0,10.1,4.2,10.1,8.3c0,4.4-2.2,6.7-4.8,6.7
c-1,0-2.1-0.4-3.1-1.1C409,389.6,409.4,387.9,409.4,386.2z M437.1,378.6l-1.2,5.7c3.1-2.7,6.7-5.7,11-5.7c4.1,0,6.3,3.3,6.3,6.9
c0,3.1-2.1,6.7-6.6,6.7c-5.1,0-2.5-6-5.3-6c-2.7,0-4.4,1.4-6.7,3.4l-7.2,34.6h-13.1l9.6-45.4L437.1,378.6L437.1,378.6z
M471.3,378.6l-6.6,30.9c-0.3,1.2-0.4,2.1-0.4,2.9c0,2.5,1.2,3.3,3.7,3.3c3.5,0,6.9-3.4,8.1-8h3.8c-5.2,14.8-14.2,16.8-19.1,16.8
c-5.5,0-9.7-3.2-9.7-10.9c0-1.8,0.3-3.7,0.7-5.9l6.2-29.2C458,378.5,471.3,378.6,471.3,378.6z M467.2,359.2c4,0,7.2,3.2,7.2,7.2
s-3.2,7.1-7.2,7.1s-7.1-3.1-7.1-7.1C460,362.4,463.3,359.2,467.2,359.2z M496.3,375.2l-1.5,6.9c2.6-2.3,6.1-3.9,10.7-3.9
c6.2,0,11.1,3.5,11.1,14.4c0,12.2-4.7,32.1-22.3,32.1c-4.5,0-6.8-1.6-7.7-3.2l-4.7,22.1l-13.7,3.2l15.2-71.5
C483.4,375.3,496.3,375.2,496.3,375.2z M504.1,392.2c0-7-2.9-7.5-4.5-7.5c-2,0-4.5,1.6-6.3,4.4l-5.4,25.5c0.4,1,1.4,2.1,3.4,2.1
C501,416.7,504.1,400.8,504.1,392.2z M531.9,409.5c-0.3,1.1-0.5,2.2-0.5,3.1c0,1.9,0.7,3.2,3.1,3.2c0.7,0,1.7,0,2.4-0.3
c-2.5,7.8-6.6,8.9-9.6,8.9c-6.4,0-9.1-4.4-9.1-10.3c0-1.6,0.2-3.1,0.6-4.8l5.8-27.2h-3l0.7-3.6h3L528,366l13.4-1.9
c0,0-1.4,6.2-3.1,14.4h5.5l-0.7,3.6h-5.5L531.9,409.5z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -34,7 +34,7 @@
<a href="#operators">Operators and Aliases</a>
<a href="#classes">Classes, Inheritance, and Super</a>
<a href="#destructuring">Destructuring Assignment</a>
<a href="#fat-arrow">Function Binding</a>
<a href="#fat-arrow">Bound and Generator Functions</a>
<a href="#embedded">Embedded JavaScript</a>
<a href="#switch">Switch and Try/Catch</a>
<a href="#comparisons">Chained Comparisons</a>
@@ -110,7 +110,7 @@
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffeescript/tarball/1.8.0">1.8.0</a>
<a href="http://github.com/jashkenas/coffeescript/tarball/1.9.1">1.9.1</a>
</p>
<pre>npm install -g coffee-script</pre>
@@ -142,8 +142,8 @@
<p>
To install, first make sure you have a working copy of the latest stable version of
<a href="http://nodejs.org/">Node.js</a>, and <a href="http://npmjs.org">npm</a>
(the Node Package Manager). You can then install CoffeeScript globally with npm:
<a href="http://nodejs.org/">Node.js</a>. You can then install CoffeeScript globally
with <a href="http://npmjs.org">npm</a>:
</p>
<pre>
@@ -707,7 +707,7 @@ Expressions
<%= codeFor('soaks') %>
<p>
Soaking up nulls is similar to Ruby's
<a href="http://andand.rubyforge.org/">andand gem</a>, and to the
<a href="https://rubygems.org/gems/andand">andand gem</a>, and to the
<a href="http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator%28%3F.%29">safe navigation operator</a>
in Groovy.
</p>
@@ -793,7 +793,7 @@ Expressions
<p>
<span id="fat-arrow" class="bookmark"></span>
<b class="header">Function binding</b>
<b class="header">Bound Functions, Generator Functions</b>
In JavaScript, the <tt>this</tt> keyword is dynamically scoped to mean the
object that the current function is attached to. If you pass a function as
a callback or attach it to a different object, the original value of <tt>this</tt>
@@ -820,6 +820,13 @@ Expressions
be automatically bound to each instance of the class when the instance is
constructed.
</p>
<p>
CoffeeScript functions also support
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*">ES6 generator functions</a>
through the <tt>yield</tt> keyword. There's no <tt>function*(){}</tt>
nonsense &mdash; a generator in CoffeeScript is simply a function that yields.
</p>
<%= codeFor('generators', 'ps.next().value') %>
<p>
<span id="embedded" class="bookmark"></span>
@@ -1045,14 +1052,18 @@ Expressions
</li>
<li>
<a href="http://www.packtpub.com/coffeescript-application-development/book">CoffeeScript Application Development</a>
is a new book from Packt Publishing that introduces CoffeeScript while
from Packt, introduces CoffeeScript while
walking through the process of building a demonstration web application.
</li>
<li>
<a href="http://www.manning.com/lee/">CoffeeScript in Action</a>
is a new book from Manning Publications that covers CoffeeScript syntax, composition techniques
from Manning Publications, covers CoffeeScript syntax, composition techniques
and application development.
</li>
<li>
<a href="http://www.dpunkt.de/buecher/4021/coffeescript.html">CoffeeScript: Die Alternative zu JavaScript</a>
from dpunkt.verlag, is the first CoffeeScript book in Deutsch.
</li>
</ul>
<h2>
@@ -1115,8 +1126,8 @@ Expressions
the Bolo tank game for modern browsers.
</li>
<li>
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
<a href="http://rack.rubyforge.org/">Rack</a> server.
<b>github</b>'s <a href="https://atom.io/">Atom</a>,
a hackable text editor built on web technologies.
</li>
</ul>
@@ -1192,6 +1203,53 @@ Expressions
Change Log
</h2>
<p>
<%= releaseHeader('2015-02-18', '1.9.1', '1.9.0') %>
<ul>
<li>
Interpolation now works in object literal keys (again). You can use this to
dynamically name properties.
</li>
<li>
Internal compiler names no longer start with underscores. This makes
the generated JavaScript a bit prettier, and also fixes an issue with
the completely broken and ungodly way that AngularJS "parses" function
arguments.
</li>
<li>
Fixed a few <tt>yield</tt>-related bugs.
</li>
<li>
Minor bug fixes and various improvements to compiler error messages.
</li>
</ul>
</p>
<p>
<%= releaseHeader('2015-01-29', '1.9.0', '1.8.0') %>
<ul>
<li>
CoffeeScript now supports ES6 generators. A generator is simply a function
that <tt>yield</tt>s.
</li>
<li>
More robust parsing and improved error messages for strings and regexes —
especially with respect to interpolation.
</li>
<li>
Changed strategy for the generation of internal compiler variable names.
Note that this means that <tt>@example</tt> function parameters are no longer
available as naked <tt>example</tt> variables within the function body.
</li>
<li>
Fixed REPL compatibility with latest versions of Node and Io.js.
</li>
<li>
Various minor bug fixes.
</li>
</ul>
</p>
<p>
<%= releaseHeader('2014-08-26', '1.8.0', '1.7.1') %>
<ul>
@@ -1463,7 +1521,7 @@ Expressions
effectively creating a shallow copy of the list.
</li>
<li>
Additional tweaks and improvments to <tt>coffee --watch</tt> under
Additional tweaks and improvements to <tt>coffee --watch</tt> under
Node's "new" file watching API. Watch will now beep by default
if you introduce a syntax error into a watched script. We also now
ignore hidden directories by default when watching recursively.

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var volume, winner;
if (ignition === true) {

View File

@@ -1,23 +1,23 @@
// Generated by CoffeeScript 1.8.0
var courses, dish, food, foods, i, _i, _j, _k, _len, _len1, _len2, _ref;
// Generated by CoffeeScript 1.9.1
var courses, dish, food, foods, i, j, k, l, len, len1, len2, ref;
_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
food = _ref[_i];
ref = ['toast', 'cheese', 'wine'];
for (j = 0, len = ref.length; j < len; j++) {
food = ref[j];
eat(food);
}
courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'];
for (i = _j = 0, _len1 = courses.length; _j < _len1; i = ++_j) {
for (i = k = 0, len1 = courses.length; k < len1; i = ++k) {
dish = courses[i];
menu(i + 1, dish);
}
foods = ['broccoli', 'spinach', 'chocolate'];
for (_k = 0, _len2 = foods.length; _k < _len2; _k++) {
food = foods[_k];
for (l = 0, len2 = foods.length; l < len2; l++) {
food = foods[l];
if (food !== 'chocolate') {
eat(food);
}

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
/*
SkinnyMochaHalfCaffScript Compiler v1.0

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var fs;
fs = require('fs');
@@ -10,5 +10,5 @@ task('build:parser', 'rebuild the Jison parser', function(options) {
require('jison');
code = require('./lib/grammar').parser.generate();
dir = options.output || 'lib';
return fs.writeFile("" + dir + "/parser.js", code);
return fs.writeFile(dir + "/parser.js", code);
});

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
$('body').click(function(e) {
return $('.box').fadeIn('fast').addClass('.active');
}).css('background', 'white');

View File

@@ -1,7 +1,7 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var Animal, Horse, Snake, sam, tom,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
Animal = (function() {
function Animal(name) {
@@ -16,8 +16,8 @@ Animal = (function() {
})();
Snake = (function(_super) {
__extends(Snake, _super);
Snake = (function(superClass) {
extend(Snake, superClass);
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
@@ -32,8 +32,8 @@ Snake = (function(_super) {
})(Animal);
Horse = (function(_super) {
__extends(Horse, _super);
Horse = (function(superClass) {
extend(Horse, superClass);
function Horse() {
return Horse.__super__.constructor.apply(this, arguments);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var cholesterol, healthy;
cholesterol = 127;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var date, mood;
if (singing) {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var Person, tim;
Person = (function() {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var fill;
fill = function(container, liquid) {

View File

@@ -1,12 +1,12 @@
// Generated by CoffeeScript 1.8.0
var filename, _fn, _i, _len;
// Generated by CoffeeScript 1.9.1
var filename, fn, i, len;
_fn = function(filename) {
fn = function(filename) {
return fs.readFile(filename, function(err, contents) {
return compile(filename, contents.toString());
});
};
for (_i = 0, _len = list.length; _i < _len; _i++) {
filename = list[_i];
_fn(filename);
for (i = 0, len = list.length; i < len; i++) {
filename = list[i];
fn(filename);
}

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var hi;
hi = function() {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var footprints, solipsism, speed;
if ((typeof mind !== "undefined" && mind !== null) && (typeof world === "undefined" || world === null)) {

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.8.0
var first, last, text, _ref;
// Generated by CoffeeScript 1.9.1
var first, last, ref, text;
text = "Every literary critic believes he will outwit history and have the last word";
_ref = text.split(" "), first = _ref[0], last = _ref[_ref.length - 1];
ref = text.split(" "), first = ref[0], last = ref[ref.length - 1];

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var eldest, grade;
grade = function(student) {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var one, six, three, two;
six = (one = 1) + (two = 2) + (three = 3);

View File

@@ -1,11 +1,11 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var globals, name;
globals = ((function() {
var _results;
_results = [];
var results;
results = [];
for (name in window) {
_results.push(name);
results.push(name);
}
return _results;
return results;
})()).slice(0, 10);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var error;
alert((function() {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var Account;
Account = function(customer, cart) {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var cube, square;
square = function(x) {

View File

@@ -0,0 +1,13 @@
// Generated by CoffeeScript 1.9.1
var perfectSquares;
perfectSquares = function*() {
var num;
num = 0;
while (true) {
num += 1;
(yield num * num);
}
};
window.ps || (window.ps = perfectSquares());

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var html;
html = "<strong>\n cup of coffeescript\n</strong>";

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var OPERATOR;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var author, quote, sentence;
author = "Wittgenstein";
quote = "A picture is a fact. -- " + author;
sentence = "" + (22 / 7) + " is a decent approximation of π";
sentence = (22 / 7) + " is a decent approximation of π";

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.8.0
var city, forecast, temp, weatherReport, _ref;
// Generated by CoffeeScript 1.9.1
var city, forecast, ref, temp, weatherReport;
weatherReport = function(location) {
return [location, 72, "Mostly Sunny"];
};
_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
ref = weatherReport("Berkeley, CA"), city = ref[0], temp = ref[1], forecast = ref[2];

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var age, ages, child, yearsOld;
yearsOld = {
@@ -8,11 +8,11 @@ yearsOld = {
};
ages = (function() {
var _results;
_results = [];
var results;
results = [];
for (child in yearsOld) {
age = yearsOld[child];
_results.push("" + child + " is " + age);
results.push(child + " is " + age);
}
return _results;
return results;
})();

View File

@@ -1,5 +1,5 @@
// Generated by CoffeeScript 1.8.0
var city, futurists, name, street, _ref, _ref1;
// Generated by CoffeeScript 1.9.1
var city, futurists, name, ref, ref1, street;
futurists = {
sculptor: "Umberto Boccioni",
@@ -10,4 +10,4 @@ futurists = {
}
};
_ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0], city = _ref1[1]);
ref = futurists.poet, name = ref.name, (ref1 = ref.address, street = ref1[0], city = ref1[1]);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var bitlist, kids, singers, song;
song = ["do", "re", "mi", "fa", "so"];

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
$('.account').attr({
"class": 'active'
});

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var cubes, list, math, num, number, opposite, race, square,
__slice = [].slice;
slice = [].slice;
number = 42;
@@ -26,7 +26,7 @@ math = {
race = function() {
var runners, winner;
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
winner = arguments[0], runners = 2 <= arguments.length ? slice.call(arguments, 1) : [];
return print(winner, runners);
};
@@ -35,11 +35,11 @@ if (typeof elvis !== "undefined" && elvis !== null) {
}
cubes = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
num = list[_i];
_results.push(math.cube(num));
var i, len, results;
results = [];
for (i = 0, len = list.length; i < len; i++) {
num = list[i];
results.push(math.cube(num));
}
return _results;
return results;
})();

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.8.0
var theBait, theSwitch, _ref;
// Generated by CoffeeScript 1.9.1
var ref, theBait, theSwitch;
theBait = 1000;
theSwitch = 0;
_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
ref = [theSwitch, theBait], theBait = ref[0], theSwitch = ref[1];

View File

@@ -1,7 +1,7 @@
// Generated by CoffeeScript 1.8.0
var close, contents, open, tag, _i, _ref,
__slice = [].slice;
// Generated by CoffeeScript 1.9.1
var close, contents, i, open, ref, tag,
slice = [].slice;
tag = "<impossible>";
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
ref = tag.split(""), open = ref[0], contents = 3 <= ref.length ? slice.call(ref, 1, i = ref.length - 1) : (i = 1, []), close = ref[i++];

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
String.prototype.dasherize = function() {
return this.replace(/_/g, "-");
};

View File

@@ -1,11 +1,11 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var countdown, num;
countdown = (function() {
var _i, _results;
_results = [];
for (num = _i = 10; _i >= 1; num = --_i) {
_results.push(num);
var i, results;
results = [];
for (num = i = 10; i >= 1; num = --i) {
results.push(num);
}
return _results;
return results;
})();

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var changeNumbers, inner, outer;
outer = 1;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var copy, end, middle, numbers, start;
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
var zip, _ref;
// Generated by CoffeeScript 1.9.1
var ref, zip;
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
zip = typeof lottery.drawWinner === "function" ? (ref = lottery.drawWinner().address) != null ? ref.zipcode : void 0 : void 0;

View File

@@ -1,12 +1,12 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var awardMedals, contenders, gold, rest, silver,
__slice = [].slice;
slice = [].slice;
gold = silver = rest = "unknown";
awardMedals = function() {
var first, others, second;
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? slice.call(arguments, 2) : [];
gold = first;
silver = second;
return rest = others;

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.8.0
var numbers, _ref;
// Generated by CoffeeScript 1.9.1
var numbers, ref;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
[].splice.apply(numbers, [3, 4].concat(ref = [-3, -4, -5, -6])), ref;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var mobyDick;
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
switch (day) {
case "Mon":
go(work);

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var grade, score;
score = 76;

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var error;
try {

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
var lyrics, num;
if (this.studyingEconomics) {
@@ -13,10 +13,10 @@ if (this.studyingEconomics) {
num = 6;
lyrics = (function() {
var _results;
_results = [];
var results;
results = [];
while (num -= 1) {
_results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
}
return _results;
return results;
})();

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@
<a href="#operators">Operators and Aliases</a>
<a href="#classes">Classes, Inheritance, and Super</a>
<a href="#destructuring">Destructuring Assignment</a>
<a href="#fat-arrow">Function Binding</a>
<a href="#fat-arrow">Bound and Generator Functions</a>
<a href="#embedded">Embedded JavaScript</a>
<a href="#switch">Switch and Try/Catch</a>
<a href="#comparisons">Chained Comparisons</a>
@@ -110,7 +110,7 @@
<p>
<b>Latest Version:</b>
<a href="http://github.com/jashkenas/coffeescript/tarball/1.8.0">1.8.0</a>
<a href="http://github.com/jashkenas/coffeescript/tarball/1.9.1">1.9.1</a>
</p>
<pre>npm install -g coffee-script</pre>
@@ -151,7 +151,7 @@ alert <span class="string">"I knew it!"</span> <span class="keyword">if</span> e
<span class="comment"># Array comprehensions:</span>
cubes = (math.cube num <span class="keyword">for</span> num <span class="keyword">in</span> list)
</code></pre><pre><code><span class="keyword">var</span> cubes, list, math, num, number, opposite, race, square,
__slice = [].slice;
slice = [].slice;
number = <span class="number">42</span>;
@@ -177,7 +177,7 @@ math = {
race = <span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> runners, winner;
winner = <span class="built_in">arguments</span>[<span class="number">0</span>], runners = <span class="number">2</span> &lt;= <span class="built_in">arguments</span>.length ? __slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>) : [];
winner = <span class="built_in">arguments</span>[<span class="number">0</span>], runners = <span class="number">2</span> &lt;= <span class="built_in">arguments</span>.length ? slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>) : [];
<span class="keyword">return</span> print(winner, runners);
};
@@ -186,16 +186,16 @@ race = <span class="function"><span class="keyword">function</span><span class="
}
cubes = (<span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> _i, _len, _results;
_results = [];
<span class="keyword">for</span> (_i = <span class="number">0</span>, _len = list.length; _i &lt; _len; _i++) {
num = list[_i];
_results.push(math.cube(num));
<span class="keyword">var</span> i, len, results;
results = [];
<span class="keyword">for</span> (i = <span class="number">0</span>, len = list.length; i &lt; len; i++) {
num = list[i];
results.push(math.cube(num));
}
<span class="keyword">return</span> _results;
<span class="keyword">return</span> results;
})();
</code></pre><script>window.example1 = "# Assignment:\nnumber = 42\nopposite = true\n\n# Conditions:\nnumber = -42 if opposite\n\n# Functions:\nsquare = (x) -> x * x\n\n# Arrays:\nlist = [1, 2, 3, 4, 5]\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n\n# Existence:\nalert \"I knew it!\" if elvis?\n\n# Array comprehensions:\ncubes = (math.cube num for num in list)\n"</script><div class='minibutton ok' onclick='javascript: var cubes, list, math, num, number, opposite, race, square,
__slice = [].slice;
slice = [].slice;
number = 42;
@@ -221,7 +221,7 @@ math = {
race = function() {
var runners, winner;
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
winner = arguments[0], runners = 2 <= arguments.length ? slice.call(arguments, 1) : [];
return print(winner, runners);
};
@@ -230,13 +230,13 @@ if (typeof elvis !== "undefined" && elvis !== null) {
}
cubes = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
num = list[_i];
_results.push(math.cube(num));
var i, len, results;
results = [];
for (i = 0, len = list.length; i < len; i++) {
num = list[i];
results.push(math.cube(num));
}
return _results;
return results;
})();
;alert(cubes);'>run: cubes</div><br class='clear' /></div>
@@ -258,8 +258,8 @@ cubes = (function() {
<p>
To install, first make sure you have a working copy of the latest stable version of
<a href="http://nodejs.org/">Node.js</a>, and <a href="http://npmjs.org">npm</a>
(the Node Package Manager). You can then install CoffeeScript globally with npm:
<a href="http://nodejs.org/">Node.js</a>. You can then install CoffeeScript globally
with <a href="http://npmjs.org">npm</a>:
</p>
<pre>
@@ -807,13 +807,13 @@ alert <span class="string">"The Field: "</span> + rest
</code></pre><pre><code><span class="keyword">var</span> awardMedals, contenders, gold, rest, silver,
__slice = [].slice;
slice = [].slice;
gold = silver = rest = <span class="string">"unknown"</span>;
awardMedals = <span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> first, others, second;
first = <span class="built_in">arguments</span>[<span class="number">0</span>], second = <span class="built_in">arguments</span>[<span class="number">1</span>], others = <span class="number">3</span> &lt;= <span class="built_in">arguments</span>.length ? __slice.call(<span class="built_in">arguments</span>, <span class="number">2</span>) : [];
first = <span class="built_in">arguments</span>[<span class="number">0</span>], second = <span class="built_in">arguments</span>[<span class="number">1</span>], others = <span class="number">3</span> &lt;= <span class="built_in">arguments</span>.length ? slice.call(<span class="built_in">arguments</span>, <span class="number">2</span>) : [];
gold = first;
silver = second;
<span class="keyword">return</span> rest = others;
@@ -829,13 +829,13 @@ alert(<span class="string">"Silver: "</span> + silver);
alert(<span class="string">"The Field: "</span> + rest);
</code></pre><script>window.example8 = "gold = silver = rest = \"unknown\"\n\nawardMedals = (first, second, others...) ->\n gold = first\n silver = second\n rest = others\n\ncontenders = [\n \"Michael Phelps\"\n \"Liu Xiang\"\n \"Yao Ming\"\n \"Allyson Felix\"\n \"Shawn Johnson\"\n \"Roman Sebrle\"\n \"Guo Jingjing\"\n \"Tyson Gay\"\n \"Asafa Powell\"\n \"Usain Bolt\"\n]\n\nawardMedals contenders...\n\nalert \"Gold: \" + gold\nalert \"Silver: \" + silver\nalert \"The Field: \" + rest\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example8);'>load</div><div class='minibutton ok' onclick='javascript: var awardMedals, contenders, gold, rest, silver,
__slice = [].slice;
slice = [].slice;
gold = silver = rest = "unknown";
awardMedals = function() {
var first, others, second;
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? slice.call(arguments, 2) : [];
gold = first;
silver = second;
return rest = others;
@@ -871,25 +871,25 @@ menu i + <span class="number">1</span>, dish <span class="keyword">for</span> di
<span class="comment"># Health conscious meal.</span>
foods = [<span class="string">'broccoli'</span>, <span class="string">'spinach'</span>, <span class="string">'chocolate'</span>]
eat food <span class="keyword">for</span> food <span class="keyword">in</span> foods <span class="keyword">when</span> food <span class="keyword">isnt</span> <span class="string">'chocolate'</span>
</code></pre><pre><code><span class="keyword">var</span> courses, dish, food, foods, i, _i, _j, _k, _len, _len1, _len2, _ref;
</code></pre><pre><code><span class="keyword">var</span> courses, dish, food, foods, i, j, k, l, len, len1, len2, ref;
_ref = [<span class="string">'toast'</span>, <span class="string">'cheese'</span>, <span class="string">'wine'</span>];
<span class="keyword">for</span> (_i = <span class="number">0</span>, _len = _ref.length; _i &lt; _len; _i++) {
food = _ref[_i];
ref = [<span class="string">'toast'</span>, <span class="string">'cheese'</span>, <span class="string">'wine'</span>];
<span class="keyword">for</span> (j = <span class="number">0</span>, len = ref.length; j &lt; len; j++) {
food = ref[j];
eat(food);
}
courses = [<span class="string">'greens'</span>, <span class="string">'caviar'</span>, <span class="string">'truffles'</span>, <span class="string">'roast'</span>, <span class="string">'cake'</span>];
<span class="keyword">for</span> (i = _j = <span class="number">0</span>, _len1 = courses.length; _j &lt; _len1; i = ++_j) {
<span class="keyword">for</span> (i = k = <span class="number">0</span>, len1 = courses.length; k &lt; len1; i = ++k) {
dish = courses[i];
menu(i + <span class="number">1</span>, dish);
}
foods = [<span class="string">'broccoli'</span>, <span class="string">'spinach'</span>, <span class="string">'chocolate'</span>];
<span class="keyword">for</span> (_k = <span class="number">0</span>, _len2 = foods.length; _k &lt; _len2; _k++) {
food = foods[_k];
<span class="keyword">for</span> (l = <span class="number">0</span>, len2 = foods.length; l &lt; len2; l++) {
food = foods[l];
<span class="keyword">if</span> (food !== <span class="string">'chocolate'</span>) {
eat(food);
}
@@ -908,22 +908,22 @@ foods = [<span class="string">'broccoli'</span>, <span class="string">'spinach'<
</code></pre><pre><code><span class="keyword">var</span> countdown, num;
countdown = (<span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> _i, _results;
_results = [];
<span class="keyword">for</span> (num = _i = <span class="number">10</span>; _i &gt;= <span class="number">1</span>; num = --_i) {
_results.push(num);
<span class="keyword">var</span> i, results;
results = [];
<span class="keyword">for</span> (num = i = <span class="number">10</span>; i &gt;= <span class="number">1</span>; num = --i) {
results.push(num);
}
<span class="keyword">return</span> _results;
<span class="keyword">return</span> results;
})();
</code></pre><script>window.example10 = "countdown = (num for num in [10..1])\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example10);'>load</div><div class='minibutton ok' onclick='javascript: var countdown, num;
countdown = (function() {
var _i, _results;
_results = [];
for (num = _i = 10; _i >= 1; num = --_i) {
_results.push(num);
var i, results;
results = [];
for (num = i = 10; i >= 1; num = --i) {
results.push(num);
}
return _results;
return results;
})();
;alert(countdown);'>run: countdown</div><br class='clear' /></div>
<p>
@@ -958,13 +958,13 @@ yearsOld = {
};
ages = (<span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> _results;
_results = [];
<span class="keyword">var</span> results;
results = [];
<span class="keyword">for</span> (child <span class="keyword">in</span> yearsOld) {
age = yearsOld[child];
_results.push(<span class="string">""</span> + child + <span class="string">" is "</span> + age);
results.push(child + <span class="string">" is "</span> + age);
}
<span class="keyword">return</span> _results;
<span class="keyword">return</span> results;
})();
</code></pre><script>window.example11 = "yearsOld = max: 10, ida: 9, tim: 11\n\nages = for child, age of yearsOld\n \"#{child} is #{age}\"\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example11);'>load</div><div class='minibutton ok' onclick='javascript: var age, ages, child, yearsOld;
@@ -975,13 +975,13 @@ yearsOld = {
};
ages = (function() {
var _results;
_results = [];
var results;
results = [];
for (child in yearsOld) {
age = yearsOld[child];
_results.push("" + child + " is " + age);
results.push(child + " is " + age);
}
return _results;
return results;
})();
;alert(ages.join(", "));'>run: ages.join(", ")</div><br class='clear' /></div>
<p>
@@ -1020,12 +1020,12 @@ lyrics = <span class="keyword">while</span> num -= <span class="number">1</span>
num = <span class="number">6</span>;
lyrics = (<span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> _results;
_results = [];
<span class="keyword">var</span> results;
results = [];
<span class="keyword">while</span> (num -= <span class="number">1</span>) {
_results.push(<span class="string">""</span> + num + <span class="string">" little monkeys, jumping on the bed. One fell out and bumped his head."</span>);
results.push(num + <span class="string">" little monkeys, jumping on the bed. One fell out and bumped his head."</span>);
}
<span class="keyword">return</span> _results;
<span class="keyword">return</span> results;
})();
</code></pre><script>window.example12 = "# Econ 101\nif this.studyingEconomics\n buy() while supply > demand\n sell() until supply > demand\n\n# Nursery Rhyme\nnum = 6\nlyrics = while num -= 1\n \"#{num} little monkeys, jumping on the bed.\n One fell out and bumped his head.\"\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example12);'>load</div><div class='minibutton ok' onclick='javascript: var lyrics, num;
@@ -1041,12 +1041,12 @@ if (this.studyingEconomics) {
num = 6;
lyrics = (function() {
var _results;
_results = [];
var results;
results = [];
while (num -= 1) {
_results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
}
return _results;
return results;
})();
;alert(lyrics.join("
"));'>run: lyrics.join("
@@ -1065,16 +1065,16 @@ lyrics = (function() {
<div class='code'><pre><code><span class="keyword">for</span> filename <span class="keyword">in</span> list
<span class="keyword">do</span> <span class="function"><span class="params">(filename)</span> -&gt;</span>
fs.readFile filename, <span class="function"><span class="params">(err, contents)</span> -&gt;</span>
compile filename, contents.toString()</code></pre><pre><code><span class="keyword">var</span> filename, _fn, _i, _len;
compile filename, contents.toString()</code></pre><pre><code><span class="keyword">var</span> filename, fn, i, len;
_fn = <span class="function"><span class="keyword">function</span><span class="params">(filename)</span> {</span>
fn = <span class="function"><span class="keyword">function</span><span class="params">(filename)</span> {</span>
<span class="keyword">return</span> fs.readFile(filename, <span class="function"><span class="keyword">function</span><span class="params">(err, contents)</span> {</span>
<span class="keyword">return</span> compile(filename, contents.toString());
});
};
<span class="keyword">for</span> (_i = <span class="number">0</span>, _len = list.length; _i &lt; _len; _i++) {
filename = list[_i];
_fn(filename);
<span class="keyword">for</span> (i = <span class="number">0</span>, len = list.length; i &lt; len; i++) {
filename = list[i];
fn(filename);
}
</code></pre><script>window.example13 = "for filename in list\n do (filename) ->\n fs.readFile filename, (err, contents) ->\n compile filename, contents.toString()"</script><div class='minibutton load' onclick='javascript: loadConsole(example13);'>load</div><br class='clear' /></div>
@@ -1129,16 +1129,16 @@ numbers[<span class="number">3.</span><span class="number">.6</span>] = [-<span
</code></pre><pre><code><span class="keyword">var</span> numbers, _ref;
</code></pre><pre><code><span class="keyword">var</span> numbers, ref;
numbers = [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>];
[].splice.apply(numbers, [<span class="number">3</span>, <span class="number">4</span>].concat(_ref = [-<span class="number">3</span>, -<span class="number">4</span>, -<span class="number">5</span>, -<span class="number">6</span>])), _ref;
</code></pre><script>window.example15 = "numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\nnumbers[3..6] = [-3, -4, -5, -6]\n\n\n\n "</script><div class='minibutton load' onclick='javascript: loadConsole(example15);'>load</div><div class='minibutton ok' onclick='javascript: var numbers, _ref;
[].splice.apply(numbers, [<span class="number">3</span>, <span class="number">4</span>].concat(ref = [-<span class="number">3</span>, -<span class="number">4</span>, -<span class="number">5</span>, -<span class="number">6</span>])), ref;
</code></pre><script>window.example15 = "numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\nnumbers[3..6] = [-3, -4, -5, -6]\n\n\n\n "</script><div class='minibutton load' onclick='javascript: loadConsole(example15);'>load</div><div class='minibutton ok' onclick='javascript: var numbers, ref;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;
[].splice.apply(numbers, [3, 4].concat(ref = [-3, -4, -5, -6])), ref;
;alert(numbers);'>run: numbers</div><br class='clear' /></div>
<p>
Note that JavaScript strings are immutable, and can't be spliced.
@@ -1226,22 +1226,22 @@ six = (one = 1) + (two = 2) + (three = 3);
globals = (name <span class="keyword">for</span> name <span class="keyword">of</span> <span class="built_in">window</span>)[<span class="number">0.</span>.<span class="number">.10</span>]</code></pre><pre><code><span class="keyword">var</span> globals, name;
globals = ((<span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">var</span> _results;
_results = [];
<span class="keyword">var</span> results;
results = [];
<span class="keyword">for</span> (name <span class="keyword">in</span> window) {
_results.push(name);
results.push(name);
}
<span class="keyword">return</span> _results;
<span class="keyword">return</span> results;
})()).slice(<span class="number">0</span>, <span class="number">10</span>);
</code></pre><script>window.example18 = "# The first ten global properties.\n\nglobals = (name for name of window)[0...10]"</script><div class='minibutton load' onclick='javascript: loadConsole(example18);'>load</div><div class='minibutton ok' onclick='javascript: var globals, name;
globals = ((function() {
var _results;
_results = [];
var results;
results = [];
for (name in window) {
_results.push(name);
results.push(name);
}
return _results;
return results;
})()).slice(0, 10);
;alert(globals);'>run: globals</div><br class='clear' /></div>
<p>
@@ -1439,13 +1439,13 @@ footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
the <b>TypeError</b> that would be raised otherwise.
</p>
<div class='code'><pre><code>zip = lottery.drawWinner?().address?.zipcode
</code></pre><pre><code><span class="keyword">var</span> zip, _ref;
</code></pre><pre><code><span class="keyword">var</span> ref, zip;
zip = <span class="keyword">typeof</span> lottery.drawWinner === <span class="string">"function"</span> ? (_ref = lottery.drawWinner().address) != <span class="literal">null</span> ? _ref.zipcode : <span class="keyword">void</span> <span class="number">0</span> : <span class="keyword">void</span> <span class="number">0</span>;
zip = <span class="keyword">typeof</span> lottery.drawWinner === <span class="string">"function"</span> ? (ref = lottery.drawWinner().address) != <span class="literal">null</span> ? ref.zipcode : <span class="keyword">void</span> <span class="number">0</span> : <span class="keyword">void</span> <span class="number">0</span>;
</code></pre><script>window.example22 = "zip = lottery.drawWinner?().address?.zipcode\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example22);'>load</div><br class='clear' /></div>
<p>
Soaking up nulls is similar to Ruby's
<a href="http://andand.rubyforge.org/">andand gem</a>, and to the
<a href="https://rubygems.org/gems/andand">andand gem</a>, and to the
<a href="http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator%28%3F.%29">safe navigation operator</a>
in Groovy.
</p>
@@ -1501,8 +1501,8 @@ tom.move()
</code></pre><pre><code><span class="keyword">var</span> Animal, Horse, Snake, sam, tom,
__hasProp = {}.hasOwnProperty,
__extends = <span class="function"><span class="keyword">function</span><span class="params">(child, parent)</span> {</span> <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> parent) { <span class="keyword">if</span> (__hasProp.call(parent, key)) child[key] = parent[key]; } <span class="function"><span class="keyword">function</span> <span class="title">ctor</span><span class="params">()</span> {</span> <span class="keyword">this</span>.constructor = child; } ctor.prototype = parent.prototype; child.prototype = <span class="keyword">new</span> ctor(); child.__super__ = parent.prototype; <span class="keyword">return</span> child; };
extend = <span class="function"><span class="keyword">function</span><span class="params">(child, parent)</span> {</span> <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> parent) { <span class="keyword">if</span> (hasProp.call(parent, key)) child[key] = parent[key]; } <span class="function"><span class="keyword">function</span> <span class="title">ctor</span><span class="params">()</span> {</span> <span class="keyword">this</span>.constructor = child; } ctor.prototype = parent.prototype; child.prototype = <span class="keyword">new</span> ctor(); child.__super__ = parent.prototype; <span class="keyword">return</span> child; },
hasProp = {}.hasOwnProperty;
Animal = (<span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="function"><span class="keyword">function</span> <span class="title">Animal</span><span class="params">(name)</span> {</span>
@@ -1517,8 +1517,8 @@ Animal = (<span class="function"><span class="keyword">function</span><span clas
})();
Snake = (<span class="function"><span class="keyword">function</span><span class="params">(_super)</span> {</span>
__extends(Snake, _super);
Snake = (<span class="function"><span class="keyword">function</span><span class="params">(superClass)</span> {</span>
extend(Snake, superClass);
<span class="function"><span class="keyword">function</span> <span class="title">Snake</span><span class="params">()</span> {</span>
<span class="keyword">return</span> Snake.__super__.constructor.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>);
@@ -1533,8 +1533,8 @@ Snake = (<span class="function"><span class="keyword">function</span><span class
})(Animal);
Horse = (<span class="function"><span class="keyword">function</span><span class="params">(_super)</span> {</span>
__extends(Horse, _super);
Horse = (<span class="function"><span class="keyword">function</span><span class="params">(superClass)</span> {</span>
extend(Horse, superClass);
<span class="function"><span class="keyword">function</span> <span class="title">Horse</span><span class="params">()</span> {</span>
<span class="keyword">return</span> Horse.__super__.constructor.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>);
@@ -1557,8 +1557,8 @@ sam.move();
tom.move();
</code></pre><script>window.example23 = "class Animal\n constructor: (@name) ->\n\n move: (meters) ->\n alert @name + \" moved #{meters}m.\"\n\nclass Snake extends Animal\n move: ->\n alert \"Slithering...\"\n super 5\n\nclass Horse extends Animal\n move: ->\n alert \"Galloping...\"\n super 45\n\nsam = new Snake \"Sammy the Python\"\ntom = new Horse \"Tommy the Palomino\"\n\nsam.move()\ntom.move()\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example23);'>load</div><div class='minibutton ok' onclick='javascript: var Animal, Horse, Snake, sam, tom,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
Animal = (function() {
function Animal(name) {
@@ -1573,8 +1573,8 @@ Animal = (function() {
})();
Snake = (function(_super) {
__extends(Snake, _super);
Snake = (function(superClass) {
extend(Snake, superClass);
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
@@ -1589,8 +1589,8 @@ Snake = (function(_super) {
})(Animal);
Horse = (function(_super) {
__extends(Horse, _super);
Horse = (function(superClass) {
extend(Horse, superClass);
function Horse() {
return Horse.__super__.constructor.apply(this, arguments);
@@ -1658,20 +1658,20 @@ theSwitch = <span class="number">0</span>
</code></pre><pre><code><span class="keyword">var</span> theBait, theSwitch, _ref;
</code></pre><pre><code><span class="keyword">var</span> ref, theBait, theSwitch;
theBait = <span class="number">1000</span>;
theSwitch = <span class="number">0</span>;
_ref = [theSwitch, theBait], theBait = _ref[<span class="number">0</span>], theSwitch = _ref[<span class="number">1</span>];
</code></pre><script>window.example25 = "theBait = 1000\ntheSwitch = 0\n\n[theBait, theSwitch] = [theSwitch, theBait]\n\n\n\n\n "</script><div class='minibutton load' onclick='javascript: loadConsole(example25);'>load</div><div class='minibutton ok' onclick='javascript: var theBait, theSwitch, _ref;
ref = [theSwitch, theBait], theBait = ref[<span class="number">0</span>], theSwitch = ref[<span class="number">1</span>];
</code></pre><script>window.example25 = "theBait = 1000\ntheSwitch = 0\n\n[theBait, theSwitch] = [theSwitch, theBait]\n\n\n\n\n "</script><div class='minibutton load' onclick='javascript: loadConsole(example25);'>load</div><div class='minibutton ok' onclick='javascript: var ref, theBait, theSwitch;
theBait = 1000;
theSwitch = 0;
_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
ref = [theSwitch, theBait], theBait = ref[0], theSwitch = ref[1];
;alert(theBait);'>run: theBait</div><br class='clear' /></div>
<p>
But it's also helpful for dealing with functions that return multiple
@@ -1686,20 +1686,20 @@ _ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
</code></pre><pre><code><span class="keyword">var</span> city, forecast, temp, weatherReport, _ref;
</code></pre><pre><code><span class="keyword">var</span> city, forecast, ref, temp, weatherReport;
weatherReport = <span class="function"><span class="keyword">function</span><span class="params">(location)</span> {</span>
<span class="keyword">return</span> [location, <span class="number">72</span>, <span class="string">"Mostly Sunny"</span>];
};
_ref = weatherReport(<span class="string">"Berkeley, CA"</span>), city = _ref[<span class="number">0</span>], temp = _ref[<span class="number">1</span>], forecast = _ref[<span class="number">2</span>];
</code></pre><script>window.example26 = "weatherReport = (location) ->\n # Make an Ajax request to fetch the weather...\n [location, 72, \"Mostly Sunny\"]\n\n[city, temp, forecast] = weatherReport \"Berkeley, CA\"\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example26);'>load</div><div class='minibutton ok' onclick='javascript: var city, forecast, temp, weatherReport, _ref;
ref = weatherReport(<span class="string">"Berkeley, CA"</span>), city = ref[<span class="number">0</span>], temp = ref[<span class="number">1</span>], forecast = ref[<span class="number">2</span>];
</code></pre><script>window.example26 = "weatherReport = (location) ->\n # Make an Ajax request to fetch the weather...\n [location, 72, \"Mostly Sunny\"]\n\n[city, temp, forecast] = weatherReport \"Berkeley, CA\"\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example26);'>load</div><div class='minibutton ok' onclick='javascript: var city, forecast, ref, temp, weatherReport;
weatherReport = function(location) {
return [location, 72, "Mostly Sunny"];
};
_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
ref = weatherReport("Berkeley, CA"), city = ref[0], temp = ref[1], forecast = ref[2];
;alert(forecast);'>run: forecast</div><br class='clear' /></div>
<p>
Destructuring assignment can be used with any depth of array and object nesting,
@@ -1719,7 +1719,7 @@ _ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast =
</code></pre><pre><code><span class="keyword">var</span> city, futurists, name, street, _ref, _ref1;
</code></pre><pre><code><span class="keyword">var</span> city, futurists, name, ref, ref1, street;
futurists = {
sculptor: <span class="string">"Umberto Boccioni"</span>,
@@ -1730,8 +1730,8 @@ futurists = {
}
};
_ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[<span class="number">0</span>], city = _ref1[<span class="number">1</span>]);
</code></pre><script>window.example27 = "futurists =\n sculptor: \"Umberto Boccioni\"\n painter: \"Vladimir Burliuk\"\n poet:\n name: \"F.T. Marinetti\"\n address: [\n \"Via Roma 42R\"\n \"Bellagio, Italy 22021\"\n ]\n\n{poet: {name, address: [street, city]}} = futurists\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example27);'>load</div><div class='minibutton ok' onclick='javascript: var city, futurists, name, street, _ref, _ref1;
ref = futurists.poet, name = ref.name, (ref1 = ref.address, street = ref1[<span class="number">0</span>], city = ref1[<span class="number">1</span>]);
</code></pre><script>window.example27 = "futurists =\n sculptor: \"Umberto Boccioni\"\n painter: \"Vladimir Burliuk\"\n poet:\n name: \"F.T. Marinetti\"\n address: [\n \"Via Roma 42R\"\n \"Bellagio, Italy 22021\"\n ]\n\n{poet: {name, address: [street, city]}} = futurists\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example27);'>load</div><div class='minibutton ok' onclick='javascript: var city, futurists, name, ref, ref1, street;
futurists = {
sculptor: "Umberto Boccioni",
@@ -1742,7 +1742,7 @@ futurists = {
}
};
_ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0], city = _ref1[1]);
ref = futurists.poet, name = ref.name, (ref1 = ref.address, street = ref1[0], city = ref1[1]);
;alert(name + "-" + street);'>run: name + "-" + street</div><br class='clear' /></div>
<p>
Destructuring assignment can even be combined with splats.
@@ -1756,18 +1756,18 @@ _ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0
</code></pre><pre><code><span class="keyword">var</span> close, contents, open, tag, _i, _ref,
__slice = [].slice;
</code></pre><pre><code><span class="keyword">var</span> close, contents, i, open, ref, tag,
slice = [].slice;
tag = <span class="string">"&lt;impossible&gt;"</span>;
_ref = tag.split(<span class="string">""</span>), open = _ref[<span class="number">0</span>], contents = <span class="number">3</span> &lt;= _ref.length ? __slice.call(_ref, <span class="number">1</span>, _i = _ref.length - <span class="number">1</span>) : (_i = <span class="number">1</span>, []), close = _ref[_i++];
</code></pre><script>window.example28 = "tag = \"<impossible>\"\n\n[open, contents..., close] = tag.split(\"\")\n\n\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example28);'>load</div><div class='minibutton ok' onclick='javascript: var close, contents, open, tag, _i, _ref,
__slice = [].slice;
ref = tag.split(<span class="string">""</span>), open = ref[<span class="number">0</span>], contents = <span class="number">3</span> &lt;= ref.length ? slice.call(ref, <span class="number">1</span>, i = ref.length - <span class="number">1</span>) : (i = <span class="number">1</span>, []), close = ref[i++];
</code></pre><script>window.example28 = "tag = \"<impossible>\"\n\n[open, contents..., close] = tag.split(\"\")\n\n\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example28);'>load</div><div class='minibutton ok' onclick='javascript: var close, contents, i, open, ref, tag,
slice = [].slice;
tag = "<impossible>";
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
ref = tag.split(""), open = ref[0], contents = 3 <= ref.length ? slice.call(ref, 1, i = ref.length - 1) : (i = 1, []), close = ref[i++];
;alert(contents.join(""));'>run: contents.join("")</div><br class='clear' /></div>
<p>
Expansion can be used to retrieve elements from the end of an array without having to assign the rest of its values. It works in function parameter lists as well.
@@ -1779,16 +1779,16 @@ _ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call
</code></pre><pre><code><span class="keyword">var</span> first, last, text, _ref;
</code></pre><pre><code><span class="keyword">var</span> first, last, ref, text;
text = <span class="string">"Every literary critic believes he will outwit history and have the last word"</span>;
_ref = text.split(<span class="string">" "</span>), first = _ref[<span class="number">0</span>], last = _ref[_ref.length - <span class="number">1</span>];
</code></pre><script>window.example29 = "text = \"Every literary critic believes he will\n outwit history and have the last word\"\n\n[first, ..., last] = text.split \" \"\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example29);'>load</div><div class='minibutton ok' onclick='javascript: var first, last, text, _ref;
ref = text.split(<span class="string">" "</span>), first = ref[<span class="number">0</span>], last = ref[ref.length - <span class="number">1</span>];
</code></pre><script>window.example29 = "text = \"Every literary critic believes he will\n outwit history and have the last word\"\n\n[first, ..., last] = text.split \" \"\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example29);'>load</div><div class='minibutton ok' onclick='javascript: var first, last, ref, text;
text = "Every literary critic believes he will outwit history and have the last word";
_ref = text.split(" "), first = _ref[0], last = _ref[_ref.length - 1];
ref = text.split(" "), first = ref[0], last = ref[ref.length - 1];
;alert(first + " " + last);'>run: first + " " + last</div><br class='clear' /></div>
<p>
Destructuring assignment is also useful when combined with class constructors
@@ -1832,7 +1832,7 @@ tim = new Person({
<p>
<span id="fat-arrow" class="bookmark"></span>
<b class="header">Function binding</b>
<b class="header">Bound Functions, Generator Functions</b>
In JavaScript, the <tt>this</tt> keyword is dynamically scoped to mean the
object that the current function is attached to. If you pass a function as
a callback or attach it to a different object, the original value of <tt>this</tt>
@@ -1875,6 +1875,44 @@ Account = <span class="function"><span class="keyword">function</span><span clas
be automatically bound to each instance of the class when the instance is
constructed.
</p>
<p>
CoffeeScript functions also support
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*">ES6 generator functions</a>
through the <tt>yield</tt> keyword. There's no <tt>function*(){}</tt>
nonsense &mdash; a generator in CoffeeScript is simply a function that yields.
</p>
<div class='code'><pre><code><span class="function"><span class="title">perfectSquares</span> = -&gt;</span>
num = <span class="number">0</span>
<span class="keyword">loop</span>
num += <span class="number">1</span>
yield num * num
<span class="keyword">return</span>
<span class="built_in">window</span>.ps <span class="keyword">or</span>= perfectSquares()</code></pre><pre><code><span class="keyword">var</span> perfectSquares;
perfectSquares = <span class="function"><span class="keyword">function</span>*<span class="params">()</span> {</span>
<span class="keyword">var</span> num;
num = <span class="number">0</span>;
<span class="keyword">while</span> (<span class="literal">true</span>) {
num += <span class="number">1</span>;
(<span class="keyword">yield</span> num * num);
}
};
window.ps || (window.ps = perfectSquares());
</code></pre><script>window.example32 = "perfectSquares = ->\n num = 0\n loop\n num += 1\n yield num * num\n return\n\nwindow.ps or= perfectSquares()"</script><div class='minibutton load' onclick='javascript: loadConsole(example32);'>load</div><div class='minibutton ok' onclick='javascript: var perfectSquares;
perfectSquares = function*() {
var num;
num = 0;
while (true) {
num += 1;
(yield num * num);
}
};
window.ps || (window.ps = perfectSquares());
;alert(ps.next().value);'>run: ps.next().value</div><br class='clear' /></div>
<p>
<span id="embedded" class="bookmark"></span>
@@ -1894,7 +1932,7 @@ Account = <span class="function"><span class="keyword">function</span><span clas
hi = <span class="function"><span class="keyword">function</span><span class="params">()</span> {</span>
<span class="keyword">return</span> [document.title, <span class="string">"Hello JavaScript"</span>].join(<span class="string">": "</span>);
};
</code></pre><script>window.example32 = "hi = `function() {\n return [document.title, \"Hello JavaScript\"].join(\": \");\n}`\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example32);'>load</div><div class='minibutton ok' onclick='javascript: var hi;
</code></pre><script>window.example33 = "hi = `function() {\n return [document.title, \"Hello JavaScript\"].join(\": \");\n}`\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example33);'>load</div><div class='minibutton ok' onclick='javascript: var hi;
hi = function() {
return [document.title, "Hello JavaScript"].join(": ");
@@ -1948,7 +1986,7 @@ hi = function() {
<span class="keyword">default</span>:
go(work);
}
</code></pre><script>window.example33 = "switch day\n when \"Mon\" then go work\n when \"Tue\" then go relax\n when \"Thu\" then go iceFishing\n when \"Fri\", \"Sat\"\n if day is bingoDay\n go bingo\n go dancing\n when \"Sun\" then go church\n else go work"</script><div class='minibutton load' onclick='javascript: loadConsole(example33);'>load</div><br class='clear' /></div>
</code></pre><script>window.example34 = "switch day\n when \"Mon\" then go work\n when \"Tue\" then go relax\n when \"Thu\" then go iceFishing\n when \"Fri\", \"Sat\"\n if day is bingoDay\n go bingo\n go dancing\n when \"Sun\" then go church\n else go work"</script><div class='minibutton load' onclick='javascript: loadConsole(example34);'>load</div><br class='clear' /></div>
<p>
Switch statements can also be used without a control expression, turning them in to a cleaner alternative to if/else chains.
@@ -1979,7 +2017,7 @@ grade = (<span class="function"><span class="keyword">function</span><span class
<span class="keyword">return</span> <span class="string">'A'</span>;
}
})();
</code></pre><script>window.example34 = "score = 76\ngrade = switch\n when score < 60 then 'F'\n when score < 70 then 'D'\n when score < 80 then 'C'\n when score < 90 then 'B'\n else 'A'\n# grade == 'C'\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example34);'>load</div><br class='clear' /></div>
</code></pre><script>window.example35 = "score = 76\ngrade = switch\n when score < 60 then 'F'\n when score < 70 then 'D'\n when score < 80 then 'C'\n when score < 90 then 'B'\n else 'A'\n# grade == 'C'\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example35);'>load</div><br class='clear' /></div>
<p>
<span id="try" class="bookmark"></span>
@@ -2006,7 +2044,7 @@ grade = (<span class="function"><span class="keyword">function</span><span class
} <span class="keyword">finally</span> {
cleanUp();
}
</code></pre><script>window.example35 = "try\n allHellBreaksLoose()\n catsAndDogsLivingTogether()\ncatch error\n print error\nfinally\n cleanUp()\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example35);'>load</div><br class='clear' /></div>
</code></pre><script>window.example36 = "try\n allHellBreaksLoose()\n catsAndDogsLivingTogether()\ncatch error\n print error\nfinally\n cleanUp()\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example36);'>load</div><br class='clear' /></div>
<p>
<span id="comparisons" class="bookmark"></span>
@@ -2026,7 +2064,7 @@ healthy = <span class="number">200</span> &gt; cholesterol &gt; <span class="num
cholesterol = <span class="number">127</span>;
healthy = (<span class="number">200</span> &gt; cholesterol &amp;&amp; cholesterol &gt; <span class="number">60</span>);
</code></pre><script>window.example36 = "cholesterol = 127\n\nhealthy = 200 > cholesterol > 60\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example36);'>load</div><div class='minibutton ok' onclick='javascript: var cholesterol, healthy;
</code></pre><script>window.example37 = "cholesterol = 127\n\nhealthy = 200 > cholesterol > 60\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><div class='minibutton ok' onclick='javascript: var cholesterol, healthy;
cholesterol = 127;
@@ -2055,14 +2093,14 @@ author = <span class="string">"Wittgenstein"</span>;
quote = <span class="string">"A picture is a fact. -- "</span> + author;
sentence = <span class="string">""</span> + (<span class="number">22</span> / <span class="number">7</span>) + <span class="string">" is a decent approximation of π"</span>;
</code></pre><script>window.example37 = "author = \"Wittgenstein\"\nquote = \"A picture is a fact. -- #{ author }\"\n\nsentence = \"#{ 22 / 7 } is a decent approximation of π\"\n\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example37);'>load</div><div class='minibutton ok' onclick='javascript: var author, quote, sentence;
sentence = (<span class="number">22</span> / <span class="number">7</span>) + <span class="string">" is a decent approximation of π"</span>;
</code></pre><script>window.example38 = "author = \"Wittgenstein\"\nquote = \"A picture is a fact. -- #{ author }\"\n\nsentence = \"#{ 22 / 7 } is a decent approximation of π\"\n\n\n\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example38);'>load</div><div class='minibutton ok' onclick='javascript: var author, quote, sentence;
author = "Wittgenstein";
quote = "A picture is a fact. -- " + author;
sentence = "" + (22 / 7) + " is a decent approximation of π";
sentence = (22 / 7) + " is a decent approximation of π";
;alert(sentence);'>run: sentence</div><br class='clear' /></div>
<p>
Multiline strings are allowed in CoffeeScript. Lines are joined by a single space unless they end with a backslash. Indentation is ignored.
@@ -2076,7 +2114,7 @@ sentence = "" + (22 / 7) + " is a decent approximation of π";
</code></pre><pre><code><span class="keyword">var</span> mobyDick;
mobyDick = <span class="string">"Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..."</span>;
</code></pre><script>window.example38 = "mobyDick = \"Call me Ishmael. Some years ago --\n never mind how long precisely -- having little\n or no money in my purse, and nothing particular\n to interest me on shore, I thought I would sail\n about a little and see the watery part of the\n world...\"\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example38);'>load</div><div class='minibutton ok' onclick='javascript: var mobyDick;
</code></pre><script>window.example39 = "mobyDick = \"Call me Ishmael. Some years ago --\n never mind how long precisely -- having little\n or no money in my purse, and nothing particular\n to interest me on shore, I thought I would sail\n about a little and see the watery part of the\n world...\"\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example39);'>load</div><div class='minibutton ok' onclick='javascript: var mobyDick;
mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";
;alert(mobyDick);'>run: mobyDick</div><br class='clear' /></div>
@@ -2095,7 +2133,7 @@ mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely --
</code></pre><pre><code><span class="keyword">var</span> html;
html = <span class="string">"&lt;strong&gt;\n cup of coffeescript\n&lt;/strong&gt;"</span>;
</code></pre><script>window.example39 = "html = \"\"\"\n <strong>\n cup of coffeescript\n </strong>\n \"\"\"\n \n"</script><div class='minibutton load' onclick='javascript: loadConsole(example39);'>load</div><div class='minibutton ok' onclick='javascript: var html;
</code></pre><script>window.example40 = "html = \"\"\"\n <strong>\n cup of coffeescript\n </strong>\n \"\"\"\n \n"</script><div class='minibutton load' onclick='javascript: loadConsole(example40);'>load</div><div class='minibutton ok' onclick='javascript: var html;
html = "<strong>\n cup of coffeescript\n</strong>";
;alert(html);'>run: html</div><br class='clear' /></div>
@@ -2120,7 +2158,7 @@ SkinnyMochaHalfCaffScript Compiler v1.0
Released under the MIT License
*/</span>
</code></pre><script>window.example40 = "###\nSkinnyMochaHalfCaffScript Compiler v1.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example40);'>load</div><br class='clear' /></div>
</code></pre><script>window.example41 = "###\nSkinnyMochaHalfCaffScript Compiler v1.0\nReleased under the MIT License\n###\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example41);'>load</div><br class='clear' /></div>
<p>
<span id="regexes" class="bookmark"></span>
@@ -2145,7 +2183,7 @@ Released under the MIT License
</code></pre><pre><code><span class="keyword">var</span> OPERATOR;
OPERATOR = <span class="regexp">/^(?:[-=]&gt;|[-+*\/%&lt;&gt;&amp;|^!?=]=|&gt;&gt;&gt;=?|([-+:])\1|([&amp;|&lt;&gt;])\2=?|\?\.|\.{2,3})/</span>;
</code></pre><script>window.example41 = "OPERATOR = /// ^ (\n ?: [-=]> # function\n | [-+*/%<>&|^!?=]= # compound assign / compare\n | >>>=? # zero-fill right shift\n | ([-+:])\\1 # doubles\n | ([&|<>])\\2=? # logic / shift\n | \\?\\. # soak access\n | \\.{2,3} # range or splat\n) ///\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example41);'>load</div><br class='clear' /></div>
</code></pre><script>window.example42 = "OPERATOR = /// ^ (\n ?: [-=]> # function\n | [-+*/%<>&|^!?=]= # compound assign / compare\n | >>>=? # zero-fill right shift\n | ([-+:])\\1 # doubles\n | ([&|<>])\\2=? # logic / shift\n | \\?\\. # soak access\n | \\.{2,3} # range or splat\n) ///\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example42);'>load</div><br class='clear' /></div>
<h2>
@@ -2190,9 +2228,9 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
<span class="built_in">require</span>(<span class="string">'jison'</span>);
code = <span class="built_in">require</span>(<span class="string">'./lib/grammar'</span>).parser.generate();
dir = options.output || <span class="string">'lib'</span>;
<span class="keyword">return</span> fs.writeFile(<span class="string">""</span> + dir + <span class="string">"/parser.js"</span>, code);
<span class="keyword">return</span> fs.writeFile(dir + <span class="string">"/parser.js"</span>, code);
});
</code></pre><script>window.example42 = "fs = require 'fs'\n\noption '-o', '--output [DIR]', 'directory for compiled code'\n\ntask 'build:parser', 'rebuild the Jison parser', (options) ->\n require 'jison'\n code = require('./lib/grammar').parser.generate()\n dir = options.output or 'lib'\n fs.writeFile \"#{dir}/parser.js\", code"</script><div class='minibutton load' onclick='javascript: loadConsole(example42);'>load</div><br class='clear' /></div>
</code></pre><script>window.example43 = "fs = require 'fs'\n\noption '-o', '--output [DIR]', 'directory for compiled code'\n\ntask 'build:parser', 'rebuild the Jison parser', (options) ->\n require 'jison'\n code = require('./lib/grammar').parser.generate()\n dir = options.output or 'lib'\n fs.writeFile \"#{dir}/parser.js\", code"</script><div class='minibutton load' onclick='javascript: loadConsole(example43);'>load</div><br class='clear' /></div>
<p>
If you need to invoke one task before another &mdash; for example, running
<tt>build</tt> before <tt>test</tt>, you can use the <tt>invoke</tt> function:
@@ -2302,14 +2340,18 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
</li>
<li>
<a href="http://www.packtpub.com/coffeescript-application-development/book">CoffeeScript Application Development</a>
is a new book from Packt Publishing that introduces CoffeeScript while
from Packt, introduces CoffeeScript while
walking through the process of building a demonstration web application.
</li>
<li>
<a href="http://www.manning.com/lee/">CoffeeScript in Action</a>
is a new book from Manning Publications that covers CoffeeScript syntax, composition techniques
from Manning Publications, covers CoffeeScript syntax, composition techniques
and application development.
</li>
<li>
<a href="http://www.dpunkt.de/buecher/4021/coffeescript.html">CoffeeScript: Die Alternative zu JavaScript</a>
from dpunkt.verlag, is the first CoffeeScript book in Deutsch.
</li>
</ul>
<h2>
@@ -2372,8 +2414,8 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
the Bolo tank game for modern browsers.
</li>
<li>
<b>josh</b>'s <a href="http://josh.github.com/nack/">nack</a>, a Node.js-powered
<a href="http://rack.rubyforge.org/">Rack</a> server.
<b>github</b>'s <a href="https://atom.io/">Atom</a>,
a hackable text editor built on web technologies.
</li>
</ul>
@@ -2449,6 +2491,61 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
Change Log
</h2>
<p>
<div class="anchor" id="1.9.1"></div>
<b class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/1.9.0...1.9.1">1.9.1</a>
<span class="timestamp"> &mdash; <time datetime="2015-02-18">February 18, 2015</time></span>
</b>
<ul>
<li>
Interpolation now works in object literal keys (again). You can use this to
dynamically name properties.
</li>
<li>
Internal compiler names no longer start with underscores. This makes
the generated JavaScript a bit prettier, and also fixes an issue with
the completely broken and ungodly way that AngularJS "parses" function
arguments.
</li>
<li>
Fixed a few <tt>yield</tt>-related bugs.
</li>
<li>
Minor bug fixes and various improvements to compiler error messages.
</li>
</ul>
</p>
<p>
<div class="anchor" id="1.9.0"></div>
<b class="header">
<a href="https://github.com/jashkenas/coffeescript/compare/1.8.0...1.9.0">1.9.0</a>
<span class="timestamp"> &mdash; <time datetime="2015-01-29">January 29, 2015</time></span>
</b>
<ul>
<li>
CoffeeScript now supports ES6 generators. A generator is simply a function
that <tt>yield</tt>s.
</li>
<li>
More robust parsing and improved error messages for strings and regexes —
especially with respect to interpolation.
</li>
<li>
Changed strategy for the generation of internal compiler variable names.
Note that this means that <tt>@example</tt> function parameters are no longer
available as naked <tt>example</tt> variables within the function body.
</li>
<li>
Fixed REPL compatibility with latest versions of Node and Io.js.
</li>
<li>
Various minor bug fixes.
</li>
</ul>
</p>
<p>
<div class="anchor" id="1.8.0"></div>
<b class="header">
@@ -2532,7 +2629,7 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
</code></pre><pre><code>$(<span class="string">'body'</span>).click(<span class="function"><span class="keyword">function</span><span class="params">(e)</span> {</span>
<span class="keyword">return</span> $(<span class="string">'.box'</span>).fadeIn(<span class="string">'fast'</span>).addClass(<span class="string">'.active'</span>);
}).css(<span class="string">'background'</span>, <span class="string">'white'</span>);
</code></pre><script>window.example43 = "$ 'body'\n.click (e) ->\n $ '.box'\n .fadeIn 'fast'\n .addClass '.active'\n.css 'background', 'white'\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example43);'>load</div><br class='clear' /></div>
</code></pre><script>window.example44 = "$ 'body'\n.click (e) ->\n $ '.box'\n .fadeIn 'fast'\n .addClass '.active'\n.css 'background', 'white'\n\n\n"</script><div class='minibutton load' onclick='javascript: loadConsole(example44);'>load</div><br class='clear' /></div>
<ul>
<li>
Added <tt>**</tt>, <tt>//</tt> and <tt>%%</tt> operators and <tt>...</tt> expansion in parameter lists and destructuring expressions.
@@ -2771,7 +2868,7 @@ task(<span class="string">'build:parser'</span>, <span class="string">'rebuild t
effectively creating a shallow copy of the list.
</li>
<li>
Additional tweaks and improvments to <tt>coffee --watch</tt> under
Additional tweaks and improvements to <tt>coffee --watch</tt> under
Node's "new" file watching API. Watch will now beep by default
if you introduce a syntax error into a watched script. We also now
ignore hidden directories by default when watching recursively.

View File

@@ -1,7 +1,7 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var CoffeeScript, compile, runScripts,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
CoffeeScript = require('./coffee-script');
@@ -34,14 +34,14 @@
if ((typeof btoa !== "undefined" && btoa !== null) && (typeof JSON !== "undefined" && JSON !== null) && (typeof unescape !== "undefined" && unescape !== null) && (typeof encodeURIComponent !== "undefined" && encodeURIComponent !== null)) {
compile = function(code, options) {
var js, v3SourceMap, _ref;
var js, ref, v3SourceMap;
if (options == null) {
options = {};
}
options.sourceMap = true;
options.inline = true;
_ref = CoffeeScript.compile(code, options), js = _ref.js, v3SourceMap = _ref.v3SourceMap;
return "" + js + "\n//# sourceMappingURL=data:application/json;base64," + (btoa(unescape(encodeURIComponent(v3SourceMap)))) + "\n//# sourceURL=coffeescript";
ref = CoffeeScript.compile(code, options), js = ref.js, v3SourceMap = ref.v3SourceMap;
return js + "\n//# sourceMappingURL=data:application/json;base64," + (btoa(unescape(encodeURIComponent(v3SourceMap)))) + "\n//# sourceURL=coffeescript";
};
}
@@ -60,9 +60,9 @@
xhr.overrideMimeType('text/plain');
}
xhr.onreadystatechange = function() {
var param, _ref;
var param, ref;
if (xhr.readyState === 4) {
if ((_ref = xhr.status) === 0 || _ref === 200) {
if ((ref = xhr.status) === 0 || ref === 200) {
param = [xhr.responseText, options];
if (!hold) {
CoffeeScript.run.apply(CoffeeScript, param);
@@ -79,19 +79,19 @@
};
runScripts = function() {
var coffees, coffeetypes, execute, i, index, s, script, scripts, _fn, _i, _len;
var coffees, coffeetypes, execute, fn, i, index, j, len, s, script, scripts;
scripts = window.document.getElementsByTagName('script');
coffeetypes = ['text/coffeescript', 'text/literate-coffeescript'];
coffees = (function() {
var _i, _len, _ref, _results;
_results = [];
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
s = scripts[_i];
if (_ref = s.type, __indexOf.call(coffeetypes, _ref) >= 0) {
_results.push(s);
var j, len, ref, results;
results = [];
for (j = 0, len = scripts.length; j < len; j++) {
s = scripts[j];
if (ref = s.type, indexOf.call(coffeetypes, ref) >= 0) {
results.push(s);
}
}
return _results;
return results;
})();
index = 0;
execute = function() {
@@ -103,7 +103,7 @@
return execute();
}
};
_fn = function(script, i) {
fn = function(script, i) {
var options;
options = {
literate: script.type === coffeetypes[1]
@@ -118,9 +118,9 @@
return coffees[i] = [script.innerHTML, options];
}
};
for (i = _i = 0, _len = coffees.length; _i < _len; i = ++_i) {
for (i = j = 0, len = coffees.length; j < len; i = ++j) {
script = coffees[i];
_fn(script, i);
fn(script, i);
}
return execute();
};

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var CoffeeScript, cakefileDirectory, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
@@ -24,9 +24,9 @@
helpers.extend(global, {
task: function(name, description, action) {
var _ref;
var ref;
if (!action) {
_ref = [description, action], action = _ref[0], description = _ref[1];
ref = [description, action], action = ref[0], description = ref[1];
}
return tasks[name] = {
name: name,
@@ -46,7 +46,7 @@
});
exports.run = function() {
var arg, args, e, _i, _len, _ref, _results;
var arg, args, e, i, len, ref, results;
global.__originalDirname = fs.realpathSync('.');
process.chdir(cakefileDirectory(__originalDirname));
args = process.argv.slice(2);
@@ -63,20 +63,20 @@
e = _error;
return fatalError("" + e);
}
_ref = options["arguments"];
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
arg = _ref[_i];
_results.push(invoke(arg));
ref = options["arguments"];
results = [];
for (i = 0, len = ref.length; i < len; i++) {
arg = ref[i];
results.push(invoke(arg));
}
return _results;
return results;
};
printTasks = function() {
var cakefilePath, desc, name, relative, spaces, task;
relative = path.relative || path.resolve;
cakefilePath = path.join(relative(__originalDirname, process.cwd()), 'Cakefile');
console.log("" + cakefilePath + " defines the following tasks:\n");
console.log(cakefilePath + " defines the following tasks:\n");
for (name in tasks) {
task = tasks[name];
spaces = 20 - name.length;

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var Lexer, SourceMap, compile, ext, formatSourcePosition, fs, getSourceMap, helpers, lexer, parser, path, sourceMaps, vm, withPrettyErrors, _base, _i, _len, _ref,
__hasProp = {}.hasOwnProperty,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
var Lexer, SourceMap, base, compile, ext, formatSourcePosition, fs, getSourceMap, helpers, i, len, lexer, parser, path, ref, sourceMaps, vm, withPrettyErrors,
hasProp = {}.hasOwnProperty,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
fs = require('fs');
@@ -18,7 +18,7 @@
SourceMap = require('./sourcemap');
exports.VERSION = '1.8.0';
exports.VERSION = '1.9.1';
exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'];
@@ -40,13 +40,25 @@
};
exports.compile = compile = withPrettyErrors(function(code, options) {
var answer, currentColumn, currentLine, extend, fragment, fragments, header, js, map, merge, newLines, _i, _len;
var answer, currentColumn, currentLine, extend, fragment, fragments, header, i, js, len, map, merge, newLines, token, tokens;
merge = helpers.merge, extend = helpers.extend;
options = extend({}, options);
if (options.sourceMap) {
map = new SourceMap;
}
fragments = parser.parse(lexer.tokenize(code, options)).compileToFragments(options);
tokens = lexer.tokenize(code, options);
options.referencedVars = (function() {
var i, len, results;
results = [];
for (i = 0, len = tokens.length; i < len; i++) {
token = tokens[i];
if (token.variable) {
results.push(token[1]);
}
}
return results;
})();
fragments = parser.parse(tokens).compileToFragments(options);
currentLine = 0;
if (options.header) {
currentLine += 1;
@@ -56,8 +68,8 @@
}
currentColumn = 0;
js = "";
for (_i = 0, _len = fragments.length; _i < _len; _i++) {
fragment = fragments[_i];
for (i = 0, len = fragments.length; i < len; i++) {
fragment = fragments[i];
if (options.sourceMap) {
if (fragment.locationData) {
map.add([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], {
@@ -103,7 +115,7 @@
});
exports.run = function(code, options) {
var answer, dir, mainModule, _ref;
var answer, dir, mainModule, ref;
if (options == null) {
options = {};
}
@@ -114,30 +126,33 @@
mainModule.paths = require('module')._nodeModulePaths(dir);
if (!helpers.isCoffee(mainModule.filename) || require.extensions) {
answer = compile(code, options);
code = (_ref = answer.js) != null ? _ref : answer;
code = (ref = answer.js) != null ? ref : answer;
}
return mainModule._compile(code, mainModule.filename);
};
exports["eval"] = function(code, options) {
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref, _ref1, _require;
var Module, _module, _require, createContext, i, isContext, js, k, len, o, r, ref, ref1, ref2, ref3, sandbox, v;
if (options == null) {
options = {};
}
if (!(code = code.trim())) {
return;
}
Script = vm.Script;
if (Script) {
createContext = (ref = vm.Script.createContext) != null ? ref : vm.createContext;
isContext = (ref1 = vm.isContext) != null ? ref1 : function(ctx) {
return options.sandbox instanceof createContext().constructor;
};
if (createContext) {
if (options.sandbox != null) {
if (options.sandbox instanceof Script.createContext().constructor) {
if (isContext(options.sandbox)) {
sandbox = options.sandbox;
} else {
sandbox = Script.createContext();
_ref = options.sandbox;
for (k in _ref) {
if (!__hasProp.call(_ref, k)) continue;
v = _ref[k];
sandbox = createContext();
ref2 = options.sandbox;
for (k in ref2) {
if (!hasProp.call(ref2, k)) continue;
v = ref2[k];
sandbox[k] = v;
}
}
@@ -154,9 +169,9 @@
return Module._load(path, _module, true);
};
_module.filename = sandbox.__filename;
_ref1 = Object.getOwnPropertyNames(require);
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
r = _ref1[_i];
ref3 = Object.getOwnPropertyNames(require);
for (i = 0, len = ref3.length; i < len; i++) {
r = ref3[i];
if (r !== 'paths') {
_require[r] = require[r];
}
@@ -169,7 +184,7 @@
}
o = {};
for (k in options) {
if (!__hasProp.call(options, k)) continue;
if (!hasProp.call(options, k)) continue;
v = options[k];
o[k] = v;
}
@@ -187,11 +202,11 @@
};
if (require.extensions) {
_ref = this.FILE_EXTENSIONS;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
ext = _ref[_i];
if ((_base = require.extensions)[ext] == null) {
_base[ext] = function() {
ref = this.FILE_EXTENSIONS;
for (i = 0, len = ref.length; i < len; i++) {
ext = ref[i];
if ((base = require.extensions)[ext] == null) {
base[ext] = function() {
throw new Error("Use CoffeeScript.register() or require the coffee-script/register module to require " + ext + " files.");
};
}
@@ -223,10 +238,10 @@
parser.lexer = {
lex: function() {
var tag, token;
token = this.tokens[this.pos++];
token = parser.tokens[this.pos++];
if (token) {
tag = token[0], this.yytext = token[1], this.yylloc = token[2];
this.errorToken = token.origin || token;
parser.errorToken = token.origin || token;
this.yylineno = this.yylloc.first_line;
} else {
tag = '';
@@ -234,7 +249,7 @@
return tag;
},
setInput: function(tokens) {
this.tokens = tokens;
parser.tokens = tokens;
return this.pos = 0;
},
upcomingInput: function() {
@@ -244,12 +259,23 @@
parser.yy = require('./nodes');
parser.yy.parseError = function(message, _arg) {
var errorLoc, errorTag, errorText, errorToken, token, tokens, _ref1;
token = _arg.token;
_ref1 = parser.lexer, errorToken = _ref1.errorToken, tokens = _ref1.tokens;
parser.yy.parseError = function(message, arg) {
var errorLoc, errorTag, errorText, errorToken, token, tokens;
token = arg.token;
errorToken = parser.errorToken, tokens = parser.tokens;
errorTag = errorToken[0], errorText = errorToken[1], errorLoc = errorToken[2];
errorText = errorToken === tokens[tokens.length - 1] ? 'end of input' : errorTag === 'INDENT' || errorTag === 'OUTDENT' ? 'indentation' : helpers.nameWhitespaceCharacter(errorText);
errorText = (function() {
switch (false) {
case errorToken !== tokens[tokens.length - 1]:
return 'end of input';
case errorTag !== 'INDENT' && errorTag !== 'OUTDENT':
return 'indentation';
case errorTag !== 'IDENTIFIER' && errorTag !== 'NUMBER' && errorTag !== 'STRING' && errorTag !== 'STRING_START' && errorTag !== 'REGEX' && errorTag !== 'REGEX_START':
return errorTag.replace(/_START$/, '').toLowerCase();
default:
return helpers.nameWhitespaceCharacter(errorText);
}
})();
return helpers.throwSyntaxError("unexpected " + errorText, errorLoc);
};
@@ -263,7 +289,7 @@
if (frame.isEval()) {
fileName = frame.getScriptNameOrSourceURL();
if (!fileName) {
fileLocation = "" + (frame.getEvalOrigin()) + ", ";
fileLocation = (frame.getEvalOrigin()) + ", ";
}
} else {
fileName = frame.getFileName();
@@ -272,7 +298,7 @@
line = frame.getLineNumber();
column = frame.getColumnNumber();
source = getSourceMapping(fileName, line, column);
fileLocation = source ? "" + fileName + ":" + source[0] + ":" + source[1] : "" + fileName + ":" + line + ":" + column;
fileLocation = source ? fileName + ":" + source[0] + ":" + source[1] : fileName + ":" + line + ":" + column;
}
functionName = frame.getFunctionName();
isConstructor = frame.isConstructor();
@@ -283,19 +309,19 @@
if (functionName) {
tp = as = '';
if (typeName && functionName.indexOf(typeName)) {
tp = "" + typeName + ".";
tp = typeName + ".";
}
if (methodName && functionName.indexOf("." + methodName) !== functionName.length - methodName.length - 1) {
as = " [as " + methodName + "]";
}
return "" + tp + functionName + as + " (" + fileLocation + ")";
} else {
return "" + typeName + "." + (methodName || '<anonymous>') + " (" + fileLocation + ")";
return typeName + "." + (methodName || '<anonymous>') + " (" + fileLocation + ")";
}
} else if (isConstructor) {
return "new " + (functionName || '<anonymous>') + " (" + fileLocation + ")";
} else if (functionName) {
return "" + functionName + " (" + fileLocation + ")";
return functionName + " (" + fileLocation + ")";
} else {
return fileLocation;
}
@@ -304,11 +330,11 @@
sourceMaps = {};
getSourceMap = function(filename) {
var answer, _ref1;
var answer, ref1;
if (sourceMaps[filename]) {
return sourceMaps[filename];
}
if (_ref1 = path != null ? path.extname(filename) : void 0, __indexOf.call(exports.FILE_EXTENSIONS, _ref1) < 0) {
if (ref1 = path != null ? path.extname(filename) : void 0, indexOf.call(exports.FILE_EXTENSIONS, ref1) < 0) {
return;
}
answer = exports._compileFile(filename, true);
@@ -330,18 +356,18 @@
}
};
frames = (function() {
var _j, _len1, _results;
_results = [];
for (_j = 0, _len1 = stack.length; _j < _len1; _j++) {
frame = stack[_j];
var j, len1, results;
results = [];
for (j = 0, len1 = stack.length; j < len1; j++) {
frame = stack[j];
if (frame.getFunction() === exports.run) {
break;
}
_results.push(" at " + (formatSourcePosition(frame, getSourceMapping)));
results.push(" at " + (formatSourcePosition(frame, getSourceMapping)));
}
return _results;
return results;
})();
return "" + (err.toString()) + "\n" + (frames.join('\n')) + "\n";
return (err.toString()) + "\n" + (frames.join('\n')) + "\n";
};
}).call(this);

View File

@@ -1,7 +1,7 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs, _ref,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, findDirectoryIndex, forkNode, fs, helpers, hidden, joinTimeout, jsToSources, mkdirp, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, ref, removeSource, removeSourceDir, silentUnlink, sourceCode, sources, spawn, timeLog, usage, useWinPathSep, version, wait, watch, watchDir, watchedDirs, writeJs,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
fs = require('fs');
@@ -13,9 +13,7 @@
CoffeeScript = require('./coffee-script');
mkdirp = require('mkdirp');
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
ref = require('child_process'), spawn = ref.spawn, exec = ref.exec;
EventEmitter = require('events').EventEmitter;
@@ -51,8 +49,10 @@
optionParser = null;
jsToSources = {};
exports.run = function() {
var literals, replCliOpts, source, _i, _len, _ref1, _results;
var i, len, literals, ref1, replCliOpts, results, source;
parseOptions();
replCliOpts = {
useGlobal: true
@@ -88,19 +88,19 @@
opts.join = path.resolve(opts.join);
console.error('\nThe --join option is deprecated and will be removed in a future version.\n\nIf for some reason it\'s necessary to share local variables between files,\nreplace...\n\n $ coffee --compile --join bundle.js -- a.coffee b.coffee c.coffee\n\nwith...\n\n $ cat a.coffee b.coffee c.coffee | coffee --compile --stdio > bundle.js\n');
}
_ref1 = opts["arguments"];
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
source = _ref1[_i];
ref1 = opts["arguments"];
results = [];
for (i = 0, len = ref1.length; i < len; i++) {
source = ref1[i];
source = path.resolve(source);
_results.push(compilePath(source, true, source));
results.push(compilePath(source, true, source));
}
return _results;
return results;
};
compilePath = function(source, topLevel, base) {
var code, err, file, files, stats, _i, _len, _results;
if (__indexOf.call(sources, source) >= 0 || watchedDirs[source] || !topLevel && (notSources[source] || hidden(source))) {
var code, err, file, files, i, len, results, stats;
if (indexOf.call(sources, source) >= 0 || watchedDirs[source] || !topLevel && (notSources[source] || hidden(source))) {
return;
}
try {
@@ -135,12 +135,12 @@
throw err;
}
}
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
_results.push(compilePath(path.join(source, file), false, base));
results = [];
for (i = 0, len = files.length; i < len; i++) {
file = files[i];
results.push(compilePath(path.join(source, file), false, base));
}
return _results;
return results;
} else if (topLevel || helpers.isCoffee(source)) {
sources.push(source);
sourceCode.push(null);
@@ -165,10 +165,10 @@
};
findDirectoryIndex = function(source) {
var err, ext, index, _i, _len, _ref1;
_ref1 = CoffeeScript.FILE_EXTENSIONS;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
ext = _ref1[_i];
var err, ext, i, index, len, ref1;
ref1 = CoffeeScript.FILE_EXTENSIONS;
for (i = 0, len = ref1.length; i < len; i++) {
ext = ref1[i];
index = path.join(source, "index" + ext);
try {
if ((fs.statSync(index)).isFile()) {
@@ -281,7 +281,7 @@
if (err.code !== 'ENOENT') {
throw err;
}
if (__indexOf.call(sources, source) < 0) {
if (indexOf.call(sources, source) < 0) {
return;
}
try {
@@ -348,7 +348,7 @@
}).on('change', function() {
clearTimeout(readdirTimeout);
return readdirTimeout = wait(25, function() {
var err, file, files, _i, _len, _results;
var err, file, files, i, len, results;
try {
files = fs.readdirSync(source);
} catch (_error) {
@@ -358,12 +358,12 @@
}
return stopWatcher();
}
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
_results.push(compilePath(path.join(source, file), false, base));
results = [];
for (i = 0, len = files.length; i < len; i++) {
file = files[i];
results.push(compilePath(path.join(source, file), false, base));
}
return _results;
return results;
});
});
};
@@ -383,11 +383,11 @@
};
removeSourceDir = function(source, base) {
var file, sourcesChanged, _i, _len;
var file, i, len, sourcesChanged;
delete watchedDirs[source];
sourcesChanged = false;
for (_i = 0, _len = sources.length; _i < _len; _i++) {
file = sources[_i];
for (i = 0, len = sources.length; i < len; i++) {
file = sources[i];
if (!(source === path.dirname(file))) {
continue;
}
@@ -412,12 +412,12 @@
};
silentUnlink = function(path) {
var err, _ref1;
var err, ref1;
try {
return fs.unlinkSync(path);
} catch (_error) {
err = _error;
if ((_ref1 = err.code) !== 'ENOENT' && _ref1 !== 'EPERM') {
if ((ref1 = err.code) !== 'ENOENT' && ref1 !== 'EPERM') {
throw err;
}
}
@@ -440,6 +440,27 @@
return path.join(dir, basename + extension);
};
mkdirp = function(dir, fn) {
var mkdirs, mode;
mode = 0x1ff & ~process.umask();
return (mkdirs = function(p, fn) {
return fs.exists(p, function(exists) {
if (exists) {
return fn();
} else {
return mkdirs(path.dirname(p), function() {
return fs.mkdir(p, mode, function(err) {
if (err) {
return fn(err);
}
return fn();
});
});
}
});
})(dir, fn);
};
writeJs = function(base, sourcePath, js, jsPath, generatedSourceMap) {
var compile, jsDir, sourceMapPath;
if (generatedSourceMap == null) {
@@ -447,13 +468,20 @@
}
sourceMapPath = outputPath(sourcePath, base, ".js.map");
jsDir = path.dirname(jsPath);
if (jsPath in jsToSources) {
printLine("Error: The two following source files have the same output file:");
printLine(" " + jsToSources[jsPath]);
printLine(" " + sourcePath);
process.exit(1);
}
jsToSources[jsPath] = sourcePath;
compile = function() {
if (opts.compile) {
if (js.length <= 0) {
js = ' ';
}
if (generatedSourceMap) {
js = "" + js + "\n//# sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n";
js = js + "\n//# sourceMappingURL=" + (helpers.baseFileName(sourceMapPath, false, useWinPathSep)) + "\n";
}
fs.writeFile(jsPath, js, function(err) {
if (err) {
@@ -487,21 +515,21 @@
};
timeLog = function(message) {
return console.log("" + ((new Date).toLocaleTimeString()) + " - " + message);
return console.log(((new Date).toLocaleTimeString()) + " - " + message);
};
printTokens = function(tokens) {
var strings, tag, token, value;
strings = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
token = tokens[_i];
var i, len, results;
results = [];
for (i = 0, len = tokens.length; i < len; i++) {
token = tokens[i];
tag = token[0];
value = token[1].toString().replace(/\n/, '\\n');
_results.push("[" + tag + " " + value + "]");
results.push("[" + tag + " " + value + "]");
}
return _results;
return results;
})();
return printLine(strings.join(' '));
};

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
@@ -63,16 +63,26 @@
AlphaNumeric: [
o('NUMBER', function() {
return new Literal($1);
}), o('STRING', function() {
}), o('String')
],
String: [
o('STRING', function() {
return new Literal($1);
}), o('STRING_START Body STRING_END', function() {
return new Parens($2);
})
],
Regex: [
o('REGEX', function() {
return new Literal($1);
}), o('REGEX_START Invocation REGEX_END', function() {
return $2;
})
],
Literal: [
o('AlphaNumeric'), o('JS', function() {
return new Literal($1);
}), o('REGEX', function() {
return new Literal($1);
}), o('DEBUGGER', function() {
}), o('Regex'), o('DEBUGGER', function() {
return new Literal($1);
}), o('UNDEFINED', function() {
return new Undefined;
@@ -421,6 +431,11 @@
return {
source: LOC(2)(new Value($2))
};
}), o('FOR Range BY Expression', function() {
return {
source: LOC(2)(new Value($2)),
step: $4
};
}), o('ForStart ForSource', function() {
$2.own = $1.own;
$2.name = $1[0];
@@ -552,6 +567,12 @@
return new Op('+', $2);
}), {
prec: 'UNARY_MATH'
}), o('YIELD Statement', function() {
return new Op($1, $2);
}), o('YIELD Expression', function() {
return new Op($1, $2);
}), o('YIELD FROM Expression', function() {
return new Op($1.concat($2), $3);
}), o('-- SimpleAssignable', function() {
return new Op('--', $2);
}), o('++ SimpleAssignable', function() {
@@ -594,20 +615,20 @@
]
};
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['left', 'POST_IF']];
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['left', 'POST_IF']];
tokens = [];
for (name in grammar) {
alternatives = grammar[name];
grammar[name] = (function() {
var _i, _j, _len, _len1, _ref, _results;
_results = [];
for (_i = 0, _len = alternatives.length; _i < _len; _i++) {
alt = alternatives[_i];
_ref = alt[0].split(' ');
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
token = _ref[_j];
var i, j, len, len1, ref, results;
results = [];
for (i = 0, len = alternatives.length; i < len; i++) {
alt = alternatives[i];
ref = alt[0].split(' ');
for (j = 0, len1 = ref.length; j < len1; j++) {
token = ref[j];
if (!grammar[token]) {
tokens.push(token);
}
@@ -615,9 +636,9 @@
if (name === 'Root') {
alt[1] = "return " + alt[1];
}
_results.push(alt);
results.push(alt);
}
return _results;
return results;
})();
}

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var buildLocationData, extend, flatten, last, repeat, syntaxErrorToString, _ref;
var buildLocationData, extend, flatten, ref, repeat, syntaxErrorToString;
exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length);
@@ -26,15 +26,15 @@
};
exports.compact = function(array) {
var item, _i, _len, _results;
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
item = array[_i];
var i, item, len1, results;
results = [];
for (i = 0, len1 = array.length; i < len1; i++) {
item = array[i];
if (item) {
_results.push(item);
results.push(item);
}
}
return _results;
return results;
};
exports.count = function(string, substr) {
@@ -63,10 +63,10 @@
};
exports.flatten = flatten = function(array) {
var element, flattened, _i, _len;
var element, flattened, i, len1;
flattened = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
element = array[_i];
for (i = 0, len1 = array.length; i < len1; i++) {
element = array[i];
if (element instanceof Array) {
flattened = flattened.concat(flatten(element));
} else {
@@ -83,14 +83,10 @@
return val;
};
exports.last = last = function(array, back) {
return array[array.length - (back || 0) - 1];
};
exports.some = (_ref = Array.prototype.some) != null ? _ref : function(fn) {
var e, _i, _len;
for (_i = 0, _len = this.length; _i < _len; _i++) {
e = this[_i];
exports.some = (ref = Array.prototype.some) != null ? ref : function(fn) {
var e, i, len1;
for (i = 0, len1 = this.length; i < len1; i++) {
e = this[i];
if (fn(e)) {
return true;
}
@@ -102,20 +98,20 @@
var line, lines, maybe_code;
maybe_code = true;
lines = (function() {
var _i, _len, _ref1, _results;
_ref1 = code.split('\n');
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
line = _ref1[_i];
var i, len1, ref1, results;
ref1 = code.split('\n');
results = [];
for (i = 0, len1 = ref1.length; i < len1; i++) {
line = ref1[i];
if (maybe_code && /^([ ]{4}|[ ]{0,3}\t)/.test(line)) {
_results.push(line);
results.push(line);
} else if (maybe_code = /^\s*$/.test(line)) {
_results.push(line);
results.push(line);
} else {
_results.push('# ' + line);
results.push('# ' + line);
}
}
return _results;
return results;
})();
return lines.join('\n');
};
@@ -150,7 +146,7 @@
locationData = obj;
}
if (locationData) {
return ("" + (locationData.first_line + 1) + ":" + (locationData.first_column + 1) + "-") + ("" + (locationData.last_line + 1) + ":" + (locationData.last_column + 1));
return ((locationData.first_line + 1) + ":" + (locationData.first_column + 1) + "-") + ((locationData.last_line + 1) + ":" + (locationData.last_column + 1));
} else {
return "No location data";
}
@@ -205,11 +201,11 @@
};
syntaxErrorToString = function() {
var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, start, _ref1, _ref2;
var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, ref1, ref2, start;
if (!(this.code && this.location)) {
return Error.prototype.toString.call(this);
}
_ref1 = this.location, first_line = _ref1.first_line, first_column = _ref1.first_column, last_line = _ref1.last_line, last_column = _ref1.last_column;
ref1 = this.location, first_line = ref1.first_line, first_column = ref1.first_column, last_line = ref1.last_line, last_column = ref1.last_column;
if (last_line == null) {
last_line = first_line;
}
@@ -224,14 +220,14 @@
if (typeof process !== "undefined" && process !== null) {
colorsEnabled = process.stdout.isTTY && !process.env.NODE_DISABLE_COLORS;
}
if ((_ref2 = this.colorful) != null ? _ref2 : colorsEnabled) {
if ((ref2 = this.colorful) != null ? ref2 : colorsEnabled) {
colorize = function(str) {
return "\x1B[1;31m" + str + "\x1B[0m";
};
codeLine = codeLine.slice(0, start) + colorize(codeLine.slice(start, end)) + codeLine.slice(end);
marker = colorize(marker);
}
return "" + filename + ":" + (first_line + 1) + ":" + (first_column + 1) + ": error: " + this.message + "\n" + codeLine + "\n" + marker;
return filename + ":" + (first_line + 1) + ":" + (first_column + 1) + ": error: " + this.message + "\n" + codeLine + "\n" + marker;
};
exports.nameWhitespaceCharacter = function(string) {

View File

@@ -1,10 +1,10 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var key, val, _ref;
var key, ref, val;
_ref = require('./coffee-script');
for (key in _ref) {
val = _ref[key];
ref = require('./coffee-script');
for (key in ref) {
val = ref[key];
exports[key] = val;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments, repeat;
@@ -11,14 +11,14 @@
}
OptionParser.prototype.parse = function(args) {
var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, seenNonOptionArg, skippingArgument, value, _i, _j, _len, _len1, _ref;
var arg, i, isOption, j, k, len, len1, matchedRule, options, originalArgs, pos, ref, rule, seenNonOptionArg, skippingArgument, value;
options = {
"arguments": []
};
skippingArgument = false;
originalArgs = args;
args = normalizeArguments(args);
for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) {
for (i = j = 0, len = args.length; j < len; i = ++j) {
arg = args[i];
if (skippingArgument) {
skippingArgument = false;
@@ -33,9 +33,9 @@
seenNonOptionArg = options["arguments"].length > 0;
if (!seenNonOptionArg) {
matchedRule = false;
_ref = this.rules;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
rule = _ref[_j];
ref = this.rules;
for (k = 0, len1 = ref.length; k < len1; k++) {
rule = ref[k];
if (rule.shortFlag === arg || rule.longFlag === arg) {
value = true;
if (rule.hasArgument) {
@@ -59,14 +59,14 @@
};
OptionParser.prototype.help = function() {
var letPart, lines, rule, spaces, _i, _len, _ref;
var j, len, letPart, lines, ref, rule, spaces;
lines = [];
if (this.banner) {
lines.unshift("" + this.banner + "\n");
lines.unshift(this.banner + "\n");
}
_ref = this.rules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rule = _ref[_i];
ref = this.rules;
for (j = 0, len = ref.length; j < len; j++) {
rule = ref[j];
spaces = 15 - rule.longFlag.length;
spaces = spaces > 0 ? repeat(' ', spaces) : '';
letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' ';
@@ -88,16 +88,16 @@
OPTIONAL = /\[(\w+(\*?))\]/;
buildRules = function(rules) {
var tuple, _i, _len, _results;
_results = [];
for (_i = 0, _len = rules.length; _i < _len; _i++) {
tuple = rules[_i];
var j, len, results, tuple;
results = [];
for (j = 0, len = rules.length; j < len; j++) {
tuple = rules[j];
if (tuple.length < 3) {
tuple.unshift(null);
}
_results.push(buildRule.apply(null, tuple));
results.push(buildRule.apply(null, tuple));
}
return _results;
return results;
};
buildRule = function(shortFlag, longFlag, description, options) {
@@ -118,15 +118,15 @@
};
normalizeArguments = function(args) {
var arg, l, match, result, _i, _j, _len, _len1, _ref;
var arg, j, k, l, len, len1, match, ref, result;
args = args.slice(0);
result = [];
for (_i = 0, _len = args.length; _i < _len; _i++) {
arg = args[_i];
for (j = 0, len = args.length; j < len; j++) {
arg = args[j];
if (match = arg.match(MULTI_FLAG)) {
_ref = match[1].split('');
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
l = _ref[_j];
ref = match[1].split('');
for (k = 0, len1 = ref.length; k < len1; k++) {
l = ref[k];
result.push('-' + l);
}
} else {

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, helpers, loadFile, path, _i, _len, _ref;
var CoffeeScript, Module, binary, child_process, ext, findExtension, fork, helpers, i, len, loadFile, path, ref;
CoffeeScript = require('./coffee-script');
@@ -17,9 +17,9 @@
};
if (require.extensions) {
_ref = CoffeeScript.FILE_EXTENSIONS;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
ext = _ref[_i];
ref = CoffeeScript.FILE_EXTENSIONS;
for (i = 0, len = ref.length; i < len; i++) {
ext = ref[i];
require.extensions[ext] = loadFile;
}
Module = require('module');

View File

@@ -1,6 +1,6 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, updateSyntaxError, vm, _ref;
var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, ref, replDefaults, updateSyntaxError, vm;
fs = require('fs');
@@ -12,23 +12,36 @@
CoffeeScript = require('./coffee-script');
_ref = require('./helpers'), merge = _ref.merge, updateSyntaxError = _ref.updateSyntaxError;
ref = require('./helpers'), merge = ref.merge, updateSyntaxError = ref.updateSyntaxError;
replDefaults = {
prompt: 'coffee> ',
historyFile: process.env.HOME ? path.join(process.env.HOME, '.coffee_history') : void 0,
historyMaxInputSize: 10240,
"eval": function(input, context, filename, cb) {
var Assign, Block, Literal, Value, ast, err, js, result, _ref1;
var Assign, Block, Literal, Value, ast, err, js, ref1, referencedVars, result, token, tokens;
input = input.replace(/\uFF00/g, '\n');
input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1');
_ref1 = require('./nodes'), Block = _ref1.Block, Assign = _ref1.Assign, Value = _ref1.Value, Literal = _ref1.Literal;
ref1 = require('./nodes'), Block = ref1.Block, Assign = ref1.Assign, Value = ref1.Value, Literal = ref1.Literal;
try {
ast = CoffeeScript.nodes(input);
tokens = CoffeeScript.tokens(input);
referencedVars = (function() {
var i, len, results;
results = [];
for (i = 0, len = tokens.length; i < len; i++) {
token = tokens[i];
if (token.variable) {
results.push(token[1]);
}
}
return results;
})();
ast = CoffeeScript.nodes(tokens);
ast = new Block([new Assign(new Value(new Literal('_')), ast, '=')]);
js = ast.compile({
bare: true,
locals: Object.keys(context)
locals: Object.keys(context),
referencedVars: referencedVars
});
result = context === global ? vm.runInThisContext(js, filename) : vm.runInContext(js, context, filename);
return cb(null, result);
@@ -41,9 +54,9 @@
};
addMultilineHandler = function(repl) {
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, rli, _ref1;
var inputStream, multiline, nodeLineListener, origPrompt, outputStream, ref1, rli;
rli = repl.rli, inputStream = repl.inputStream, outputStream = repl.outputStream;
origPrompt = (_ref1 = repl._prompt) != null ? _ref1 : repl.prompt;
origPrompt = (ref1 = repl._prompt) != null ? ref1 : repl.prompt;
multiline = {
enabled: false,
initialPrompt: origPrompt.replace(/^[^> ]*/, function(x) {
@@ -58,7 +71,7 @@
rli.removeListener('line', nodeLineListener);
rli.on('line', function(cmd) {
if (multiline.enabled) {
multiline.buffer += "" + cmd + "\n";
multiline.buffer += cmd + "\n";
rli.setPrompt(multiline.prompt);
rli.prompt(true);
} else {
@@ -118,7 +131,7 @@
fd = fs.openSync(filename, 'a');
repl.rli.addListener('line', function(code) {
if (code && code.length && code !== '.history' && lastLine !== code) {
fs.write(fd, "" + code + "\n");
fs.write(fd, code + "\n");
return lastLine = code;
}
});
@@ -128,7 +141,7 @@
return repl.commands[getCommandId(repl, 'history')] = {
help: 'Show command history',
action: function() {
repl.outputStream.write("" + (repl.rli.history.slice(0).reverse().join('\n')) + "\n");
repl.outputStream.write((repl.rli.history.slice(0).reverse().join('\n')) + "\n");
return repl.displayPrompt();
}
};
@@ -146,13 +159,13 @@
module.exports = {
start: function(opts) {
var build, major, minor, repl, _ref1;
var build, major, minor, ref1, repl;
if (opts == null) {
opts = {};
}
_ref1 = process.versions.node.split('.').map(function(n) {
ref1 = process.versions.node.split('.').map(function(n) {
return parseInt(n);
}), major = _ref1[0], minor = _ref1[1], build = _ref1[2];
}), major = ref1[0], minor = ref1[1], build = ref1[2];
if (major === 0 && minor < 8) {
console.warn("Node 0.8.0+ required for CoffeeScript REPL");
process.exit(1);

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, left, rite, _i, _len, _ref,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice;
var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, k, left, len, ref, rite,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
slice = [].slice;
generate = function(tag, value, origin) {
var tok;
@@ -17,8 +17,8 @@
exports.Rewriter = (function() {
function Rewriter() {}
Rewriter.prototype.rewrite = function(tokens) {
this.tokens = tokens;
Rewriter.prototype.rewrite = function(tokens1) {
this.tokens = tokens1;
this.removeLeadingNewlines();
this.closeOpenCalls();
this.closeOpenIndexes();
@@ -40,7 +40,7 @@
};
Rewriter.prototype.detectEnd = function(i, condition, action) {
var levels, token, tokens, _ref, _ref1;
var levels, ref, ref1, token, tokens;
tokens = this.tokens;
levels = 0;
while (token = tokens[i]) {
@@ -50,9 +50,9 @@
if (!token || levels < 0) {
return action.call(this, token, i - 1);
}
if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) {
if (ref = token[0], indexOf.call(EXPRESSION_START, ref) >= 0) {
levels += 1;
} else if (_ref1 = token[0], __indexOf.call(EXPRESSION_END, _ref1) >= 0) {
} else if (ref1 = token[0], indexOf.call(EXPRESSION_END, ref1) >= 0) {
levels -= 1;
}
i += 1;
@@ -61,10 +61,10 @@
};
Rewriter.prototype.removeLeadingNewlines = function() {
var i, tag, _i, _len, _ref;
_ref = this.tokens;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
tag = _ref[i][0];
var i, k, len, ref, tag;
ref = this.tokens;
for (i = k = 0, len = ref.length; k < len; i = ++k) {
tag = ref[i][0];
if (tag !== 'TERMINATOR') {
break;
}
@@ -77,8 +77,8 @@
Rewriter.prototype.closeOpenCalls = function() {
var action, condition;
condition = function(token, i) {
var _ref;
return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')';
var ref;
return ((ref = token[0]) === ')' || ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')';
};
action = function(token, i) {
return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END';
@@ -94,8 +94,8 @@
Rewriter.prototype.closeOpenIndexes = function() {
var action, condition;
condition = function(token, i) {
var _ref;
return (_ref = token[0]) === ']' || _ref === 'INDEX_END';
var ref;
return (ref = token[0]) === ']' || ref === 'INDEX_END';
};
action = function(token, i) {
return token[0] = 'INDEX_END';
@@ -108,11 +108,11 @@
});
};
Rewriter.prototype.matchTags = function() {
var fuzz, i, j, pattern, _i, _ref, _ref1;
i = arguments[0], pattern = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
Rewriter.prototype.indexOfTag = function() {
var fuzz, i, j, k, pattern, ref, ref1;
i = arguments[0], pattern = 2 <= arguments.length ? slice.call(arguments, 1) : [];
fuzz = 0;
for (j = _i = 0, _ref = pattern.length; 0 <= _ref ? _i < _ref : _i > _ref; j = 0 <= _ref ? ++_i : --_i) {
for (j = k = 0, ref = pattern.length; 0 <= ref ? k < ref : k > ref; j = 0 <= ref ? ++k : --k) {
while (this.tag(i + j + fuzz) === 'HERECOMMENT') {
fuzz += 2;
}
@@ -122,37 +122,55 @@
if (typeof pattern[j] === 'string') {
pattern[j] = [pattern[j]];
}
if (_ref1 = this.tag(i + j + fuzz), __indexOf.call(pattern[j], _ref1) < 0) {
return false;
if (ref1 = this.tag(i + j + fuzz), indexOf.call(pattern[j], ref1) < 0) {
return -1;
}
}
return true;
return i + j + fuzz - 1;
};
Rewriter.prototype.looksObjectish = function(j) {
return this.matchTags(j, '@', null, ':') || this.matchTags(j, null, ':');
var end, index;
if (this.indexOfTag(j, '@', null, ':') > -1 || this.indexOfTag(j, null, ':') > -1) {
return true;
}
index = this.indexOfTag(j, EXPRESSION_START);
if (index > -1) {
end = null;
this.detectEnd(index + 1, (function(token) {
var ref;
return ref = token[0], indexOf.call(EXPRESSION_END, ref) >= 0;
}), (function(token, i) {
return end = i;
}));
if (this.tag(end + 1) === ':') {
return true;
}
}
return false;
};
Rewriter.prototype.findTagsBackwards = function(i, tags) {
var backStack, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
var backStack, ref, ref1, ref2, ref3, ref4, ref5;
backStack = [];
while (i >= 0 && (backStack.length || (_ref2 = this.tag(i), __indexOf.call(tags, _ref2) < 0) && ((_ref3 = this.tag(i), __indexOf.call(EXPRESSION_START, _ref3) < 0) || this.tokens[i].generated) && (_ref4 = this.tag(i), __indexOf.call(LINEBREAKS, _ref4) < 0))) {
if (_ref = this.tag(i), __indexOf.call(EXPRESSION_END, _ref) >= 0) {
while (i >= 0 && (backStack.length || (ref2 = this.tag(i), indexOf.call(tags, ref2) < 0) && ((ref3 = this.tag(i), indexOf.call(EXPRESSION_START, ref3) < 0) || this.tokens[i].generated) && (ref4 = this.tag(i), indexOf.call(LINEBREAKS, ref4) < 0))) {
if (ref = this.tag(i), indexOf.call(EXPRESSION_END, ref) >= 0) {
backStack.push(this.tag(i));
}
if ((_ref1 = this.tag(i), __indexOf.call(EXPRESSION_START, _ref1) >= 0) && backStack.length) {
if ((ref1 = this.tag(i), indexOf.call(EXPRESSION_START, ref1) >= 0) && backStack.length) {
backStack.pop();
}
i -= 1;
}
return _ref5 = this.tag(i), __indexOf.call(tags, _ref5) >= 0;
return ref5 = this.tag(i), indexOf.call(tags, ref5) >= 0;
};
Rewriter.prototype.addImplicitBracesAndParens = function() {
var stack;
var stack, start;
stack = [];
start = null;
return this.scanTokens(function(token, i, tokens) {
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, newLine, nextTag, offset, prevTag, prevToken, ref, ref1, ref2, ref3, ref4, ref5, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag;
tag = token[0];
prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0];
nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0];
@@ -164,20 +182,20 @@
return i - startIdx + n;
};
inImplicit = function() {
var _ref, _ref1;
return (_ref = stackTop()) != null ? (_ref1 = _ref[2]) != null ? _ref1.ours : void 0 : void 0;
var ref, ref1;
return (ref = stackTop()) != null ? (ref1 = ref[2]) != null ? ref1.ours : void 0 : void 0;
};
inImplicitCall = function() {
var _ref;
return inImplicit() && ((_ref = stackTop()) != null ? _ref[0] : void 0) === '(';
var ref;
return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '(';
};
inImplicitObject = function() {
var _ref;
return inImplicit() && ((_ref = stackTop()) != null ? _ref[0] : void 0) === '{';
var ref;
return inImplicit() && ((ref = stackTop()) != null ? ref[0] : void 0) === '{';
};
inImplicitControl = function() {
var _ref;
return inImplicit && ((_ref = stackTop()) != null ? _ref[0] : void 0) === 'CONTROL';
var ref;
return inImplicit && ((ref = stackTop()) != null ? ref[0] : void 0) === 'CONTROL';
};
startImplicitCall = function(j) {
var idx;
@@ -194,11 +212,11 @@
};
endImplicitCall = function() {
stack.pop();
tokens.splice(i, 0, generate('CALL_END', ')'));
tokens.splice(i, 0, generate('CALL_END', ')', ['', 'end of input', token[2]]));
return i += 1;
};
startImplicitObject = function(j, startsLine) {
var idx;
var idx, val;
if (startsLine == null) {
startsLine = true;
}
@@ -210,7 +228,9 @@
ours: true
}
]);
tokens.splice(idx, 0, generate('{', generate(new String('{')), token));
val = new String('{');
val.generated = true;
tokens.splice(idx, 0, generate('{', val, token));
if (j == null) {
return i += 1;
}
@@ -241,11 +261,11 @@
stack.push([tag, i]);
return forward(1);
}
if (__indexOf.call(EXPRESSION_START, tag) >= 0) {
if (indexOf.call(EXPRESSION_START, tag) >= 0) {
stack.push([tag, i]);
return forward(1);
}
if (__indexOf.call(EXPRESSION_END, tag) >= 0) {
if (indexOf.call(EXPRESSION_END, tag) >= 0) {
while (inImplicit()) {
if (inImplicitCall()) {
endImplicitCall();
@@ -255,33 +275,39 @@
stack.pop();
}
}
stack.pop();
start = stack.pop();
}
if ((__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced && !token.stringEnd || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (__indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || __indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((_ref = tokens[i + 1]) != null ? _ref.spaced : void 0) && !((_ref1 = tokens[i + 1]) != null ? _ref1.newLine : void 0))) {
if ((indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((ref = tokens[i + 1]) != null ? ref.spaced : void 0) && !((ref1 = tokens[i + 1]) != null ? ref1.newLine : void 0))) {
if (tag === '?') {
tag = token[0] = 'FUNC_EXIST';
}
startImplicitCall(i + 1);
return forward(2);
}
if (__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.matchTags(i + 1, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
if (indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.indexOfTag(i + 1, 'INDENT', null, ':') > -1 && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
startImplicitCall(i + 1);
stack.push(['INDENT', i + 2]);
return forward(3);
}
if (tag === ':') {
if (this.tag(i - 2) === '@') {
s = i - 2;
} else {
s = i - 1;
}
s = (function() {
var ref2;
switch (false) {
case ref2 = this.tag(i - 1), indexOf.call(EXPRESSION_END, ref2) < 0:
return start[1];
case this.tag(i - 2) !== '@':
return i - 2;
default:
return i - 1;
}
}).call(this);
while (this.tag(s - 2) === 'HERECOMMENT') {
s -= 2;
}
this.insideForDeclaration = nextTag === 'FOR';
startsLine = s === 0 || (_ref2 = this.tag(s - 1), __indexOf.call(LINEBREAKS, _ref2) >= 0) || tokens[s - 1].newLine;
startsLine = s === 0 || (ref2 = this.tag(s - 1), indexOf.call(LINEBREAKS, ref2) >= 0) || tokens[s - 1].newLine;
if (stackTop()) {
_ref3 = stackTop(), stackTag = _ref3[0], stackIdx = _ref3[1];
ref3 = stackTop(), stackTag = ref3[0], stackIdx = ref3[1];
if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) {
return forward(1);
}
@@ -289,18 +315,21 @@
startImplicitObject(s, !!startsLine);
return forward(2);
}
if (inImplicitObject() && __indexOf.call(LINEBREAKS, tag) >= 0) {
if (inImplicitObject() && indexOf.call(LINEBREAKS, tag) >= 0) {
stackTop()[2].sameLine = false;
}
newLine = prevTag === 'OUTDENT' || prevToken.newLine;
if (__indexOf.call(IMPLICIT_END, tag) >= 0 || __indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) {
if (indexOf.call(IMPLICIT_END, tag) >= 0 || indexOf.call(CALL_CLOSERS, tag) >= 0 && newLine) {
while (inImplicit()) {
_ref4 = stackTop(), stackTag = _ref4[0], stackIdx = _ref4[1], (_ref5 = _ref4[2], sameLine = _ref5.sameLine, startsLine = _ref5.startsLine);
ref4 = stackTop(), stackTag = ref4[0], stackIdx = ref4[1], (ref5 = ref4[2], sameLine = ref5.sameLine, startsLine = ref5.startsLine);
if (inImplicitCall() && prevTag !== ',') {
endImplicitCall();
} else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':' && endImplicitObject()) {
} else if (inImplicitObject() && !this.insideForDeclaration && sameLine && tag !== 'TERMINATOR' && prevTag !== ':') {
endImplicitObject();
} else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) {
if (nextTag === 'HERECOMMENT') {
return forward(1);
}
endImplicitObject();
} else {
break;
@@ -319,16 +348,16 @@
Rewriter.prototype.addLocationDataToGeneratedTokens = function() {
return this.scanTokens(function(token, i, tokens) {
var column, line, nextLocation, prevLocation, _ref, _ref1;
var column, line, nextLocation, prevLocation, ref, ref1;
if (token[2]) {
return 1;
}
if (!(token.generated || token.explicit)) {
return 1;
}
if (token[0] === '{' && (nextLocation = (_ref = tokens[i + 1]) != null ? _ref[2] : void 0)) {
if (token[0] === '{' && (nextLocation = (ref = tokens[i + 1]) != null ? ref[2] : void 0)) {
line = nextLocation.first_line, column = nextLocation.first_column;
} else if (prevLocation = (_ref1 = tokens[i - 1]) != null ? _ref1[2] : void 0) {
} else if (prevLocation = (ref1 = tokens[i - 1]) != null ? ref1[2] : void 0) {
line = prevLocation.last_line, column = prevLocation.last_column;
} else {
line = column = 0;
@@ -347,37 +376,37 @@
var action, condition, indent, outdent, starter;
starter = indent = outdent = null;
condition = function(token, i) {
var _ref, _ref1, _ref2, _ref3;
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'TERMINATOR' && (_ref1 = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((_ref2 = token[0]) === 'CATCH' || _ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (_ref3 = token[0], __indexOf.call(CALL_CLOSERS, _ref3) >= 0) && this.tokens[i - 1].newLine;
var ref, ref1, ref2, ref3;
return token[1] !== ';' && (ref = token[0], indexOf.call(SINGLE_CLOSERS, ref) >= 0) && !(token[0] === 'TERMINATOR' && (ref1 = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((ref2 = token[0]) === 'CATCH' || ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (ref3 = token[0], indexOf.call(CALL_CLOSERS, ref3) >= 0) && this.tokens[i - 1].newLine;
};
action = function(token, i) {
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
};
return this.scanTokens(function(token, i, tokens) {
var j, tag, _i, _ref, _ref1, _ref2;
var j, k, ref, ref1, ref2, tag;
tag = token[0];
if (tag === 'TERMINATOR') {
if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
tokens.splice.apply(tokens, [i, 1].concat(__slice.call(this.indentation())));
tokens.splice.apply(tokens, [i, 1].concat(slice.call(this.indentation())));
return 1;
}
if (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0) {
if (ref = this.tag(i + 1), indexOf.call(EXPRESSION_CLOSE, ref) >= 0) {
tokens.splice(i, 1);
return 0;
}
}
if (tag === 'CATCH') {
for (j = _i = 1; _i <= 2; j = ++_i) {
if (!((_ref1 = this.tag(i + j)) === 'OUTDENT' || _ref1 === 'TERMINATOR' || _ref1 === 'FINALLY')) {
for (j = k = 1; k <= 2; j = ++k) {
if (!((ref1 = this.tag(i + j)) === 'OUTDENT' || ref1 === 'TERMINATOR' || ref1 === 'FINALLY')) {
continue;
}
tokens.splice.apply(tokens, [i + j, 0].concat(__slice.call(this.indentation())));
tokens.splice.apply(tokens, [i + j, 0].concat(slice.call(this.indentation())));
return 2 + j;
}
}
if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
if (indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
starter = tag;
_ref2 = this.indentation(tokens[i]), indent = _ref2[0], outdent = _ref2[1];
ref2 = this.indentation(tokens[i]), indent = ref2[0], outdent = ref2[1];
if (starter === 'THEN') {
indent.fromThen = true;
}
@@ -399,7 +428,7 @@
var prevTag, tag;
tag = token[0];
prevTag = this.tokens[i - 1][0];
return tag === 'TERMINATOR' || (tag === 'INDENT' && __indexOf.call(SINGLE_LINERS, prevTag) < 0);
return tag === 'TERMINATOR' || (tag === 'INDENT' && indexOf.call(SINGLE_LINERS, prevTag) < 0);
};
action = function(token, i) {
if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) {
@@ -432,15 +461,15 @@
Rewriter.prototype.generate = generate;
Rewriter.prototype.tag = function(i) {
var _ref;
return (_ref = this.tokens[i]) != null ? _ref[0] : void 0;
var ref;
return (ref = this.tokens[i]) != null ? ref[0] : void 0;
};
return Rewriter;
})();
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']];
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END'], ['STRING_START', 'STRING_END'], ['REGEX_START', 'REGEX_END']];
exports.INVERSES = INVERSES = {};
@@ -448,8 +477,8 @@
EXPRESSION_END = [];
for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) {
_ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1];
for (k = 0, len = BALANCED_PAIRS.length; k < len; k++) {
ref = BALANCED_PAIRS[k], left = ref[0], rite = ref[1];
EXPRESSION_START.push(INVERSES[rite] = left);
EXPRESSION_END.push(INVERSES[left] = rite);
}
@@ -458,7 +487,7 @@
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'UNARY_MATH', 'SUPER', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'STRING_START', 'JS', 'REGEX', 'REGEX_START', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'YIELD', 'UNARY_MATH', 'SUPER', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++'];
IMPLICIT_UNSPACED_CALL = ['+', '-'];

View File

@@ -1,16 +1,15 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var Scope, extend, last, _ref;
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
var Scope,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
exports.Scope = Scope = (function() {
Scope.root = null;
function Scope(parent, expressions, method) {
function Scope(parent, expressions, method, referencedVars) {
var ref, ref1;
this.parent = parent;
this.expressions = expressions;
this.method = method;
this.referencedVars = referencedVars;
this.variables = [
{
name: 'arguments',
@@ -19,8 +18,9 @@
];
this.positions = {};
if (!this.parent) {
Scope.root = this;
this.utilities = {};
}
this.root = (ref = (ref1 = this.parent) != null ? ref1.root : void 0) != null ? ref : this;
}
Scope.prototype.add = function(name, type, immediate) {
@@ -38,8 +38,8 @@
};
Scope.prototype.namedMethod = function() {
var _ref1;
if (((_ref1 = this.method) != null ? _ref1.name : void 0) || !this.parent) {
var ref;
if (((ref = this.method) != null ? ref.name : void 0) || !this.parent) {
return this.method;
}
return this.parent.namedMethod();
@@ -61,23 +61,26 @@
};
Scope.prototype.check = function(name) {
var _ref1;
return !!(this.type(name) || ((_ref1 = this.parent) != null ? _ref1.check(name) : void 0));
var ref;
return !!(this.type(name) || ((ref = this.parent) != null ? ref.check(name) : void 0));
};
Scope.prototype.temporary = function(name, index) {
if (name.length > 1) {
return '_' + name + (index > 1 ? index - 1 : '');
Scope.prototype.temporary = function(name, index, single) {
if (single == null) {
single = false;
}
if (single) {
return (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
} else {
return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
return name + (index || '');
}
};
Scope.prototype.type = function(name) {
var v, _i, _len, _ref1;
_ref1 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
var i, len, ref, v;
ref = this.variables;
for (i = 0, len = ref.length; i < len; i++) {
v = ref[i];
if (v.name === name) {
return v.type;
}
@@ -85,16 +88,20 @@
return null;
};
Scope.prototype.freeVariable = function(name, reserve) {
var index, temp;
if (reserve == null) {
reserve = true;
Scope.prototype.freeVariable = function(name, options) {
var index, ref, temp;
if (options == null) {
options = {};
}
index = 0;
while (this.check((temp = this.temporary(name, index)))) {
while (true) {
temp = this.temporary(name, index, options.single);
if (!(this.check(temp) || indexOf.call(this.root.referencedVars, temp) >= 0)) {
break;
}
index++;
}
if (reserve) {
if ((ref = options.reserve) != null ? ref : true) {
this.add(temp, 'var', true);
}
return temp;
@@ -113,30 +120,32 @@
};
Scope.prototype.declaredVariables = function() {
var realVars, tempVars, v, _i, _len, _ref1;
realVars = [];
tempVars = [];
_ref1 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.type === 'var') {
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
var v;
return ((function() {
var i, len, ref, results;
ref = this.variables;
results = [];
for (i = 0, len = ref.length; i < len; i++) {
v = ref[i];
if (v.type === 'var') {
results.push(v.name);
}
}
}
return realVars.sort().concat(tempVars.sort());
return results;
}).call(this)).sort();
};
Scope.prototype.assignedVariables = function() {
var v, _i, _len, _ref1, _results;
_ref1 = this.variables;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
var i, len, ref, results, v;
ref = this.variables;
results = [];
for (i = 0, len = ref.length; i < len; i++) {
v = ref[i];
if (v.type.assigned) {
_results.push("" + v.name + " = " + v.type.value);
results.push(v.name + " = " + v.type.value);
}
}
return _results;
return results;
};
return Scope;

View File

@@ -1,16 +1,16 @@
// Generated by CoffeeScript 1.8.0
// Generated by CoffeeScript 1.9.1
(function() {
var LineMap, SourceMap;
LineMap = (function() {
function LineMap(line) {
this.line = line;
function LineMap(line1) {
this.line = line1;
this.columns = [];
}
LineMap.prototype.add = function(column, _arg, options) {
LineMap.prototype.add = function(column, arg, options) {
var sourceColumn, sourceLine;
sourceLine = _arg[0], sourceColumn = _arg[1];
sourceLine = arg[0], sourceColumn = arg[1];
if (options == null) {
options = {};
}
@@ -45,18 +45,18 @@
}
SourceMap.prototype.add = function(sourceLocation, generatedLocation, options) {
var column, line, lineMap, _base;
var base, column, line, lineMap;
if (options == null) {
options = {};
}
line = generatedLocation[0], column = generatedLocation[1];
lineMap = ((_base = this.lines)[line] || (_base[line] = new LineMap(line)));
lineMap = ((base = this.lines)[line] || (base[line] = new LineMap(line)));
return lineMap.add(column, sourceLocation, options);
};
SourceMap.prototype.sourceLocation = function(_arg) {
SourceMap.prototype.sourceLocation = function(arg) {
var column, line, lineMap;
line = _arg[0], column = _arg[1];
line = arg[0], column = arg[1];
while (!((lineMap = this.lines[line]) || (line <= 0))) {
line--;
}
@@ -64,7 +64,7 @@
};
SourceMap.prototype.generate = function(options, code) {
var buffer, lastColumn, lastSourceColumn, lastSourceLine, lineMap, lineNumber, mapping, needComma, v3, writingline, _i, _j, _len, _len1, _ref, _ref1;
var buffer, i, j, lastColumn, lastSourceColumn, lastSourceLine, len, len1, lineMap, lineNumber, mapping, needComma, ref, ref1, v3, writingline;
if (options == null) {
options = {};
}
@@ -77,13 +77,13 @@
lastSourceColumn = 0;
needComma = false;
buffer = "";
_ref = this.lines;
for (lineNumber = _i = 0, _len = _ref.length; _i < _len; lineNumber = ++_i) {
lineMap = _ref[lineNumber];
ref = this.lines;
for (lineNumber = i = 0, len = ref.length; i < len; lineNumber = ++i) {
lineMap = ref[lineNumber];
if (lineMap) {
_ref1 = lineMap.columns;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
mapping = _ref1[_j];
ref1 = lineMap.columns;
for (j = 0, len1 = ref1.length; j < len1; j++) {
mapping = ref1[j];
if (!(mapping)) {
continue;
}

View File

@@ -8,7 +8,7 @@
"compiler"
],
"author": "Jeremy Ashkenas",
"version": "1.8.0",
"version": "1.9.1",
"license": "MIT",
"engines": {
"node": ">=0.8.0"
@@ -23,7 +23,8 @@
},
"preferGlobal": true,
"scripts": {
"test": "node ./bin/cake test"
"test": "node ./bin/cake test",
"test-harmony": "node --harmony ./bin/cake test"
},
"homepage": "http://coffeescript.org",
"bugs": "https://github.com/jashkenas/coffeescript/issues",
@@ -36,9 +37,6 @@
"jison": ">=0.2.0",
"highlight.js": "~8.0.0",
"underscore": "~1.5.2",
"docco": "~0.6.2"
},
"dependencies": {
"mkdirp": "~0.3.5"
"docco": "~0.7.0"
}
}

View File

@@ -12,7 +12,7 @@ helpers = require './helpers'
SourceMap = require './sourcemap'
# The current CoffeeScript version number.
exports.VERSION = '1.8.0'
exports.VERSION = '1.9.1'
exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']
@@ -44,7 +44,15 @@ exports.compile = compile = withPrettyErrors (code, options) ->
if options.sourceMap
map = new SourceMap
fragments = parser.parse(lexer.tokenize code, options).compileToFragments options
tokens = lexer.tokenize code, options
# Pass a list of referenced variables, so that generated variables won't get
# the same name.
options.referencedVars = (
token[1] for token in tokens when token.variable
)
fragments = parser.parse(tokens).compileToFragments options
currentLine = 0
currentLine += 1 if options.header
@@ -124,13 +132,17 @@ exports.run = (code, options = {}) ->
# The CoffeeScript REPL uses this to run the input.
exports.eval = (code, options = {}) ->
return unless code = code.trim()
Script = vm.Script
if Script
createContext = vm.Script.createContext ? vm.createContext
isContext = vm.isContext ? (ctx) ->
options.sandbox instanceof createContext().constructor
if createContext
if options.sandbox?
if options.sandbox instanceof Script.createContext().constructor
if isContext options.sandbox
sandbox = options.sandbox
else
sandbox = Script.createContext()
sandbox = createContext()
sandbox[k] = v for own k, v of options.sandbox
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
else
@@ -188,16 +200,17 @@ lexer = new Lexer
# directly as a "Jison lexer".
parser.lexer =
lex: ->
token = @tokens[@pos++]
token = parser.tokens[@pos++]
if token
[tag, @yytext, @yylloc] = token
@errorToken = token.origin or token
parser.errorToken = token.origin or token
@yylineno = @yylloc.first_line
else
tag = ''
tag
setInput: (@tokens) ->
setInput: (tokens) ->
parser.tokens = tokens
@pos = 0
upcomingInput: ->
""
@@ -209,15 +222,18 @@ parser.yy.parseError = (message, {token}) ->
# Disregard Jison's message, it contains redundant line numer information.
# Disregard the token, we take its value directly from the lexer in case
# the error is caused by a generated token which might refer to its origin.
{errorToken, tokens} = parser.lexer
{errorToken, tokens} = parser
[errorTag, errorText, errorLoc] = errorToken
errorText = if errorToken is tokens[tokens.length - 1]
'end of input'
else if errorTag in ['INDENT', 'OUTDENT']
'indentation'
else
helpers.nameWhitespaceCharacter errorText
errorText = switch
when errorToken is tokens[tokens.length - 1]
'end of input'
when errorTag in ['INDENT', 'OUTDENT']
'indentation'
when errorTag in ['IDENTIFIER', 'NUMBER', 'STRING', 'STRING_START', 'REGEX', 'REGEX_START']
errorTag.replace(/_START$/, '').toLowerCase()
else
helpers.nameWhitespaceCharacter errorText
# The second argument has a `loc` property, which should have the location
# data for this token. Unfortunately, Jison seems to send an outdated `loc`
@@ -303,4 +319,3 @@ Error.prepareStackTrace = (err, stack) ->
" at #{formatSourcePosition frame, getSourceMapping}"
"#{err.toString()}\n#{frames.join '\n'}\n"

View File

@@ -10,7 +10,6 @@ path = require 'path'
helpers = require './helpers'
optparse = require './optparse'
CoffeeScript = require './coffee-script'
mkdirp = require 'mkdirp'
{spawn, exec} = require 'child_process'
{EventEmitter} = require 'events'
@@ -59,6 +58,7 @@ sourceCode = []
notSources = {}
watchedDirs = {}
optionParser = null
jsToSources = {}
# Run `coffee` by parsing passed options and determining what action to take.
# Many flags cause us to divert before compiling anything. Flags passed after
@@ -330,6 +330,20 @@ outputPath = (source, base, extension=".js") ->
dir = path.join opts.output, path.relative base, srcDir
path.join dir, basename + extension
# Recursively mkdir, like `mkdir -p`.
mkdirp = (dir, fn) ->
mode = 0o777 & ~process.umask()
do mkdirs = (p = dir, fn) ->
fs.exists p, (exists) ->
if exists
fn()
else
mkdirs path.dirname(p), ->
fs.mkdir p, mode, (err) ->
return fn err if err
fn()
# 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`.
@@ -339,6 +353,12 @@ outputPath = (source, base, extension=".js") ->
writeJs = (base, sourcePath, js, jsPath, generatedSourceMap = null) ->
sourceMapPath = outputPath sourcePath, base, ".js.map"
jsDir = path.dirname jsPath
if jsPath of jsToSources
printLine "Error: The two following source files have the same output file:"
printLine " " + jsToSources[jsPath]
printLine " " + sourcePath
process.exit 1
jsToSources[jsPath] = sourcePath
compile = ->
if opts.compile
js = ' ' if js.length <= 0

View File

@@ -132,7 +132,17 @@ grammar =
# they can also serve as keys in object literals.
AlphaNumeric: [
o 'NUMBER', -> new Literal $1
o 'String'
]
String: [
o 'STRING', -> new Literal $1
o 'STRING_START Body STRING_END', -> new Parens $2
]
Regex: [
o 'REGEX', -> new Literal $1
o 'REGEX_START Invocation REGEX_END', -> $2
]
# All of our immediate values. Generally these can be passed straight
@@ -140,7 +150,7 @@ grammar =
Literal: [
o 'AlphaNumeric'
o 'JS', -> new Literal $1
o 'REGEX', -> new Literal $1
o 'Regex'
o 'DEBUGGER', -> new Literal $1
o 'UNDEFINED', -> new Undefined
o 'NULL', -> new Null
@@ -451,7 +461,8 @@ grammar =
]
ForBody: [
o 'FOR Range', -> source: LOC(2) new Value($2)
o 'FOR Range', -> source: (LOC(2) new Value($2))
o 'FOR Range BY Expression', -> source: (LOC(2) new Value($2)), step: $4
o 'ForStart ForSource', -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2
]
@@ -536,6 +547,9 @@ grammar =
o 'UNARY_MATH Expression', -> new Op $1 , $2
o '- Expression', (-> new Op '-', $2), prec: 'UNARY_MATH'
o '+ Expression', (-> new Op '+', $2), prec: 'UNARY_MATH'
o 'YIELD Statement', -> new Op $1 , $2
o 'YIELD Expression', -> new Op $1 , $2
o 'YIELD FROM Expression', -> new Op $1.concat($2) , $3
o '-- SimpleAssignable', -> new Op '--', $2
o '++ SimpleAssignable', -> new Op '++', $2
@@ -595,6 +609,7 @@ operators = [
['left', 'COMPARE']
['left', 'LOGIC']
['nonassoc', 'INDENT', 'OUTDENT']
['right', 'YIELD']
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
['right', 'FORIN', 'FOROF', 'BY', 'WHEN']
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']

View File

@@ -62,9 +62,6 @@ exports.del = (obj, key) ->
delete obj[key]
val
# Gets the last item of an array(-like) object.
exports.last = last = (array, back) -> array[array.length - (back or 0) - 1]
# Typical Array::some
exports.some = Array::some ? (fn) ->
return true for e in this when fn e

View File

@@ -12,7 +12,7 @@
{Rewriter, INVERSES} = require './rewriter'
# Import the helpers we need.
{count, starts, compact, last, repeat, invertLiterate,
{count, starts, compact, repeat, invertLiterate,
locationDataToString, throwSyntaxError} = require './helpers'
# The Lexer Class
@@ -32,8 +32,7 @@ exports.Lexer = class Lexer
# Each tokenizing method is responsible for returning the number of characters
# it has consumed.
#
# Before returning the token stream, run it through the [Rewriter](rewriter.html)
# unless explicitly asked not to.
# Before returning the token stream, run it through the [Rewriter](rewriter.html).
tokenize: (code, opts = {}) ->
@literate = opts.literate # Are we lexing literate CoffeeScript?
@indent = 0 # The current indentation level.
@@ -60,7 +59,6 @@ exports.Lexer = class Lexer
@commentToken() or
@whitespaceToken() or
@lineToken() or
@heredocToken() or
@stringToken() or
@numberToken() or
@regexToken() or
@@ -72,8 +70,10 @@ exports.Lexer = class Lexer
i += consumed
return {@tokens, index: i} if opts.untilBalanced and @ends.length is 0
@closeIndentation()
@error "missing #{tag}" if tag = @ends.pop()
@error "missing #{end.tag}", end.origin[2] if end = @ends.pop()
return @tokens if opts.rewrite is off
(new Rewriter).rewrite @tokens
@@ -109,8 +109,12 @@ exports.Lexer = class Lexer
if id is 'own' and @tag() is 'FOR'
@token 'OWN', id
return id.length
forcedIdentifier = colon or
(prev = last @tokens) and (prev[0] in ['.', '?.', '::', '?::'] or
if id is 'from' and @tag() is 'YIELD'
@token 'FROM', id
return id.length
[..., prev] = @tokens
forcedIdentifier = colon or prev? and
(prev[0] in ['.', '?.', '::', '?::'] or
not prev.spaced and prev[0] is '@')
tag = 'IDENTIFIER'
@@ -140,7 +144,7 @@ exports.Lexer = class Lexer
id = new String id
id.reserved = yes
else if id in RESERVED
@error "reserved word \"#{id}\""
@error "reserved word '#{id}'", length: id.length
unless forcedIdentifier
id = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
@@ -153,6 +157,7 @@ exports.Lexer = class Lexer
else tag
tagToken = @token tag, id, 0, idLength
tagToken.variable = not forcedIdentifier
if poppedToken
[tagToken[2].first_line, tagToken[2].first_column] =
[poppedToken[2].first_line, poppedToken[2].first_column]
@@ -167,15 +172,16 @@ exports.Lexer = class Lexer
numberToken: ->
return 0 unless match = NUMBER.exec @chunk
number = match[0]
if /^0[BOX]/.test number
@error "radix prefix '#{number}' must be lowercase"
else if /E/.test(number) and not /^0x/.test number
@error "exponential notation '#{number}' must be indicated with a lowercase 'e'"
else if /^0\d*[89]/.test number
@error "decimal literal '#{number}' must not be prefixed with '0'"
else if /^0\d+/.test number
@error "octal literal '#{number}' must be prefixed with '0o'"
lexedLength = number.length
if /^0[BOX]/.test number
@error "radix prefix in '#{number}' must be lowercase", offset: 1
else if /E/.test(number) and not /^0x/.test number
@error "exponential notation in '#{number}' must be indicated with a lowercase 'e'",
offset: number.indexOf('E')
else if /^0\d*[89]/.test number
@error "decimal literal '#{number}' must not be prefixed with '0'", length: lexedLength
else if /^0\d+/.test number
@error "octal literal '#{number}' must be prefixed with '0o'", length: lexedLength
if octalLiteral = /^0o([0-7]+)/.exec number
number = '0x' + parseInt(octalLiteral[1], 8).toString 16
if binaryLiteral = /^0b([01]+)/.exec number
@@ -183,49 +189,60 @@ exports.Lexer = class Lexer
@token 'NUMBER', number, 0, lexedLength
lexedLength
# Matches strings, including multi-line strings. Ensures that quotation marks
# are balanced within the string's contents, and within nested interpolations.
# Matches strings, including multi-line strings, as well as heredocs, with or without
# interpolation.
stringToken: ->
switch quote = @chunk.charAt 0
when "'" then [string] = SIMPLESTR.exec(@chunk) || []
when '"' then string = @balancedString @chunk, '"'
return 0 unless string
inner = string[1...-1]
trimmed = @removeNewlines inner
if quote is '"' and 0 < string.indexOf '#{', 1
numBreak = pos = 0
innerLen = inner.length
numBreak++ while inner.charAt(pos++) is '\n' and pos < innerLen
@interpolateString trimmed, strOffset: 1 + numBreak, lexedLength: string.length
else
@token 'STRING', quote + @escapeLines(trimmed) + quote, 0, string.length
if octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test string
@error "octal escape sequences #{string} are not allowed"
string.length
[quote] = STRING_START.exec(@chunk) || []
return 0 unless quote
regex = switch quote
when "'" then STRING_SINGLE
when '"' then STRING_DOUBLE
when "'''" then HEREDOC_SINGLE
when '"""' then HEREDOC_DOUBLE
heredoc = quote.length is 3
# Matches heredocs, adjusting indentation to the correct level, as heredocs
# preserve whitespace, but ignore indentation to the left.
heredocToken: ->
return 0 unless match = HEREDOC.exec @chunk
heredoc = match[0]
quote = heredoc.charAt 0
doc = @sanitizeHeredoc match[2], quote: quote, indent: null
if quote is '"' and 0 <= doc.indexOf '#{'
strOffset = if match[2].charAt(0) is '\n' then 4 else 3
@interpolateString doc, heredoc: yes, strOffset: strOffset, lexedLength: heredoc.length
{tokens, index: end} = @matchWithInterpolations regex, quote
$ = tokens.length - 1
delimiter = quote[0]
if heredoc
# Find the smallest indentation. It will be removed from all lines later.
indent = null
doc = (token[1] for token, i in tokens when token[0] is 'NEOSTRING').join '#{}'
while match = HEREDOC_INDENT.exec doc
attempt = match[1]
indent = attempt if indent is null or 0 < attempt.length < indent.length
indentRegex = /// ^#{indent} ///gm if indent
@mergeInterpolationTokens tokens, {delimiter}, (value, i) =>
value = @formatString value
value = value.replace LEADING_BLANK_LINE, '' if i is 0
value = value.replace TRAILING_BLANK_LINE, '' if i is $
value = value.replace indentRegex, '' if indentRegex
value
else
@token 'STRING', @makeString(doc, quote, yes), 0, heredoc.length
heredoc.length
@mergeInterpolationTokens tokens, {delimiter}, (value, i) =>
value = @formatString value
value = value.replace SIMPLE_STRING_OMIT, (match, offset) ->
if (i is 0 and offset is 0) or
(i is $ and offset + match.length is value.length)
''
else
' '
value
end
# Matches and consumes comments.
commentToken: ->
return 0 unless match = @chunk.match COMMENT
[comment, here] = match
if here
@token 'HERECOMMENT',
(@sanitizeHeredoc here,
herecomment: true, indent: repeat ' ', @indent),
0, comment.length
if match = HERECOMMENT_ILLEGAL.exec comment
@error "block comments cannot contain #{match[0]}",
offset: match.index, length: match[0].length
if here.indexOf('\n') >= 0
here = here.replace /// \n #{repeat ' ', @indent} ///g, '\n'
@token 'HERECOMMENT', here, 0, comment.length
comment.length
# Matches JavaScript interpolated directly into the source via backticks.
@@ -234,70 +251,51 @@ exports.Lexer = class Lexer
@token 'JS', (script = match[0])[1...-1], 0, script.length
script.length
# Matches regular expression literals. Lexing regular expressions is difficult
# to distinguish from division, so we borrow some basic heuristics from
# JavaScript and Ruby.
# Matches regular expression literals, as well as multiline extended ones.
# Lexing regular expressions is difficult to distinguish from division, so we
# borrow some basic heuristics from JavaScript and Ruby.
regexToken: ->
return 0 if @chunk.charAt(0) isnt '/'
return length if length = @heregexToken()
prev = last @tokens
return 0 if prev and (prev[0] in (if prev.spaced then NOT_REGEX else NOT_SPACED_REGEX))
return 0 unless match = REGEX.exec @chunk
[match, regex, flags] = match
# Avoid conflicts with floor division operator.
return 0 if regex is '//'
if regex[..1] is '/*' then @error 'regular expressions cannot begin with `*`'
@token 'REGEX', "#{regex}#{flags}", 0, match.length
match.length
# Matches multiline extended regular expressions.
heregexToken: ->
return 0 unless match = HEREGEX.exec @chunk
[heregex, body, flags] = match
if 0 > body.indexOf '#{'
re = @escapeLines body.replace(HEREGEX_OMIT, '$1$2').replace(/\//g, '\\/'), yes
if re.match /^\*/ then @error 'regular expressions cannot begin with `*`'
@token 'REGEX', "/#{ re or '(?:)' }/#{flags}", 0, heregex.length
return heregex.length
@token 'IDENTIFIER', 'RegExp', 0, 0
@token 'CALL_START', '(', 0, 0
tokens = []
for token in @interpolateString(body, regex: yes, strOffset: 3)
[tag, value] = token
if tag is 'TOKENS'
tokens.push value...
else if tag is 'NEOSTRING'
continue unless value = value.replace HEREGEX_OMIT, '$1$2'
# Convert NEOSTRING into STRING
value = value.replace /\\/g, '\\\\'
token[0] = 'STRING'
token[1] = @makeString(value, '"', yes)
tokens.push token
switch
when match = REGEX_ILLEGAL.exec @chunk
@error "regular expressions cannot begin with #{match[2]}",
offset: match.index + match[1].length
when match = @matchWithInterpolations HEREGEX, '///'
{tokens, index} = match
when match = REGEX.exec @chunk
[regex, body, closed] = match
@validateEscapes body, isRegex: yes, offsetInChunk: 1
index = regex.length
[..., prev] = @tokens
if prev
if prev.spaced and prev[0] in CALLABLE
return 0 if not closed or POSSIBLY_DIVISION.test regex
else if prev[0] in NOT_REGEX
return 0
@error 'missing / (unclosed regex)' unless closed
else
@error "Unexpected #{tag}"
return 0
prev = last @tokens
plusToken = ['+', '+']
plusToken[2] = prev[2] # Copy location data
tokens.push plusToken
[flags] = REGEX_FLAGS.exec @chunk[index..]
end = index + flags.length
origin = @makeToken 'REGEX', null, 0, end
switch
when not VALID_FLAGS.test flags
@error "invalid regular expression flags #{flags}", offset: index, length: flags.length
when regex or tokens.length is 1
body ?= @formatHeregex tokens[0][1]
@token 'REGEX', "#{@makeDelimitedLiteral body, delimiter: '/'}#{flags}", 0, end, origin
else
@token 'REGEX_START', '(', 0, 0, origin
@token 'IDENTIFIER', 'RegExp', 0, 0
@token 'CALL_START', '(', 0, 0
@mergeInterpolationTokens tokens, {delimiter: '"', double: yes}, @formatHeregex
if flags
@token ',', ',', index, 0
@token 'STRING', '"' + flags + '"', index, flags.length
@token ')', ')', end, 0
@token 'REGEX_END', ')', end, 0
# Remove the extra "+"
tokens.pop()
unless tokens[0]?[0] is 'STRING'
@token 'STRING', '""', 0, 0
@token '+', '+', 0, 0
@tokens.push tokens...
if flags
# Find the flags in the heregex
flagsOffset = heregex.lastIndexOf flags
@token ',', ',', flagsOffset, 0
@token 'STRING', '"' + flags + '"', flagsOffset, flags.length
@token ')', ')', heregex.length-1, 0
heregex.length
end
# 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,
@@ -330,11 +328,11 @@ exports.Lexer = class Lexer
diff = size - @indent + @outdebt
@token 'INDENT', diff, indent.length - size, size
@indents.push diff
@ends.push 'OUTDENT'
@ends.push {tag: 'OUTDENT'}
@outdebt = @indebt = 0
@indent = size
else if size < @baseIndent
@error 'missing indentation', indent.length
@error 'missing indentation', offset: indent.length
else
@indebt = 0
@outdentToken @indent - size, noNewlines, indent.length
@@ -376,7 +374,7 @@ exports.Lexer = class Lexer
whitespaceToken: ->
return 0 unless (match = WHITESPACE.exec @chunk) or
(nline = @chunk.charAt(0) is '\n')
prev = last @tokens
[..., prev] = @tokens
prev[if match then 'spaced' else 'newLine'] = true if prev
if match then match[0].length else 0
@@ -404,10 +402,10 @@ exports.Lexer = class Lexer
else
value = @chunk.charAt 0
tag = value
prev = last @tokens
[..., prev] = @tokens
if value is '=' and prev
if not prev[1].reserved and prev[1] in JS_FORBIDDEN
@error "reserved word \"#{@value()}\" can't be assigned"
@error "reserved word '#{prev[1]}' can't be assigned", prev[2]
if prev[1] in ['||', '&&']
prev[0] = 'COMPOUND_ASSIGN'
prev[1] += '='
@@ -430,31 +428,16 @@ exports.Lexer = class Lexer
tag = 'INDEX_START'
switch prev[0]
when '?' then prev[0] = 'INDEX_SOAK'
token = @makeToken tag, value
switch value
when '(', '{', '[' then @ends.push INVERSES[value]
when '(', '{', '[' then @ends.push {tag: INVERSES[value], origin: token}
when ')', '}', ']' then @pair value
@token tag, value
@tokens.push token
value.length
# Token Manipulators
# ------------------
# Sanitize a heredoc or herecomment by
# erasing all external indentation on the left-hand side.
sanitizeHeredoc: (doc, options) ->
{indent, herecomment} = options
if herecomment
if HEREDOC_ILLEGAL.test doc
@error "block comment cannot contain \"*/\", starting"
return doc if doc.indexOf('\n') < 0
else
while match = HEREDOC_INDENT.exec doc
attempt = match[1]
indent = attempt if indent is null or 0 < attempt.length < indent.length
doc = doc.replace /// \n #{indent} ///g, '\n' if indent
doc = doc.replace /^\n/, '' unless herecomment
doc
# 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.
@@ -480,145 +463,149 @@ exports.Lexer = class Lexer
closeIndentation: ->
@outdentToken @indent
# 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.
balancedString: (str, end) ->
continueCount = 0
stack = [end]
for i in [1...str.length]
if continueCount
--continueCount
continue
switch letter = str.charAt i
when '\\'
++continueCount
continue
when end
stack.pop()
unless stack.length
return str[0..i]
end = stack[stack.length - 1]
continue
if end is '}' and letter in ['"', "'"]
stack.push end = letter
else if end is '}' and letter is '/' and match = (HEREGEX.exec(str[i..]) or REGEX.exec(str[i..]))
continueCount += match[0].length - 1
else if end is '}' and letter is '{'
stack.push end = '}'
else if end is '"' and prev is '#' and letter is '{'
stack.push end = '}'
prev = letter
@error "missing #{ stack.pop() }, starting"
# Expand variables and expressions inside double-quoted strings using
# Ruby-like notation for substitution of arbitrary expressions.
# Match the contents of a delimited token and expand variables and expressions
# inside it using Ruby-like notation for substitution of arbitrary
# expressions.
#
# "Hello #{name.capitalize()}."
#
# If it encounters an interpolation, this method will recursively create a
# new Lexer, tokenize the interpolated contents, and merge them into the
# token stream.
# If it encounters an interpolation, this method will recursively create a new
# Lexer and tokenize until the `{` of `#{` is balanced with a `}`.
#
# - `str` is the start of the string contents (IE with the " or """ stripped
# off.)
# - `options.offsetInChunk` is the start of the interpolated string in the
# current chunk, including the " or """, etc... If not provided, this is
# assumed to be 0. `options.lexedLength` is the length of the
# interpolated string, including both the start and end quotes. Both of these
# values are ignored if `options.regex` is true.
# - `options.strOffset` is the offset of str, relative to the start of the
# current chunk.
interpolateString: (str, options = {}) ->
{heredoc, regex, offsetInChunk, strOffset, lexedLength} = options
offsetInChunk ||= 0
strOffset ||= 0
lexedLength ||= str.length
# Parse the string.
# - `regex` matches the contents of a token (but not `delimiter`, and not
# `#{` if interpolations are desired).
# - `delimiter` is the delimiter of the token. Examples are `'`, `"`, `'''`,
# `"""` and `///`.
#
# This method allows us to have strings within interpolations within strings,
# ad infinitum.
matchWithInterpolations: (regex, delimiter) ->
tokens = []
pi = 0
i = -1
while letter = str.charAt i += 1
if letter is '\\'
i += 1
continue
unless letter is '#' and str.charAt(i+1) is '{' and
(expr = @balancedString str[i + 1..], '}')
continue
# NEOSTRING is a fake token. This will be converted to a string below.
tokens.push @makeToken('NEOSTRING', str[pi...i], strOffset + pi) if pi < i
unless errorToken
errorToken = @makeToken '', 'string interpolation', offsetInChunk + i + 1, 2
inner = expr[1...-1]
if inner.length
[line, column] = @getLineAndColumnFromChunk(strOffset + i + 2)
nested = new Lexer().tokenize inner, line: line, column: column, rewrite: off
popped = nested.pop()
popped = nested.shift() if nested[0]?[0] is 'TERMINATOR'
if len = nested.length
if len > 1
nested.unshift @makeToken '(', '(', strOffset + i + 1, 0
nested.push @makeToken ')', ')', strOffset + i + 1 + inner.length, 0
# Push a fake 'TOKENS' token, which will get turned into real tokens below.
tokens.push ['TOKENS', nested]
i += expr.length
pi = i + 1
tokens.push @makeToken('NEOSTRING', str[pi..], strOffset + pi) if i > pi < str.length
offsetInChunk = delimiter.length
return null unless @chunk[...offsetInChunk] is delimiter
str = @chunk[offsetInChunk..]
loop
[strPart] = regex.exec str
# If regex, then return now and let the regex code deal with all these fake tokens
return tokens if regex
@validateEscapes strPart, {isRegex: delimiter.charAt(0) is '/', offsetInChunk}
# If we didn't find any tokens, then just return an empty string.
return @token 'STRING', '""', offsetInChunk, lexedLength unless tokens.length
# Push a fake 'NEOSTRING' token, which will get turned into a real string later.
tokens.push @makeToken 'NEOSTRING', strPart, offsetInChunk
# If the first token is not a string, add a fake empty string to the beginning.
tokens.unshift @makeToken('NEOSTRING', '', offsetInChunk) unless tokens[0][0] is 'NEOSTRING'
str = str[strPart.length..]
offsetInChunk += strPart.length
if interpolated = tokens.length > 1
@token '(', '(', offsetInChunk, 0, errorToken
break unless str[...2] is '#{'
# Push all the tokens
# The `1`s are to remove the `#` in `#{`.
[line, column] = @getLineAndColumnFromChunk offsetInChunk + 1
{tokens: nested, index} =
new Lexer().tokenize str[1..], line: line, column: column, untilBalanced: on
# Skip the trailing `}`.
index += 1
# Turn the leading and trailing `{` and `}` into parentheses. Unnecessary
# parentheses will be removed later.
[open, ..., close] = nested
open[0] = open[1] = '('
close[0] = close[1] = ')'
close.origin = ['', 'end of interpolation', close[2]]
# Remove leading 'TERMINATOR' (if any).
nested.splice 1, 1 if nested[1]?[0] is 'TERMINATOR'
# Push a fake 'TOKENS' token, which will get turned into real tokens later.
tokens.push ['TOKENS', nested]
str = str[index..]
offsetInChunk += index
unless str[...delimiter.length] is delimiter
@error "missing #{delimiter}", length: delimiter.length
[firstToken, ..., lastToken] = tokens
firstToken[2].first_column -= delimiter.length
lastToken[2].last_column += delimiter.length
lastToken[2].last_column -= 1 if lastToken[1].length is 0
{tokens, index: offsetInChunk + delimiter.length}
# Merge the array `tokens` of the fake token types 'TOKENS' and 'NEOSTRING'
# (as returned by `matchWithInterpolations`) into the token stream. The value
# of 'NEOSTRING's are converted using `fn` and turned into strings using
# `options` first.
mergeInterpolationTokens: (tokens, options, fn) ->
if tokens.length > 1
lparen = @token 'STRING_START', '(', 0, 0
firstIndex = @tokens.length
for token, i in tokens
[tag, value] = token
if i
switch tag
when 'TOKENS'
# Optimize out empty interpolations (an empty pair of parentheses).
continue if value.length is 2
# Push all the tokens in the fake 'TOKENS' token. These already have
# sane location data.
locationToken = value[0]
tokensToPush = value
when 'NEOSTRING'
# Convert 'NEOSTRING' into 'STRING'.
converted = fn token[1], i
# Optimize out empty strings. We ensure that the tokens stream always
# starts with a string token, though, to make sure that the result
# really is a string.
if converted.length is 0
if i is 0
firstEmptyStringIndex = @tokens.length
else
continue
# However, there is one case where we can optimize away a starting
# empty string.
if i is 2 and firstEmptyStringIndex?
@tokens.splice firstEmptyStringIndex, 2 # Remove empty string and the plus.
token[0] = 'STRING'
token[1] = @makeDelimitedLiteral converted, options
locationToken = token
tokensToPush = [token]
if @tokens.length > firstIndex
# Create a 0-length "+" token.
plusToken = @token '+', '+' if i
locationToken = if tag == 'TOKENS' then value[0] else token
plusToken = @token '+', '+'
plusToken[2] =
first_line: locationToken[2].first_line
first_line: locationToken[2].first_line
first_column: locationToken[2].first_column
last_line: locationToken[2].first_line
last_column: locationToken[2].first_column
if tag is 'TOKENS'
# Push all the tokens in the fake 'TOKENS' token. These already have
# sane location data.
@tokens.push value...
else if tag is 'NEOSTRING'
# Convert NEOSTRING into STRING
token[0] = 'STRING'
token[1] = @makeString value, '"', heredoc
@tokens.push token
else
@error "Unexpected #{tag}"
if interpolated
rparen = @makeToken ')', ')', offsetInChunk + lexedLength, 0
rparen.stringEnd = true
@tokens.push rparen
tokens
last_line: locationToken[2].first_line
last_column: locationToken[2].first_column
@tokens.push tokensToPush...
if lparen
[..., lastToken] = tokens
lparen.origin = ['STRING', null,
first_line: lparen[2].first_line
first_column: lparen[2].first_column
last_line: lastToken[2].last_line
last_column: lastToken[2].last_column
]
rparen = @token 'STRING_END', ')'
rparen[2] =
first_line: lastToken[2].last_line
first_column: lastToken[2].last_column
last_line: lastToken[2].last_line
last_column: lastToken[2].last_column
# Pairs up a closing token, ensuring that all listed pairs of tokens are
# correctly balanced throughout the course of the token stream.
pair: (tag) ->
unless tag is wanted = last @ends
[..., prev] = @ends
unless tag is wanted = prev?.tag
@error "unmatched #{tag}" unless 'OUTDENT' is wanted
# Auto-close INDENT to support syntax like this:
#
# el.click((event) ->
# el.hide())
#
@outdentToken last(@indents), true
[..., lastIndent] = @indents
@outdentToken lastIndent, true
return @pair tag
@ends.pop()
@@ -641,8 +628,8 @@ exports.Lexer = class Lexer
column = @chunkColumn
if lineCount > 0
lines = string.split '\n'
column = last(lines).length
[..., lastLine] = string.split '\n'
column = lastLine.length
else
column += string.length
@@ -677,50 +664,76 @@ exports.Lexer = class Lexer
@tokens.push token
token
# Peek at a tag in the current token stream.
tag: (index, tag) ->
(tok = last @tokens, index) and if tag then tok[0] = tag else tok[0]
# Peek at the last tag in the token stream.
tag: ->
[..., token] = @tokens
token?[0]
# Peek at a value in the current token stream.
value: (index, val) ->
(tok = last @tokens, index) and if val then tok[1] = val else tok[1]
# Peek at the last value in the token stream.
value: ->
[..., token] = @tokens
token?[1]
# Are we in the midst of an unfinished expression?
unfinished: ->
LINE_CONTINUER.test(@chunk) or
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-',
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', 'UNARY_MATH', '+', '-', 'YIELD',
'**', 'SHIFT', 'RELATION', 'COMPARE', 'LOGIC', 'THROW', 'EXTENDS']
# Remove newlines from beginning and (non escaped) from end of string literals.
removeNewlines: (str) ->
str.replace(/^\s*\n\s*/, '')
.replace(/([^\\]|\\\\)\s*\n\s*$/, '$1')
formatString: (str) ->
str.replace STRING_OMIT, '$1'
# Converts newlines for string literals.
escapeLines: (str, heredoc) ->
# Ignore escaped backslashes and remove escaped newlines
str = str.replace /\\[^\S\n]*(\n|\\)\s*/g, (escaped, character) ->
if character is '\n' then '' else escaped
if heredoc
str.replace MULTILINER, '\\n'
else
str.replace /\s*\n\s*/g, ' '
formatHeregex: (str) ->
str.replace HEREGEX_OMIT, '$1$2'
# Constructs a string token by escaping quotes and newlines.
makeString: (body, quote, heredoc) ->
return quote + quote unless body
# Ignore escaped backslashes and unescape quotes
body = body.replace /// \\( #{quote} | \\ ) ///g, (match, contents) ->
if contents is quote then contents else match
body = body.replace /// #{quote} ///g, '\\$&'
quote + @escapeLines(body, heredoc) + quote
# Validates escapes in strings and regexes.
validateEscapes: (str, options = {}) ->
match = INVALID_ESCAPE.exec str
return unless match
[[], before, octal, hex, unicode] = match
return if options.isRegex and octal and octal.charAt(0) isnt '0'
message =
if octal
"octal escape sequences are not allowed"
else
"invalid escape sequence"
invalidEscape = "\\#{octal or hex or unicode}"
@error "#{message} #{invalidEscape}",
offset: (options.offsetInChunk ? 0) + match.index + before.length
length: invalidEscape.length
# Throws a compiler error on the current position.
error: (message, offset = 0) ->
# TODO: Are there some cases we could improve the error line number by
# passing the offset in the chunk where the error happened?
[first_line, first_column] = @getLineAndColumnFromChunk offset
throwSyntaxError message, {first_line, first_column}
# Constructs a string or regex by escaping certain characters.
makeDelimitedLiteral: (body, options = {}) ->
body = '(?:)' if body is '' and options.delimiter is '/'
regex = ///
(\\\\) # escaped backslash
| (\\0(?=[1-7])) # nul character mistaken as octal escape
| \\?(#{options.delimiter}) # (possibly escaped) delimiter
| \\?(?: (\n)|(\r)|(\u2028)|(\u2029) ) # (possibly escaped) newlines
| (\\.) # other escapes
///g
body = body.replace regex, (match, backslash, nul, delimiter, lf, cr, ls, ps, other) -> switch
# Ignore escaped backslashes.
when backslash then (if options.double then backslash + backslash else backslash)
when nul then '\\x00'
when delimiter then "\\#{delimiter}"
when lf then '\\n'
when cr then '\\r'
when ls then '\\u2028'
when ps then '\\u2029'
when other then (if options.double then "\\#{other}" else other)
"#{options.delimiter}#{body}#{options.delimiter}"
# Throws an error at either a given offset from the current chunk or at the
# location of a token (`token[2]`).
error: (message, options = {}) ->
location =
if 'first_line' of options
options
else
[first_line, first_column] = @getLineAndColumnFromChunk options.offset ? 0
{first_line, first_column, last_column: first_column + (options.length ? 1) - 1}
throwSyntaxError message, location
# Constants
# ---------
@@ -729,7 +742,7 @@ exports.Lexer = class Lexer
JS_KEYWORDS = [
'true', 'false', 'null', 'this'
'new', 'delete', 'typeof', 'in', 'instanceof'
'return', 'throw', 'break', 'continue', 'debugger'
'return', 'throw', 'break', 'continue', 'debugger', 'yield'
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
'class', 'extends', 'super'
]
@@ -756,12 +769,11 @@ COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat COFFEE_ALIASES
# to avoid having a JavaScript error at runtime.
RESERVED = [
'case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum'
'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind'
'__indexOf', 'implements', 'interface', 'package', 'private', 'protected'
'public', 'static', 'yield'
'export', 'import', 'native', 'implements', 'interface', 'package', 'private'
'protected', 'public', 'static'
]
STRICT_PROSCRIBED = ['arguments', 'eval']
STRICT_PROSCRIBED = ['arguments', 'eval', 'yield*']
# The superset of both JavaScript keywords and reserved words, none of which may
# be used as identifiers or properties.
@@ -775,7 +787,8 @@ BOM = 65279
# Token matching regexes.
IDENTIFIER = /// ^
( [$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]* )
(?!\d)
( (?: (?!\s)[$\w\x7f-\uffff] )+ )
( [^\n\S]* : (?!:) )? # Is this a property name?
///
@@ -786,8 +799,6 @@ NUMBER = ///
^ \d*\.?\d+ (?:e[+-]?\d+)? # decimal
///i
HEREDOC = /// ^ ("""|''') ((?: \\[\s\S] | [^\\] )*?) (?:\n[^\n\S]*)? \1 ///
OPERATOR = /// ^ (
?: [-=]> # function
| [-+*/%<>&|^!?=]= # compound assign / compare
@@ -806,43 +817,67 @@ CODE = /^[-=]>/
MULTI_DENT = /^(?:\n[^\n\S]*)+/
SIMPLESTR = /^'[^\\']*(?:\\[\s\S][^\\']*)*'/
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/
# String-matching-regexes.
STRING_START = /^(?:'''|"""|'|")/
STRING_SINGLE = /// ^(?: [^\\'] | \\[\s\S] )* ///
STRING_DOUBLE = /// ^(?: [^\\"#] | \\[\s\S] | \#(?!\{) )* ///
HEREDOC_SINGLE = /// ^(?: [^\\'] | \\[\s\S] | '(?!'') )* ///
HEREDOC_DOUBLE = /// ^(?: [^\\"#] | \\[\s\S] | "(?!"") | \#(?!\{) )* ///
STRING_OMIT = ///
((?:\\\\)+) # consume (and preserve) an even number of backslashes
| \\[^\S\n]*\n\s* # remove escaped newlines
///g
SIMPLE_STRING_OMIT = /\s*\n\s*/g
HEREDOC_INDENT = /\n+([^\n\S]*)(?=\S)/g
# Regex-matching-regexes.
REGEX = /// ^
(/ (?! [\s=] ) # disallow leading whitespace or equals signs
[^ [ / \n \\ ]* # every other thing
(?:
(?: \\[\s\S] # anything escaped
| \[ # character class
[^ \] \n \\ ]*
(?: \\[\s\S] [^ \] \n \\ ]* )*
]
) [^ [ / \n \\ ]*
)*
/) ([imgy]{0,4}) (?!\w)
/ (?!/) ((
?: [^ [ / \n \\ ] # every other thing
| \\[^\n] # anything but newlines escaped
| \[ # character class
(?: \\[^\n] | [^ \] \n \\ ] )*
]
)*) (/)?
///
HEREGEX = /// ^ /{3} ((?:\\?[\s\S])+?) /{3} ([imgy]{0,4}) (?!\w) ///
REGEX_FLAGS = /^\w*/
VALID_FLAGS = /^(?!.*(.).*\1)[imgy]*$/
HEREGEX = /// ^(?: [^\\/#] | \\[\s\S] | /(?!//) | \#(?!\{) )* ///
HEREGEX_OMIT = ///
((?:\\\\)+) # consume (and preserve) an even number of backslashes
| \\(\s|/) # preserve escaped whitespace and "de-escape" slashes
| \\(\s) # preserve escaped whitespace
| \s+(?:#.*)? # remove whitespace and comments
///g
# Token cleaning regexes.
MULTILINER = /\n/g
REGEX_ILLEGAL = /// ^ ( / | /{3}\s*) (\*) ///
HEREDOC_INDENT = /\n+([^\n\S]*)/g
POSSIBLY_DIVISION = /// ^ /=?\s ///
HEREDOC_ILLEGAL = /\*\//
# Other regexes.
HERECOMMENT_ILLEGAL = /\*\//
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) ///
TRAILING_SPACES = /\s+$/
INVALID_ESCAPE = ///
( (?:^|[^\\]) (?:\\\\)* ) # make sure the escape isnt escaped
\\ (
?: (0[0-7]|[1-7]) # octal escape
| (x(?![\da-fA-F]{2}).{0,2}) # hex escape
| (u(?![\da-fA-F]{4}).{0,4}) # unicode escape
)
///
LEADING_BLANK_LINE = /^[^\n\S]*\n/
TRAILING_BLANK_LINE = /\n[^\n\S]*$/
TRAILING_SPACES = /\s+$/
# Compound assignment tokens.
COMPOUND_ASSIGN = [
@@ -873,23 +908,20 @@ RELATION = ['IN', 'OF', 'INSTANCEOF']
# Boolean tokens.
BOOL = ['TRUE', 'FALSE']
# 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', 'BOOL', 'NULL', 'UNDEFINED', '++', '--']
# If the previous token is not spaced, there are more preceding tokens that
# force a division parse:
NOT_SPACED_REGEX = NOT_REGEX.concat ')', '}', 'THIS', 'IDENTIFIER', 'STRING', ']'
# Tokens which could legitimately be invoked or indexed. An opening
# parentheses or bracket following these tokens will be recorded as the start
# of a function invocation or indexing operation.
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER']
INDEXABLE = CALLABLE.concat 'NUMBER', 'BOOL', 'NULL', 'UNDEFINED'
CALLABLE = ['IDENTIFIER', ')', ']', '?', '@', 'THIS', 'SUPER']
INDEXABLE = CALLABLE.concat [
'NUMBER', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END'
'BOOL', 'NULL', 'UNDEFINED', '}', '::'
]
# Tokens which a regular expression will never immediately follow (except spaced
# CALLABLEs in some cases), but which a division operator can.
#
# See: http://www-archive.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
NOT_REGEX = INDEXABLE.concat ['++', '--']
# Tokens that, when immediately preceding a `WHEN`, indicate that the `WHEN`
# occurs at the start of a line. We disambiguate these from trailing whens to

View File

@@ -9,7 +9,7 @@ Error.stackTraceLimit = Infinity
{RESERVED, STRICT_PROSCRIBED} = require './lexer'
# Import the helpers we plan to use.
{compact, flatten, extend, merge, del, starts, ends, last, some,
{compact, flatten, extend, merge, del, starts, ends, some,
addLocationDataFn, locationDataToString, throwSyntaxError} = require './helpers'
# Functions required by parser
@@ -89,7 +89,11 @@ exports.Base = class Base
else
meth = 'call'
func = new Value func, [new Access new Literal meth]
(new Call func, args).compileNode o
parts = (new Call func, args).compileNode o
if func.isGenerator
parts.unshift @makeCode "(yield* "
parts.push @makeCode ")"
parts
# If the code generation wishes to use the result of a complex expression
# in multiple places, ensure that the expression is only ever evaluated once,
@@ -98,14 +102,15 @@ exports.Base = class Base
# If `level` is passed, then returns `[val, ref]`, where `val` is the compiled value, and `ref`
# is the compiled reference. If `level` is not passed, this returns `[val, ref]` where
# the two values are raw nodes which have not been compiled.
cache: (o, level, reused) ->
unless @isComplex()
ref = if level then @compileToFragments o, level else this
[ref, ref]
else
ref = new Literal reused or o.scope.freeVariable 'ref'
cache: (o, level, isComplex) ->
complex = if isComplex? then isComplex this else @isComplex()
if complex
ref = new Literal o.scope.freeVariable 'ref'
sub = new Assign ref, this
if level then [sub.compileToFragments(o, level), [@makeCode(ref.value)]] else [sub, ref]
else
ref = if level then @compileToFragments o, level else this
[ref, ref]
cacheToCodeFragments: (cacheValues) ->
[fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]
@@ -316,7 +321,7 @@ exports.Block = class Block extends Base
o.indent = if o.bare then '' else TAB
o.level = LEVEL_TOP
@spaced = yes
o.scope = new Scope null, this, null
o.scope = new Scope null, this, null, o.referencedVars ? []
# Mark given local variables in the root scope as parameters so they don't
# end up being declared on this block.
o.scope.parameter name for name in o.locals or []
@@ -448,14 +453,15 @@ exports.Return = class Return extends Base
compileNode: (o) ->
answer = []
exprIsYieldReturn = @expression?.isYieldReturn?()
# TODO: If we call expression.compile() here twice, we'll sometimes get back different results!
answer.push @makeCode @tab + "return#{if @expression then " " else ""}"
unless exprIsYieldReturn
answer.push @makeCode @tab + "return#{if @expression then " " else ""}"
if @expression
answer = answer.concat @expression.compileToFragments o, LEVEL_PAREN
answer.push @makeCode ";"
answer.push @makeCode ";" unless exprIsYieldReturn
return answer
#### Value
# A value, variable or literal or parenthesized, indexed or dotted into,
@@ -506,10 +512,11 @@ exports.Value = class Value extends Base
(@base instanceof Obj) and (not onlyGenerated or @base.generated)
isSplice: ->
last(@properties) instanceof Slice
[..., lastProp] = @properties
lastProp instanceof Slice
looksStatic: (className) ->
@base.value is className and @properties.length and
@base.value is className and @properties.length is 1 and
@properties[0].name?.value isnt 'prototype'
# The value can be unwrapped as its inner node, if there are no attached
@@ -521,7 +528,7 @@ exports.Value = class Value extends Base
# We cache them separately for compiling complex expressions.
# `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c`
cacheReference: (o) ->
name = last @properties
[..., name] = @properties
if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
return [this, this] # `a` `a.b`
base = new Value @base, @properties[...-1]
@@ -577,7 +584,7 @@ exports.Comment = class Comment extends Base
makeReturn: THIS
compileNode: (o, level) ->
comment = @comment.replace /^(\s*)#/gm, "$1 *"
comment = @comment.replace /^(\s*)# /gm, "$1 * "
code = "/*#{multident comment, @tab}#{if '\n' in comment then "\n#{@tab}" else ''} */"
code = o.indent + code if (level or o.level) is LEVEL_TOP
[@makeCode("\n"), @makeCode(code)]
@@ -610,10 +617,21 @@ exports.Call = class Call extends Base
superReference: (o) ->
method = o.scope.namedMethod()
if method?.klass
accesses = [new Access(new Literal '__super__')]
{klass, name, variable} = method
if klass.isComplex()
bref = new Literal o.scope.parent.freeVariable 'base'
base = new Value new Parens new Assign bref, klass
variable.base = base
variable.properties.splice 0, klass.properties.length
if name.isComplex() or (name instanceof Index and name.index.isAssignable())
nref = new Literal o.scope.parent.freeVariable 'name'
name = new Index new Assign nref, name.index
variable.properties.pop()
variable.properties.push name
accesses = [new Access new Literal '__super__']
accesses.push new Access new Literal 'constructor' if method.static
accesses.push new Access new Literal method.name
(new Value (new Literal method.klass), accesses).compile o
accesses.push if nref? then new Index nref else name
(new Value bref ? klass, accesses).compile o
else if method?.ctor
"#{method.name}.__super__.constructor"
else
@@ -733,7 +751,7 @@ exports.Extends = class Extends extends Base
# Hooks one constructor into another's prototype chain.
compileToFragments: (o) ->
new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compileToFragments o
new Call(new Value(new Literal utility 'extend', o), [@child, @parent]).compileToFragments o
#### Access
@@ -790,9 +808,10 @@ exports.Range = class Range extends Base
# But only if they need to be cached to avoid double evaluation.
compileVariables: (o) ->
o = merge o, top: true
[@fromC, @fromVar] = @cacheToCodeFragments @from.cache o, LEVEL_LIST
[@toC, @toVar] = @cacheToCodeFragments @to.cache o, LEVEL_LIST
[@step, @stepVar] = @cacheToCodeFragments step.cache o, LEVEL_LIST if step = del o, 'step'
isComplex = del o, 'isComplex'
[@fromC, @fromVar] = @cacheToCodeFragments @from.cache o, LEVEL_LIST, isComplex
[@toC, @toVar] = @cacheToCodeFragments @to.cache o, LEVEL_LIST, isComplex
[@step, @stepVar] = @cacheToCodeFragments step.cache o, LEVEL_LIST, isComplex if step = del o, 'step'
[@fromNum, @toNum] = [@fromVar.match(NUMBER), @toVar.match(NUMBER)]
@stepNum = @stepVar.match(NUMBER) if @stepVar
@@ -850,7 +869,7 @@ exports.Range = class Range extends Base
range.pop() if @exclusive
return [@makeCode "[#{ range.join(', ') }]"]
idt = @tab + TAB
i = o.scope.freeVariable 'i'
i = o.scope.freeVariable 'i', single: true
result = o.scope.freeVariable 'results'
pre = "\n#{idt}#{result} = [];"
if @fromNum and @toNum
@@ -908,35 +927,54 @@ exports.Obj = class Obj extends Base
compileNode: (o) ->
props = @properties
return [@makeCode(if @front then '({})' else '{}')] unless props.length
if @generated
for node in props when node instanceof Value
node.error 'cannot have an implicit value in an implicit object'
break for prop, dynamicIndex in props when (prop.variable or prop).base instanceof Parens
hasDynamic = dynamicIndex < props.length
idt = o.indent += TAB
lastNoncom = @lastNonComment @properties
answer = []
if hasDynamic
oref = o.scope.freeVariable 'obj'
answer.push @makeCode "(\n#{idt}#{oref} = "
answer.push @makeCode "{#{if props.length is 0 or dynamicIndex is 0 then '}' else '\n'}"
for prop, i in props
join = if i is props.length - 1
if i is dynamicIndex
answer.push @makeCode "\n#{idt}}" unless i is 0
answer.push @makeCode ',\n'
join = if i is props.length - 1 or i is dynamicIndex - 1
''
else if prop is lastNoncom or prop instanceof Comment
'\n'
else
',\n'
indent = if prop instanceof Comment then '' else idt
indent += TAB if hasDynamic and i < dynamicIndex
if prop instanceof Assign and prop.variable instanceof Value and prop.variable.hasProperties()
prop.variable.error 'Invalid object key'
if prop instanceof Value and prop.this
prop = new Assign prop.properties[0].name, prop, 'object'
if prop not instanceof Comment
if prop not instanceof Assign
prop = new Assign prop, prop, 'object'
(prop.variable.base or prop.variable).asKey = yes
if i < dynamicIndex
if prop not instanceof Assign
prop = new Assign prop, prop, 'object'
(prop.variable.base or prop.variable).asKey = yes
else
if prop instanceof Assign
key = prop.variable
value = prop.value
else
[key, value] = prop.base.cache o
prop = new Assign (new Value (new Literal oref), [new Access key]), value
if indent then answer.push @makeCode indent
answer.push prop.compileToFragments(o, LEVEL_TOP)...
if join then answer.push @makeCode join
answer.unshift @makeCode "{#{ props.length and '\n' }"
answer.push @makeCode "#{ props.length and '\n' + @tab }}"
if @front then @wrapInBraces answer else answer
if hasDynamic
answer.push @makeCode ",\n#{idt}#{oref}\n#{@tab})"
else
answer.push @makeCode "\n#{@tab}}" unless props.length is 0
if @front and not hasDynamic then @wrapInBraces answer else answer
assigns: (name) ->
for prop in @properties when prop.assigns name then return yes
@@ -990,7 +1028,8 @@ exports.Class = class Class extends Base
# Figure out the appropriate name for the constructor function of this class.
determineName: ->
return null unless @variable
decl = if tail = last @variable.properties
[..., tail] = @variable.properties
decl = if tail
tail instanceof Access and tail.name.value
else
@variable.base.value
@@ -1006,7 +1045,6 @@ exports.Class = class Class extends Base
if node instanceof Literal and node.value is 'this'
node.value = name
else if node instanceof Code
node.klass = name
node.context = name if node.bound
# Ensure that all functions bound to the instance are proxied in the
@@ -1014,7 +1052,7 @@ exports.Class = class Class extends Base
addBoundFunctions: (o) ->
for bvar in @boundFuncs
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind', o}(#{lhs}, this)"
return
# Merge the properties from a top-level object as prototypal properties
@@ -1040,7 +1078,8 @@ exports.Class = class Class extends Base
if assign.variable.this
func.static = yes
else
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base])
acc = if base.isComplex() then new Index base else new Access base
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), acc])
if func instanceof Code and func.bound
@boundFuncs.push base
func.bound = no
@@ -1113,7 +1152,7 @@ exports.Class = class Class extends Base
@body.expressions.push lname
if @parent
superClass = new Literal o.classScope.freeVariable 'super', no
superClass = new Literal o.classScope.freeVariable 'superClass', reserve: no
@body.expressions.unshift new Extends lname, superClass
func.params.push new Param superClass
args.push @parent
@@ -1157,21 +1196,28 @@ exports.Assign = class Assign extends Base
return @compileSplice o if @variable.isSplice()
return @compileConditional o if @context in ['||=', '&&=', '?=']
return @compileSpecialMath o if @context in ['**=', '//=', '%%=']
compiledName = @variable.compileToFragments o, LEVEL_LIST
name = fragmentsToText compiledName
if @value instanceof Code
if @value.static
@value.klass = @variable.base
@value.name = @variable.properties[0]
@value.variable = @variable
else if @variable.properties?.length >= 2
[properties..., prototype, name] = @variable.properties
if prototype.name?.value is 'prototype'
@value.klass = new Value @variable.base, properties
@value.name = name
@value.variable = @variable
unless @context
varBase = @variable.unwrapAll()
unless varBase.isAssignable()
@variable.error "\"#{@variable.compile o}\" cannot be assigned"
unless varBase.hasProperties?()
if @param
o.scope.add name, 'var'
o.scope.add varBase.value, 'var'
else
o.scope.find name
if @value instanceof Code and match = METHOD_DEF.exec name
@value.klass = match[1] if match[2]
@value.name = match[3] ? match[4] ? match[5]
o.scope.find varBase.value
val = @value.compileToFragments o, LEVEL_LIST
compiledName = @variable.compileToFragments o, LEVEL_LIST
return (compiledName.concat @makeCode(": "), val) if @context is 'object'
answer = compiledName.concat @makeCode(" #{ @context or '=' } "), val
if o.level <= LEVEL_LIST then answer else @wrapInBraces answer
@@ -1228,9 +1274,9 @@ exports.Assign = class Assign extends Base
if not expandedIdx and obj instanceof Splat
name = obj.name.unwrap().value
obj = obj.unwrap()
val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice' }.call(#{vvarText}, #{i}"
val = "#{olen} <= #{vvarText}.length ? #{ utility 'slice', o }.call(#{vvarText}, #{i}"
if rest = olen - i - 1
ivar = o.scope.freeVariable 'i'
ivar = o.scope.freeVariable 'i', single: true
val += ", #{ivar} = #{vvarText}.length - #{rest}) : (#{ivar} = #{i}, [])"
else
val += ") : []"
@@ -1241,7 +1287,7 @@ exports.Assign = class Assign extends Base
if rest is 1
expandedIdx = "#{vvarText}.length - 1"
else
ivar = o.scope.freeVariable 'i'
ivar = o.scope.freeVariable 'i', single: true
val = new Literal "#{ivar} = #{vvarText}.length - #{rest}"
expandedIdx = "#{ivar}++"
assigns.push val.compileToFragments o, LEVEL_LIST
@@ -1315,9 +1361,11 @@ exports.Assign = class Assign extends Base
# has no *children* -- they're within the inner scope.
exports.Code = class Code extends Base
constructor: (params, body, tag) ->
@params = params or []
@body = body or new Block
@bound = tag is 'boundfunc'
@params = params or []
@body = body or new Block
@bound = tag is 'boundfunc'
@isGenerator = !!@body.contains (node) ->
node instanceof Op and node.operator in ['yield', 'yield*']
children: ['params', 'body']
@@ -1355,9 +1403,8 @@ exports.Code = class Code extends Base
for param in @params when param not instanceof Expansion
o.scope.parameter param.asReference o
for param in @params when param.splat or param instanceof Expansion
for {name: p} in @params when param not instanceof Expansion
if p.this then p = p.properties[0].name
if p.value then o.scope.add p.value, 'var', yes
for p in @params when p not instanceof Expansion and p.name.value
o.scope.add p.name.value, 'var', yes
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
new Value new Literal 'arguments'
break
@@ -1381,12 +1428,13 @@ exports.Code = class Code extends Base
o.scope.parameter fragmentsToText params[i]
uniqs = []
@eachParamName (name, node) ->
node.error "multiple parameters named '#{name}'" if name in uniqs
node.error "multiple parameters named #{name}" if name in uniqs
uniqs.push name
@body.makeReturn() unless wasEmpty or @noReturn
code = 'function'
code += ' ' + @name if @ctor
code += '('
code = 'function'
code += '*' if @isGenerator
code += ' ' + @name if @ctor
code += '('
answer = [@makeCode(code)]
for p, i in params
if i then answer.push @makeCode ", "
@@ -1425,9 +1473,9 @@ exports.Param = class Param extends Base
return @reference if @reference
node = @name
if node.this
node = node.properties[0].name
if node.value.reserved
node = new Literal o.scope.freeVariable node.value
name = node.properties[0].name.value
name = "_#{name}" if name.reserved
node = new Literal o.scope.freeVariable name
else if node.isComplex()
node = new Literal o.scope.freeVariable 'arg'
node = new Value node
@@ -1445,9 +1493,7 @@ exports.Param = class Param extends Base
# `name` is the name of the parameter and `node` is the AST node corresponding
# to that name.
eachName: (iterator, name = @name)->
atParam = (obj) ->
node = obj.properties[0].name
iterator node.value, node unless node.value.reserved
atParam = (obj) -> iterator "@#{obj.properties[0].name.value}", obj
# * simple literals `foo`
return iterator name.value, name if name instanceof Literal
# * at-params `@foo`
@@ -1504,12 +1550,12 @@ exports.Splat = class Splat extends Base
node = list[0]
fragments = node.compileToFragments o, LEVEL_LIST
return fragments if apply
return [].concat node.makeCode("#{ utility 'slice' }.call("), fragments, node.makeCode(")")
return [].concat node.makeCode("#{ utility 'slice', o }.call("), fragments, node.makeCode(")")
args = list[index..]
for node, i in args
compiledNode = node.compileToFragments o, LEVEL_LIST
args[i] = if node instanceof Splat
then [].concat node.makeCode("#{ utility 'slice' }.call("), compiledNode, node.makeCode(")")
then [].concat node.makeCode("#{ utility 'slice', o }.call("), compiledNode, node.makeCode(")")
else [].concat node.makeCode("["), compiledNode, node.makeCode("]")
if index is 0
node = list[0]
@@ -1518,7 +1564,8 @@ exports.Splat = class Splat extends Base
base = (node.compileToFragments o, LEVEL_LIST for node in list[...index])
base = list[0].joinFragmentArrays base, ', '
concatPart = list[index].joinFragmentArrays args, ', '
[].concat list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, (last list).makeCode(")")
[..., last] = list
[].concat list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, last.makeCode(")")
#### Expansion
@@ -1612,9 +1659,10 @@ exports.Op = class Op extends Base
# The map of conversions from CoffeeScript to JavaScript symbols.
CONVERSIONS =
'==': '==='
'!=': '!=='
'of': 'in'
'==': '==='
'!=': '!=='
'of': 'in'
'yieldfrom': 'yield*'
# The map of invertible operators.
INVERSIONS =
@@ -1625,11 +1673,18 @@ exports.Op = class Op extends Base
isSimpleNumber: NO
isYield: ->
@operator in ['yield', 'yield*']
isYieldReturn: ->
@isYield() and @first instanceof Return
isUnary: ->
not @second
isComplex: ->
not (@isUnary() and @operator in ['+', '-']) or @first.isComplex()
not (@isUnary() and @operator in ['+', '-'] and
@first instanceof Value and @first.isSimpleNumber())
# Am I capable of
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
@@ -1691,6 +1746,7 @@ exports.Op = class Op extends Base
@error 'delete operand may not be argument or var'
if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED
@error "cannot increment/decrement \"#{@first.unwrapAll().value}\""
return @compileYield o if @isYield()
return @compileUnary o if @isUnary()
return @compileChain o if isChain
switch @operator
@@ -1745,6 +1801,22 @@ exports.Op = class Op extends Base
parts.reverse() if @flip
@joinFragmentArrays parts, ''
compileYield: (o) ->
parts = []
op = @operator
if not o.scope.parent?
@error 'yield statements must occur within a function generator.'
if 'expression' in Object.keys(@first) and not (@first instanceof Throw)
if @isYieldReturn()
parts.push @first.compileToFragments o, LEVEL_TOP
else if @first.expression?
parts.push @first.expression.compileToFragments o, LEVEL_OP
else
parts.push [@makeCode "(#{op} "]
parts.push @first.compileToFragments o, LEVEL_OP
parts.push [@makeCode ")"]
@joinFragmentArrays parts, ''
compilePower: (o) ->
# Make a Math.pow call
pow = new Value new Literal('Math'), [new Access new Literal 'pow']
@@ -1756,7 +1828,7 @@ exports.Op = class Op extends Base
new Call(floor, [div]).compileToFragments o
compileModulo: (o) ->
mod = new Value new Literal utility 'modulo'
mod = new Value new Literal utility 'modulo', o
new Call(mod, [@first, @second]).compileToFragments o
toString: (idt) ->
@@ -1790,7 +1862,7 @@ exports.In = class In extends Base
compileLoopTest: (o) ->
[sub, ref] = @object.cache o, LEVEL_LIST
fragments = [].concat @makeCode(utility('indexOf') + ".call("), @array.compileToFragments(o, LEVEL_LIST),
fragments = [].concat @makeCode(utility('indexOf', o) + ".call("), @array.compileToFragments(o, LEVEL_LIST),
@makeCode(", "), ref, @makeCode(") " + if @negated then '< 0' else '>= 0')
return fragments if fragmentsToText(sub) is fragmentsToText(ref)
fragments = sub.concat @makeCode(', '), fragments
@@ -1935,29 +2007,30 @@ exports.For = class For extends While
# comprehensions. Some of the generated code can be shared in common, and
# some cannot.
compileNode: (o) ->
body = Block.wrap [@body]
lastJumps = last(body.expressions)?.jumps()
@returns = no if lastJumps and lastJumps instanceof Return
source = if @range then @source.base else @source
scope = o.scope
name = @name and (@name.compile o, LEVEL_LIST) if not @pattern
index = @index and (@index.compile o, LEVEL_LIST)
body = Block.wrap [@body]
[..., last] = body.expressions
@returns = no if last?.jumps() instanceof Return
source = if @range then @source.base else @source
scope = o.scope
name = @name and (@name.compile o, LEVEL_LIST) if not @pattern
index = @index and (@index.compile o, LEVEL_LIST)
scope.find(name) if name and not @pattern
scope.find(index) if index
rvar = scope.freeVariable 'results' if @returns
ivar = (@object and index) or scope.freeVariable 'i'
kvar = (@range and name) or index or ivar
kvarAssign = if kvar isnt ivar then "#{kvar} = " else ""
rvar = scope.freeVariable 'results' if @returns
ivar = (@object and index) or scope.freeVariable 'i', single: true
kvar = (@range and name) or index or ivar
kvarAssign = if kvar isnt ivar then "#{kvar} = " else ""
if @step and not @range
[step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST
[step, stepVar] = @cacheToCodeFragments @step.cache o, LEVEL_LIST, isComplexOrAssignable
stepNum = stepVar.match NUMBER
name = ivar if @pattern
varPart = ''
guardPart = ''
defPart = ''
idt1 = @tab + TAB
name = ivar if @pattern
varPart = ''
guardPart = ''
defPart = ''
idt1 = @tab + TAB
if @range
forPartFragments = source.compileToFragments merge(o, {index: ivar, name, @step})
forPartFragments = source.compileToFragments merge o,
{index: ivar, name, @step, isComplex: isComplexOrAssignable}
else
svar = @source.compile o, LEVEL_LIST
if (name or @own) and not IDENTIFIER.test svar
@@ -1999,7 +2072,7 @@ exports.For = class For extends While
varPart = "\n#{idt1}#{namePart};" if namePart
if @object
forPartFragments = [@makeCode("#{kvar} in #{svar}")]
guardPart = "\n#{idt1}if (!#{utility 'hasProp'}.call(#{svar}, #{kvar})) continue;" if @own
guardPart = "\n#{idt1}if (!#{utility 'hasProp', o}.call(#{svar}, #{kvar})) continue;" if @own
bodyFragments = body.compileToFragments merge(o, indent: idt1), LEVEL_TOP
if bodyFragments and (bodyFragments.length > 0)
bodyFragments = [].concat @makeCode("\n"), bodyFragments, @makeCode("\n")
@@ -2158,10 +2231,10 @@ UTILITIES =
# Correctly set up a prototype chain for inheritance, including a reference
# to the superclass for `super()` calls, and copies of any static properties.
extends: -> "
extend: (o) -> "
function(child, parent) {
for (var key in parent) {
if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key];
if (#{utility 'hasProp', o}.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
@@ -2212,8 +2285,7 @@ LEVEL_ACCESS = 6 # ...[0]
# Tabs are two spaces for pretty printing.
TAB = ' '
IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"
IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ ///
IDENTIFIER = /// ^ (?!\d) [$\w\x7f-\uffff]+ $ ///
SIMPLENUM = /^[+-]?\d+$/
HEXNUM = /^[+-]?0x[\da-f]+/i
NUMBER = ///^[+-]?(?:
@@ -2221,15 +2293,6 @@ NUMBER = ///^[+-]?(?:
\d*\.?\d+ (?:e[+-]?\d+)? # decimal
)$///i
METHOD_DEF = /// ^
(#{IDENTIFIER_STR})
(\.prototype)?
(?: \.(#{IDENTIFIER_STR})
| \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\]
| \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\]
)
$ ///
# Is a literal value a string/regex?
IS_STRING = /^['"]/
IS_REGEX = /^\//
@@ -2238,10 +2301,14 @@ IS_REGEX = /^\//
# ----------------
# Helper for ensuring that utility functions are assigned at the top level.
utility = (name) ->
ref = "__#{name}"
Scope.root.assign ref, UTILITIES[name]()
ref
utility = (name, o) ->
{root} = o.scope
if name of root.utilities
root.utilities[name]
else
ref = root.freeVariable name
root.assign ref, UTILITIES[name] o
root.utilities[name] = ref
multident = (code, tab) ->
code = code.replace /\n/g, '$&' + tab
@@ -2265,6 +2332,8 @@ isLiteralThis = (node) ->
(node instanceof Code and node.bound) or
(node instanceof Call and node.isSuper)
isComplexOrAssignable = (node) -> node.isComplex() or node.isAssignable?()
# Unfold a node's child if soak, then tuck the node under created `If`
unfoldSoak = (o, parent, name) ->
return unless ifn = parent[name].unfoldSoak o

Some files were not shown because too many files have changed in this diff Show More