diff --git a/documentation/docs/grammar.html b/documentation/docs/grammar.html index 5d79eea5..5728ab41 100644 --- a/documentation/docs/grammar.html +++ b/documentation/docs/grammar.html @@ -96,6 +96,7 @@ through and printed to JavaScript.
AssignObj: [
o "Identifier ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
o "AlphaNumeric ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
+ o "ThisProperty ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'this'
o "Comment"
]
A return statement from a function body.
Return: [
o "RETURN Expression", -> new ReturnNode $2
@@ -125,14 +126,12 @@ that hoovers up the remaining arguments.
A splat that occurs outside of a parameter list.
Splat: [
o "Expression . . .", -> new SplatNode $1
- ]
-
Variables and properties that can be assigned to.
SimpleAssignable: [
+ ]
Variables and properties that can be assigned to.
SimpleAssignable: [
o "Identifier", -> new ValueNode $1
o "Value Accessor", -> $1.push $2
o "Invocation Accessor", -> new ValueNode $1, [$2]
o "ThisProperty"
- ]
-
Everything that can be assigned to.
Assignable: [
+ ]
Everything that can be assigned to.
Assignable: [
o "SimpleAssignable"
o "Array", -> new ValueNode $1
o "Object", -> new ValueNode $1
@@ -198,8 +197,7 @@ object.
A reference to the this current object.
This: [
o "THIS", -> new ValueNode new LiteralNode 'this'
o "@", -> new ValueNode new LiteralNode 'this'
- ]
-
A reference to a property on this.
ThisProperty: [
+ ]
A reference to a property on this.
ThisProperty: [
o "@ Identifier", -> new ValueNode new LiteralNode('this'), [new AccessorNode($2)]
]
The CoffeeScript range literal.
Range: [
o "[ Expression . . Expression ]", -> new RangeNode $2, $5
diff --git a/documentation/docs/lexer.html b/documentation/docs/lexer.html
index 47b1c3f6..c839798d 100644
--- a/documentation/docs/lexer.html
+++ b/documentation/docs/lexer.html
@@ -310,7 +310,7 @@ match if successful, and false
otherwise.
Are we in the midst of an unfinished expression?
unfinished: ->
prev: @prev(2)
@value() and @value().match and @value().match(NO_NEWLINE) and
- prev and (prev[0] isnt '.') and not @value().match(CODE)
There are no exensions to the core lexer by default.
Lexer.extensions: []
Keywords that CoffeeScript shares in common with JavaScript.
JS_KEYWORDS: [
+ prev and (prev[0] isnt '.') and not @value().match(CODE)
There are no exensions to the core lexer by default.
@extensions: []
Keywords that CoffeeScript shares in common with JavaScript.
JS_KEYWORDS: [
"if", "else",
"true", "false",
"new", "return",
@@ -320,21 +320,20 @@ match if successful, and false
otherwise.
CoffeeScript-only keywords, which we're more relaxed about allowing. They can't +]
CoffeeScript-only keywords, which we're more relaxed about allowing. They can't be used standalone, but you can reference them as an attached property.
COFFEE_ALIASES: ["and", "or", "is", "isnt", "not"]
COFFEE_KEYWORDS: COFFEE_ALIASES.concat [
"then", "unless",
"yes", "no", "on", "off",
"of", "by", "where", "when"
-]
The combined list of keywords is the superset that gets passed verbatim to -the parser.
KEYWORDS: JS_KEYWORDS.concat COFFEE_KEYWORDS
The list of keywords that are reserved by JavaScript, but not used, or are +]
The combined list of keywords is the superset that gets passed verbatim to +the parser.
KEYWORDS: JS_KEYWORDS.concat COFFEE_KEYWORDS
The list of keywords that are reserved by JavaScript, but not used, or are used by CoffeeScript internally. We throw an error when these are encountered, to avoid having a JavaScript error at runtime.
RESERVED: [
"case", "default", "do", "function", "var", "void", "with"
- "const", "let", "debugger", "enum", "export", "import", "native",
- "__extends", "__hasProp"
-]
The superset of both JavaScript keywords and reserved words, none of which may -be used as identifiers or properties.
JS_FORBIDDEN: JS_KEYWORDS.concat RESERVED
Token matching regexes.
IDENTIFIER : /^([a-zA-Z\$_](\w|\$)*)/
+ "const", "let", "debugger", "enum", "export", "import", "native"
+]
The superset of both JavaScript keywords and reserved words, none of which may +be used as identifiers or properties.
JS_FORBIDDEN: JS_KEYWORDS.concat RESERVED
Token matching regexes.
IDENTIFIER : /^([a-zA-Z\$_](\w|\$)*)/
NUMBER : /^(\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?)))\b/i
HEREDOC : /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/
INTERPOLATION : /^\$([a-zA-Z_@]\w*(\.\w+)*)/
@@ -345,27 +344,27 @@ be used as identifiers or properties.
Regex-matching-regexes.
REGEX_START : /^\/[^\/ ]/
+ASSIGNMENT : /^(:|=)$/
Regex-matching-regexes.
REGEX_START : /^\/[^\/ ]/
REGEX_INTERPOLATION: /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/
REGEX_FLAGS : /^[imgy]{0,4}/
-REGEX_ESCAPE : /\\[^\$]/g
Token cleaning regexes.
JS_CLEANER : /(^`|`$)/g
+REGEX_ESCAPE : /\\[^\$]/g
Token cleaning regexes.
JS_CLEANER : /(^`|`$)/g
MULTILINER : /\n/g
STRING_NEWLINES : /\n[ \t]*/g
COMMENT_CLEANER : /(^[ \t]*#|\n[ \t]*$)/mg
NO_NEWLINE : /^([+\*&|\/\-%=<>:!.\\][<>=&|]*|and|or|is|isnt|not|delete|typeof|instanceof)$/
-HEREDOC_INDENT : /^[ \t]+/mg
Tokens which a regular expression will never immediately follow, but which +HEREDOC_INDENT : /^[ \t]+/mg
Tokens which a regular expression will never immediately follow, but which a division operator might.
See: http://www.mozilla.org/js/language/js20-2002-04/rationale/syntax.html#regular-expressions
Our list is shorter, due to sans-parentheses method calls.
NOT_REGEX: [
'NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE'
-]
Tokens which could legitimately be invoked or indexed. A opening +]
Tokens which could legitimately be invoked or indexed. A opening parentheses or bracket following these tokens will be recorded as the start -of a function invocation or indexing operation.
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@']
Tokens that indicate an access -- keywords immediately following will be -treated as identifiers.
ACCESSORS: ['PROPERTY_ACCESS', 'PROTOTYPE_ACCESS', 'SOAK_ACCESS', '@']
Tokens that, when immediately preceding a WHEN
, indicate that the WHEN
+of a function invocation or indexing operation.
CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@']
Tokens that indicate an access -- keywords immediately following will be +treated as identifiers.
ACCESSORS: ['PROPERTY_ACCESS', 'PROTOTYPE_ACCESS', 'SOAK_ACCESS', '@']
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
-avoid an ambiguity in the grammar.
LINE_BREAK: ['INDENT', 'OUTDENT', 'TERMINATOR']
Half-assignments...
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?']
Conversions from CoffeeScript operators into JavaScript ones.
CONVERSIONS: {
+avoid an ambiguity in the grammar.
LINE_BREAK: ['INDENT', 'OUTDENT', 'TERMINATOR']
Half-assignments...
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?']
Conversions from CoffeeScript operators into JavaScript ones.
CONVERSIONS: {
'and': '&&'
'or': '||'
'is': '=='
diff --git a/documentation/docs/nodes.html b/documentation/docs/nodes.html
index 4d5cecca..a71e2295 100644
--- a/documentation/docs/nodes.html
+++ b/documentation/docs/nodes.html
@@ -262,8 +262,6 @@ returning the bound function. After ECMAScript 5, Prototype.js, and
Underscore's bind
functions.
exports.CurryNode: class CurryNode extends CallNode
type: 'Curry'
- body: 'func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)))'
-
constructor: (meth, args) ->
@children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])]
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
@@ -274,30 +272,17 @@ Underscore's bind
functions.
Node to extend an object's prototype with an ancestor object. + utility 'slice' + ref: new ValueNode literal utility 'bind' + (new CallNode(ref, [@meth, @context, literal(@arguments(o))])).compile o
Node to extend an object's prototype with an ancestor object.
After goog.inherits
from the
Closure Library.
exports.ExtendsNode: class ExtendsNode extends BaseNode
type: 'Extends'
- code: '''
- function(child, parent) {
- var ctor = function(){ };
- ctor.prototype = parent.prototype;
- child.__superClass__ = parent.prototype;
- child.prototype = new ctor();
- child.prototype.constructor = child;
- }
- '''
-
constructor: (child, parent) ->
@children: [@child: child, @parent: parent]
Hooks one constructor into another's prototype chain.
compile_node: (o) ->
- o.scope.assign('__extends', @code, true)
- ref: new ValueNode literal('__extends')
- call: new CallNode ref, [@child, @parent]
- call.compile(o)
A .
accessor into a property of a value, or the ::
shorthand for
+ ref: new ValueNode literal utility 'extends'
+ (new CallNode ref, [@child, @parent]).compile o
A .
accessor into a property of a value, or the ::
shorthand for
an accessor into the object's prototype.
exports.AccessorNode: class AccessorNode extends BaseNode
type: 'Accessor'
@@ -392,7 +377,7 @@ commas affixed to comments.
for obj, i in @objects
code: obj.compile(o)
if obj instanceof SplatNode
- return @compile_splat_literal(@objects, o)
+ return @compile_splat_literal @objects, o
else if obj instanceof CommentNode
objects.push "\n$code\n$o.indent"
else if i is @objects.length - 1
@@ -418,14 +403,16 @@ constructor, property assignments, and inheritance getting built out below.
o.top: true
for prop in @properties
- if prop.variable and prop.variable.base.value is 'constructor'
+ pvar: prop.variable
+ if pvar and pvar.base.value is 'constructor'
func: prop.value
func.body.push(new ReturnNode(literal('this')))
constructor: new AssignNode(@variable, func)
else
- if prop.variable
- val: new ValueNode(@variable, [new AccessorNode(prop.variable, 'prototype')])
- prop: new AssignNode(val, prop.value)
+ if pvar
+ access: if prop.context is 'this' then pvar.base.properties[0] else new AccessorNode(pvar, 'prototype')
+ val: new ValueNode(@variable, [access])
+ prop: new AssignNode(val, prop.value)
props.push prop
if not constructor
@@ -508,7 +495,7 @@ for details.
Compile the assignment from an array splice literal, using JavaScript's
Array#splice
method.
compile_splice: (o) ->
- name: @variable.compile(merge(o, {only_first: true}))
+ name: @variable.compile merge o, {only_first: true}
l: @variable.properties.length
range: @variable.properties[l - 1].range
plus: if range.exclusive then '' else ' + 1'
@@ -557,8 +544,9 @@ a closure.
When traversing (for printing or inspecting), return the real children of @@ -587,28 +575,28 @@ the splat in the parameter list, by slicing the arguments object.
for trailing in @trailings o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]") i: + 1 - "$name = Array.prototype.slice.call(arguments, $@index, arguments.length - ${@trailings.length})"A compiling a splat as a destructuring assignment means slicing arguments + "$name = ${utility('slice')}.call(arguments, $@index, arguments.length - ${@trailings.length})"
A compiling a splat as a destructuring assignment means slicing arguments from the right-hand-side's corresponding array.
compile_value: (o, name, index, trailings) ->
- if trailings? then "Array.prototype.slice.call($name, $index, ${name}.length - $trailings)" \
- else "Array.prototype.slice.call($name, $index)"
Utility function that converts arbitrary number of elements, mixed with -splats, to a proper array
SplatNode.compile_mixed_array: (list, o) ->
- args: []
- i: 0
- for arg in list
- code: arg.compile o
- if not (arg instanceof SplatNode)
- prev: args[i - 1]
- if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']'
- args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]"
- continue
- else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])'
- args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])"
- continue
- else
- code: "[$code]"
- args.push(if i is 0 then code else ".concat($code)")
- i: + 1
- args.join('')
A while loop, the only sort of low-level loop exposed by CoffeeScript. From + trail: if trailings then ", ${name}.length - $trailings" else '' + "${utility 'slice'}.call($name, $index$trail)"
Utility function that converts arbitrary number of elements, mixed with +splats, to a proper array
@compile_mixed_array: (list, o) ->
+ args: []
+ i: 0
+ for arg in list
+ code: arg.compile o
+ if not (arg instanceof SplatNode)
+ prev: args[i - 1]
+ if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']'
+ args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]"
+ continue
+ else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])'
+ args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])"
+ continue
+ else
+ code: "[$code]"
+ args.push(if i is 0 then code else ".concat($code)")
+ i: + 1
+ args.join('')
A while loop, the only sort of low-level loop exposed by CoffeeScript. From it, all other loops can be manufactured. Useful in cases where you need more flexibility or more speed than a comprehension can provide.
exports.WhileNode: class WhileNode extends BaseNode
type: 'While'
@@ -738,12 +726,12 @@ table.
The meat of the ExistenceNode is in this static compile_test
method
because other nodes like to check the existence of their variables as well.
-Be careful not to double-evaluate anything.
ExistenceNode.compile_test: (o, variable) ->
- [first, second]: [variable, variable]
- if variable instanceof CallNode or (variable instanceof ValueNode and variable.has_properties())
- [first, second]: variable.compile_reference(o)
- [first, second]: [first.compile(o), second.compile(o)]
- "(typeof $first !== \"undefined\" && $second !== null)"
An extra set of parentheses, specified explicitly in the source. At one time +Be careful not to double-evaluate anything.
@compile_test: (o, variable) ->
+ [first, second]: [variable, variable]
+ if variable instanceof CallNode or (variable instanceof ValueNode and variable.has_properties())
+ [first, second]: variable.compile_reference(o)
+ [first, second]: [first.compile(o), second.compile(o)]
+ "(typeof $first !== \"undefined\" && $second !== null)"
An extra set of parentheses, specified explicitly in the source. At one time we tried to clean up the results by detecting and removing redundant parentheses, but no longer -- you can put in as many as you please.
@@ -833,8 +821,7 @@ some cannot.Tabs are two spaces for pretty printing.
TAB: ' '
Trim out all trailing whitespace, so that the generated code plays nice -with Git.
TRAILING_WHITESPACE: /\s+$/gm
Keep this identifier regex in sync with the Lexer.
IDENTIFIER: /^[a-zA-Z\$_](\w|\$)*$/
Handy helper for a generating LiteralNode.
literal: (name) ->
- new LiteralNode(name)
+}
UTILITIES: {
Correctly set up a prototype chain for inheritance, including a reference
+to the superclass for super()
calls. See:
+goog.inherits
__extends: """
+ function(child, parent) {
+ var ctor = function(){ };
+ ctor.prototype = parent.prototype;
+ child.__superClass__ = parent.prototype;
+ child.prototype = new ctor();
+ child.prototype.constructor = child;
+ }
+ """
Bind a function to a calling context, optionally including curried arguments. +See Underscore's implementation
__bind: """
+ function(func, obj, args) {
+ return function() {
+ return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
+ };
+ }
+ """
+
+ __hasProp:'Object.prototype.hasOwnProperty'
+
+ __slice: 'Array.prototype.slice'
+
+}
Tabs are two spaces for pretty printing.
TAB: ' '
Trim out all trailing whitespace, so that the generated code plays nice +with Git.
TRAILING_WHITESPACE: /\s+$/gm
Keep this identifier regex in sync with the Lexer.
IDENTIFIER: /^[a-zA-Z\$_](\w|\$)*$/
Handy helper for a generating LiteralNode.
literal: (name) ->
+ new LiteralNode(name)
Helper for ensuring that utility functions are assigned at the top level.
utility: (name) ->
+ ref: "__$name"
+ Scope.root.assign ref, UTILITIES[ref]
+ ref