From 0af132d0c65e2ffa9b1b65d2478bd5c6f36e35dc Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas
Assignment of a variable, property, or index to a value.
Assign: [
- o "Value ASSIGN Expression", -> new AssignNode $1, $3
+ o "Assignable ASSIGN Expression", -> new AssignNode $1, $3
]
Assignment when it happens within an object literal. The difference from the ordinary Assign is that these allow numbers and strings as keys.
AssignObj: [
o "Identifier ASSIGN Expression", -> new AssignNode new ValueNode($1), $3, 'object'
@@ -125,18 +125,26 @@ that hoovers up the remaining arguments.
A splat that occurs outside of a parameter list.
Splat: [
o "Expression . . .", -> new SplatNode $1
- ]
The types of things that can be treated as values -- assigned to, invoked -as functions, indexed into, named as a class, etc.
Value: [
+ ]
+
Variables and properties that can be assigned to.
SimpleAssignable: [
o "Identifier", -> new ValueNode $1
- o "Literal", -> 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: [
+ o "SimpleAssignable"
o "Array", -> new ValueNode $1
o "Object", -> new ValueNode $1
+ ]
The types of things that can be treated as values -- assigned to, invoked +as functions, indexed into, named as a class, etc.
Value: [
+ o "Assignable"
+ o "Literal", -> new ValueNode $1
o "Parenthetical", -> new ValueNode $1
o "Range", -> new ValueNode $1
o "This"
- o "Value Accessor", -> $1.push $2
- o "Invocation Accessor", -> new ValueNode $1, [$2]
- ]
The general group of accessors into an object, by property, by prototype + o "NULL", -> new ValueNode new LiteralNode 'null' + ]
The general group of accessors into an object, by property, by prototype or by array index or slice.
Accessor: [
o "PROPERTY_ACCESS Identifier", -> new AccessorNode $2
o "PROTOTYPE_ACCESS Identifier", -> new AccessorNode $2, 'prototype'
@@ -144,58 +152,65 @@ or by array index or slice.
Indexing into an object or array using bracket notation.
Index: [
+ ]
Indexing into an object or array using bracket notation.
Index: [
o "INDEX_START Expression INDEX_END", -> new IndexNode $2
o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode $2, 'soak'
- ]
In CoffeeScript, an object literal is simply a list of assignments.
Object: [
+ ]
In CoffeeScript, an object literal is simply a list of assignments.
Object: [
o "{ AssignList }", -> new ObjectNode $2
o "{ IndentedAssignList }", -> new ObjectNode $2
- ]
Class definitions have optional bodies of prototype property assignments, + o "{ AssignList , }", -> new ObjectNode $2 + o "{ IndentedAssignList , }", -> new ObjectNode $2 + ]
Class definitions have optional bodies of prototype property assignments, and optional references to the superclass.
Class: [
- o "CLASS Value", -> new ClassNode $2
- o "CLASS Value EXTENDS Value", -> new ClassNode $2, $4
- o "CLASS Value IndentedAssignList", -> new ClassNode $2, null, $3
- o "CLASS Value EXTENDS Value IndentedAssignList", -> new ClassNode $2, $4, $5
- ]
Assignment of properties within an object literal can be separated by + o "CLASS SimpleAssignable", -> new ClassNode $2 + o "CLASS SimpleAssignable EXTENDS Value", -> new ClassNode $2, $4 + o "CLASS SimpleAssignable IndentedAssignList", -> new ClassNode $2, null, $3 + o "CLASS SimpleAssignable EXTENDS Value IndentedAssignList", -> new ClassNode $2, $4, $5 + ]
Assignment of properties within an object literal can be separated by comma, as in JavaScript, or simply by newline.
AssignList: [
o "", -> []
o "AssignObj", -> [$1]
o "AssignList , AssignObj", -> $1.concat [$3]
o "AssignList TERMINATOR AssignObj", -> $1.concat [$3]
o "AssignList , TERMINATOR AssignObj", -> $1.concat [$4]
- ]
An AssignList within a block indentation.
IndentedAssignList: [
+ ]
An AssignList within a block indentation.
IndentedAssignList: [
o "INDENT AssignList OUTDENT", -> $2
- ]
The three flavors of function call: normal, object instantiation with new
,
+ o "INDENT AssignList , OUTDENT", -> $2
+ ]
The three flavors of function call: normal, object instantiation with new
,
and calling super()
Call: [
o "Invocation"
o "NEW Invocation", -> $2.new_instance()
o "Super"
- ]
-
- Curry: [
+ ]
Binds a function call to a context and/or arguments.
Curry: [
o "Value <- Arguments", -> new CurryNode $1, $3
- ]
Extending an object by setting its prototype chain to reference a parent + ]
Extending an object by setting its prototype chain to reference a parent object.
Extends: [
- o "Value EXTENDS Value", -> new ExtendsNode $1, $3
- ]
Ordinary function invocation, or a chained series of calls.
Invocation: [
+ o "SimpleAssignable EXTENDS Value", -> new ExtendsNode $1, $3
+ ]
Ordinary function invocation, or a chained series of calls.
Invocation: [
o "Value Arguments", -> new CallNode $1, $2
o "Invocation Arguments", -> new CallNode $1, $2
- ]
The list of arguments to a function call.
Arguments: [
+ ]
The list of arguments to a function call.
Arguments: [
o "CALL_START ArgList CALL_END", -> $2
- ]
Calling super.
Super: [
+ o "CALL_START ArgList , CALL_END", -> $2
+ ]
Calling super.
Super: [
o "SUPER CALL_START ArgList CALL_END", -> new CallNode 'super', $3
- ]
A reference to the this current object, either naked or to a property.
This: [
+ o "SUPER CALL_START ArgList , CALL_END", -> new CallNode 'super', $3
+ ]
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: [
o "@ Identifier", -> new ValueNode new LiteralNode('this'), [new AccessorNode($2)]
- ]
The CoffeeScript range literal.
Range: [
+ ]
The CoffeeScript range literal.
Range: [
o "[ Expression . . Expression ]", -> new RangeNode $2, $5
o "[ Expression . . . Expression ]", -> new RangeNode $2, $6, true
- ]
The slice literal.
Slice: [
+ ]
The slice literal.
Slice: [
o "INDEX_START Expression . . Expression INDEX_END", -> new RangeNode $2, $5
o "INDEX_START Expression . . . Expression INDEX_END", -> new RangeNode $2, $6, true
- ]
The array literal.
Array: [
+ ]
The array literal.
Array: [
o "[ ArgList ]", -> new ArrayNode $2
- ]
The ArgList is both the list of objects passed into a function call, + o "[ ArgList , ]", -> new ArrayNode $2 + ]
The ArgList is both the list of objects passed into a function call, as well as the contents of an array literal (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o "", -> []
@@ -206,80 +221,84 @@ as well as the contents of an array literal
o "ArgList , TERMINATOR Expression", -> $1.concat [$4]
o "ArgList , INDENT Expression", -> $1.concat [$4]
o "ArgList OUTDENT"
- ]
Just simple, comma-separated, required arguments (no fancy syntax). We need + o "ArgList , OUTDENT" + ]
Just simple, comma-separated, required arguments (no fancy syntax). We need this to be separate from the ArgList for use in Switch blocks, where having the newlines wouldn't make sense.
SimpleArgs: [
o "Expression"
o "SimpleArgs , Expression", ->
if $1 instanceof Array then $1.concat([$3]) else [$1].concat([$3])
- ]
The variants of try/catch/finally exception handling blocks.
Try: [
+ ]
The variants of try/catch/finally exception handling blocks.
Try: [
o "TRY Block Catch", -> new TryNode $2, $3[0], $3[1]
o "TRY Block FINALLY Block", -> new TryNode $2, null, null, $4
o "TRY Block Catch FINALLY Block", -> new TryNode $2, $3[0], $3[1], $5
- ]
A catch clause names its error and runs a block of code.
Catch: [
+ ]
A catch clause names its error and runs a block of code.
Catch: [
o "CATCH Identifier Block", -> [$2, $3]
- ]
Throw an exception object.
Throw: [
+ ]
Throw an exception object.
Throw: [
o "THROW Expression", -> new ThrowNode $2
- ]
Parenthetical expressions. Note that the Parenthetical is a Value, + ]
Parenthetical expressions. Note that the Parenthetical is a Value, not an Expression, so if you need to use an expression in a place where only values are accepted, wrapping it in parentheses will always do the trick.
Parenthetical: [
o "( Expression )", -> new ParentheticalNode $2
- ]
A language extension to CoffeeScript from the outside. We simply pass + ]
A language extension to CoffeeScript from the outside. We simply pass it through unaltered.
Extension: [
o "EXTENSION", -> yytext
- ]
The condition portion of a while loop.
WhileSource: [
+ ]
The condition portion of a while loop.
WhileSource: [
o "WHILE Expression", -> new WhileNode $2
o "WHILE Expression WHEN Expression", -> new WhileNode $2, {filter : $4}
- ]
The while loop can either be normal, with a block of expressions to execute, + ]
The while loop can either be normal, with a block of expressions to execute, or postfix, with a single expression. There is no do..while.
While: [
o "WhileSource Block", -> $1.add_body $2
o "Expression WhileSource", -> $2.add_body Expressions.wrap [$1]
- ]
Array, object, and range comprehensions, at the most generic level. + ]
Array, object, and range comprehensions, at the most generic level. Comprehensions can either be normal, with a block of expressions to execute, or postfix, with a single expression.
For: [
o "Expression FOR ForVariables ForSource", -> new ForNode $1, $4, $3[0], $3[1]
o "FOR ForVariables ForSource Block", -> new ForNode $4, $3, $2[0], $2[1]
- ]
An array or range comprehension has variables for the current element and + ]
An array or range comprehension has variables for the current element and (optional) reference to the current index. Or, key, value, in the case of object comprehensions.
ForVariables: [
o "Identifier", -> [$1]
o "Identifier , Identifier", -> [$1, $3]
- ]
The source of a comprehension is an array or object with an optional filter -clause. If it's an array comprehension, you can also choose to step throug + ]
The source of a comprehension is an array or object with an optional filter +clause. If it's an array comprehension, you can also choose to step through in fixed-size increments.
ForSource: [
- o "IN Expression", -> {source: $2}
- o "OF Expression", -> {source: $2, object: true}
- o "ForSource WHEN Expression", -> $1.filter: $3; $1
- o "ForSource BY Expression", -> $1.step: $3; $1
- ]
The CoffeeScript switch/when/else block replaces the JavaScript + o "IN Expression", -> {source: $2} + o "OF Expression", -> {source: $2, object: true} + o "IN Expression WHEN Expression", -> {source: $2, filter: $4} + o "OF Expression WHEN Expression", -> {source: $2, filter: $4, object: true} + o "IN Expression BY Expression", -> {source: $2, step: $4} + o "IN Expression WHEN Expression BY Expression", -> {source: $2, filter: $4; step: $6} + o "IN Expression BY Expression WHEN Expression", -> {source: $2, step: $4, filter: $6} + ]
The CoffeeScript switch/when/else block replaces the JavaScript switch/case/default by compiling into an if-else chain.
Switch: [
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition $2
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else $6, true
- ]
The inner list of whens is left recursive. At code-generation time, the + ]
The inner list of whens is left recursive. At code-generation time, the IfNode will rewrite them into a proper chain.
Whens: [
o "When"
o "Whens When", -> $1.push $2
- ]
An individual When clause, with action.
When: [
+ ]
An individual When clause, with action.
When: [
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, null, {statement: true}
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, null, {statement: true}
o "Comment TERMINATOR When", -> $3.comment: $1; $3
- ]
The most basic form of if is a condition and an action. The following + ]
The most basic form of if is a condition and an action. The following if-related rules are broken up along these lines in order to avoid ambiguity.
IfStart: [
o "IF Expression Block", -> new IfNode $2, $3
o "IfStart ElsIf", -> $1.add_else $2
- ]
An IfStart can optionally be followed by an else block.
IfBlock: [
+ ]
An IfStart can optionally be followed by an else block.
IfBlock: [
o "IfStart"
o "IfStart ELSE Block", -> $1.add_else $3
- ]
An else if continuation of the if expression.
ElsIf: [
+ ]
An else if continuation of the if expression.
ElsIf: [
o "ELSE IF Expression Block", -> (new IfNode($3, $4)).force_statement()
- ]
The full complement of if expressions, including postfix one-liner + ]
The full complement of if expressions, including postfix one-liner if and unless.
If: [
o "IfBlock"
o "Expression IF Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true}
o "Expression UNLESS Expression", -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true, invert: true}
- ]
Arithmetic and logical operators, working on one or more operands. + ]
Arithmetic and logical operators, working on one or more operands. Here they are grouped by order of precedence. The actual precedence rules are defined at the bottom of the page. It would be shorter if we could combine most of these rules into a single generic Operand OpSymbol Operand @@ -336,7 +355,7 @@ rules are necessary.
Operators at the top of this list have higher precedence than the ones lower +}
Operators at the top of this list have higher precedence than the ones lower
down. Following these rules is what makes 2 + 3 * 4
parse as:
2 + (3 * 4)
@@ -365,7 +384,7 @@ down. Following these rules is what makes 2 + 3 * 4
parse as:
["left", 'EXTENDS']
["right", 'ASSIGN', 'RETURN']
["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']
-]
Finally, now what we have our grammar and our operators, we can create +]
Finally, now what we have our grammar and our operators, we can create our Jison.Parser. We do this by processing all of our rules, recording all terminals (every symbol which does not appear as the name of a rule above) as "tokens".
tokens: []
@@ -374,7 +393,7 @@ as "tokens".
Initialize the Parser with our list of terminal tokens, our grammar + alt
Initialize the Parser with our list of terminal tokens, our grammar rules, and the name of the root. Reverse the operators because Jison orders precedence from low to high, and we have it high to low (as in Yacc).
exports.parser: new Parser {
diff --git a/documentation/docs/lexer.html b/documentation/docs/lexer.html
index ab619d5b..47b1c3f6 100644
--- a/documentation/docs/lexer.html
+++ b/documentation/docs/lexer.html
@@ -318,7 +318,8 @@ match if successful, and false
otherwise.
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 [
diff --git a/documentation/docs/nodes.html b/documentation/docs/nodes.html
index 6a13dcd5..4d5cecca 100644
--- a/documentation/docs/nodes.html
+++ b/documentation/docs/nodes.html
@@ -148,7 +148,13 @@ make sense.
add_implicit_parentheses: ->
stack: [0]
- calls: 0
+ calls: 0
+ parens: 0
@scan_tokens (prev, token, post, i) =>
tag: token[0]
switch tag
when 'CALL_START' then calls: + 1
when 'CALL_END' then calls: - 1
+ when '(' then parens: + 1
+ when ')' then parens: - 1
when 'INDENT' then stack.push(0)
when 'OUTDENT'
last: stack.pop()
@@ -94,8 +97,9 @@ deal with them.
The tokens that signal the start of a balanced pair.
EXPRESSION_START: pair[0] for pair in BALANCED_PAIRS
The tokens that signal the end of a balanced pair.
EXPRESSION_END: pair[1] for pair in BALANCED_PAIRS
Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE: ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END
Tokens that, if followed by an IMPLICIT_CALL
, indicate a function invocation.
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-']
If preceded by an IMPLICIT_FUNC
, indicates a function invocation.
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION',
'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT',
+ 'THIS', 'NULL',
'@', '->', '=>', '[', '(', '{']
Tokens indicating that the implicit call must enclose a block of expressions.
IMPLICIT_BLOCK: ['->', '=>', '{', '[', ',']
Tokens that always mark the end of an implicit call for single-liners.
IMPLICIT_END: ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT']
Single-line flavors of block expressions that have unclosed endings. The grammar can't disambiguate them, so we insert the implicit indentation.
SINGLE_LINERS: ['ELSE', "->", "=>", 'TRY', 'FINALLY', 'THEN']
SINGLE_CLOSERS: ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN']