- Show the same type of error message for compound assignment as for `=`
assignment when the LHS is invalid.
- Show the same type of error message when trying to assign to a CoffeeScript
keyword as when trying to assign to a JavaScript keyword.
- Now longer treat `&& =` as `&&=`. The same goes for `and=`, `||=` and `or=`.
- Unify the error message to: `<optional type> '<value>' can't be assigned`.
Previously, the parser created `Literal` nodes for many things. This resulted in
information loss. Instead of being able to check the node type, we had to use
regexes to tell the different types of `Literal`s apart. That was a bit like
parsing literals twice: Once in the lexer, and once (or more) in the compiler.
It also caused problems, such as `` `this` `` and `this` being indistinguishable
(fixes#2009).
Instead returning `new Literal` in the grammar, subtypes of it are now returned
instead, such as `NumberLiteral`, `StringLiteral` and `IdentifierLiteral`. `new
Literal` by itself is only used to represent code chunks that fit no category.
(While mentioning `NumberLiteral`, there's also `InfinityLiteral` now, which is
a subtype of `NumberLiteral`.)
`StringWithInterpolations` has been added as a subtype of `Parens`, and
`RegexWithInterpolations` as a subtype of `Call`. This makes it easier for other
programs to make use of CoffeeScript's "AST" (nodes). For example, it is now
possible to distinguish between `"a #{b} c"` and `"a " + b + " c"`. Fixes#4192.
`SuperCall` has been added as a subtype of `Call`.
Note, though, that some information is still lost, especially in the lexer. For
example, there is no way to distinguish a heredoc from a regular string, or a
heregex without interpolations from a regular regex. Binary and octal number
literals are indistinguishable from hexadecimal literals.
After the new subtypes were added, they were taken advantage of, removing most
regexes in nodes.coffee. `SIMPLENUM` (which matches non-hex integers) had to be
kept, though, because such numbers need special handling in JavaScript (for
example in `1..toString()`).
An especially nice hack to get rid of was using `new String()` for the token
value for reserved identifiers (to be able to set a property on them which could
survive through the parser). Now it's a good old regular string.
In range literals, slices, splices and for loop steps when number literals
are involved, CoffeeScript can do some optimizations, such as precomputing the
value of, say, `5 - 3` (outputting `2` instead of `5 - 3` literally). As a side
bonus, this now also works with hexadecimal number literals, such as `0x02`.
Finally, this also improves the output of `coffee --nodes`:
# Before:
$ bin/coffee -ne 'while true
"#{a}"
break'
Block
While
Value
Bool
Block
Value
Parens
Block
Op +
Value """"
Value
Parens
Block
Value "a" "break"
# After:
$ bin/coffee -ne 'while true
"#{a}"
break'
Block
While
Value BooleanLiteral: true
Block
Value
StringWithInterpolations
Block
Op +
Value StringLiteral: ""
Value
Parens
Block
Value IdentifierLiteral: a
StatementLiteral: break
Commit 347a6255 is a bit problematic:
- It doesn't include the built .js files.
- It breaks `CoffeeScript.register()`. This can be seen by running the tests;
four of them fails. The error is that `CoffeeScript.register()` calls
`CoffeeScript._compileFile()` with the `sourceMap` option enabled, which
returns an object while the code expected a string.
This commit fixes the broken `CoffeeScript.register()`, by setting the
`sourceMap` option to `false` (but still keeping the `inlineMap` option enabled,
which was the intention of commit 347a6255). It also commits the built .js
files. The tests now pass.
`({a = 1}) ->` and `({a: b}) ->` worked, but not the combination of the two:
`({a: b = 1}) ->`. That destrucuring worked for normal assignments, though:
`{a: b = 1} = c`. This commit fixes the param case.
This breaks compatibility with
->
yield for i in [1..3]
i * 2
and
->
yield
i * 2
yield's behaviour now mirrors that of return in that it can be used stand alone as well as with expressions. Thus, it currently also inherits the above limitations.
This let's you do things like:
fullName = ({first = 'John', last = 'Doe'}) -> "#{first} #{last}"
Note: CoffeeScrits treats `undefined` and `null` the same, and that's true in
the case of destructuring defaults as well, as opposed to ES2015 which only uses
the default value if the target is `undefined`. A similar ES2015 difference
already exists for function parameter defaults. It is important for CoffeeScript
to be consistent with itself.
fullName2 = (first = 'John', last = 'Doe') -> "#{first} #{last}"
assert fullName('Bob', null) is fullName2(first: 'Bob', last: null)
Fixes#1558, #3288 and #4005.
Let me know if there's something I should be doing differently as this is my first contribution to coffeescript.
I fixed the reported issue where a generated variable could clash with a user-defined one in a try/catch block.
I added a test for a few scenarios with different variable names for a try/catch, to confirm the fix and avoid regressions.
Testing with `'[object Array]' is Object::toString.call element` allows arrays from another JS context to be properly handled. The specific use case here is to support jest, which sets up JS contexts using Node/io.js's "vm" module. This approach works in ES3 environments in contrast with ES5's `Array.isArray`.
If you passed an array of tokens (as opposed to a string of code) to
`CoffeeScript.nodes`, its attempts to prettify error messages would break. Now
it does not attempt to prettify error messages in that case anymore (because it
is not possible to prettify the errors without a string of code).
The repl was affected by the above bug.
Fixes#3887.