2009-12-13 17:07:16 -05:00
|
|
|
class Parser
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# Declare terminal tokens produced by the lexer.
|
2009-12-30 15:52:07 -05:00
|
|
|
token IF ELSE UNLESS
|
2009-12-14 23:03:51 -05:00
|
|
|
token NUMBER STRING REGEX
|
2009-12-23 20:24:55 -05:00
|
|
|
token TRUE FALSE YES NO ON OFF
|
2010-01-23 23:30:55 -05:00
|
|
|
token IDENTIFIER PROPERTY_ACCESS PROTOTYPE_ACCESS SOAK_ACCESS
|
2010-01-26 00:40:58 -05:00
|
|
|
token CODE PARAM_START PARAM PARAM_END NEW RETURN
|
2010-01-26 20:59:52 -05:00
|
|
|
token CALL_START CALL_END INDEX_START INDEX_END
|
2009-12-14 10:00:31 -05:00
|
|
|
token TRY CATCH FINALLY THROW
|
2009-12-14 23:11:28 -05:00
|
|
|
token BREAK CONTINUE
|
2010-01-11 00:01:16 -05:00
|
|
|
token FOR IN OF BY WHEN WHILE
|
2010-01-03 22:25:38 -05:00
|
|
|
token SWITCH LEADING_WHEN
|
2009-12-24 14:50:44 -05:00
|
|
|
token DELETE INSTANCEOF TYPEOF
|
2009-12-24 19:49:23 -05:00
|
|
|
token SUPER EXTENDS
|
2010-02-05 22:39:39 -05:00
|
|
|
token ASSIGN RETURN
|
2009-12-14 23:03:51 -05:00
|
|
|
token NEWLINE
|
2009-12-22 11:27:19 -05:00
|
|
|
token COMMENT
|
2009-12-15 09:11:27 -05:00
|
|
|
token JS
|
2009-12-24 16:48:46 -05:00
|
|
|
token INDENT OUTDENT
|
2009-12-13 17:07:16 -05:00
|
|
|
|
2009-12-16 20:19:52 -05:00
|
|
|
# Declare order of operations.
|
2009-12-13 17:07:16 -05:00
|
|
|
prechigh
|
2010-02-08 11:56:46 -05:00
|
|
|
left '?'
|
2010-01-26 22:14:18 -05:00
|
|
|
nonassoc UMINUS UPLUS NOT '!' '!!' '~' '++' '--'
|
2010-02-08 11:56:46 -05:00
|
|
|
left '*' '/' '%' '.'
|
2009-12-13 17:07:16 -05:00
|
|
|
left '+' '-'
|
2010-02-01 18:31:23 -05:00
|
|
|
left '<<' '>>' '>>>' '&' '|' '^'
|
2009-12-13 17:07:16 -05:00
|
|
|
left '<=' '<' '>' '>='
|
2010-02-09 22:20:04 -05:00
|
|
|
right DELETE INSTANCEOF TYPEOF
|
2009-12-24 20:21:20 -05:00
|
|
|
right '==' '!=' IS ISNT
|
2009-12-13 17:07:16 -05:00
|
|
|
left '&&' '||' AND OR
|
2010-02-01 18:31:23 -05:00
|
|
|
right '-=' '+=' '/=' '*=' '%=' '||=' '&&=' '?='
|
2009-12-28 23:08:02 -05:00
|
|
|
right INDENT
|
|
|
|
left OUTDENT
|
2010-01-11 00:01:16 -05:00
|
|
|
right WHEN LEADING_WHEN IN OF BY
|
2010-01-12 17:45:06 -05:00
|
|
|
right THROW FOR NEW SUPER
|
2010-01-03 15:59:33 -05:00
|
|
|
left EXTENDS
|
2010-01-24 18:59:29 -05:00
|
|
|
right ASSIGN RETURN
|
2010-01-26 10:52:05 -05:00
|
|
|
right '->' '=>' UNLESS IF ELSE WHILE
|
2009-12-13 17:07:16 -05:00
|
|
|
preclow
|
|
|
|
|
|
|
|
rule
|
|
|
|
|
|
|
|
# All parsing will end in this rule, being the trunk of the AST.
|
|
|
|
Root:
|
2010-01-03 13:59:17 -05:00
|
|
|
/* nothing */ { result = Expressions.new }
|
|
|
|
| Terminator { result = Expressions.new }
|
2009-12-13 17:23:10 -05:00
|
|
|
| Expressions { result = val[0] }
|
2010-01-04 22:51:02 -05:00
|
|
|
| Block Terminator { result = val[0] }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-16 21:01:47 -05:00
|
|
|
# Any list of expressions or method body, seperated by line breaks or semis.
|
2009-12-13 17:07:16 -05:00
|
|
|
Expressions:
|
2010-01-03 13:59:17 -05:00
|
|
|
Expression { result = Expressions.wrap(val) }
|
2009-12-13 17:23:10 -05:00
|
|
|
| Expressions Terminator Expression { result = val[0] << val[2] }
|
2009-12-13 23:25:31 -05:00
|
|
|
| Expressions Terminator { result = val[0] }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# All types of expressions in our language. The basic unit of CoffeeScript
|
|
|
|
# is the expression.
|
2009-12-13 17:07:16 -05:00
|
|
|
Expression:
|
2009-12-25 19:20:28 -05:00
|
|
|
Value
|
2009-12-13 17:07:16 -05:00
|
|
|
| Call
|
|
|
|
| Code
|
|
|
|
| Operation
|
2009-12-29 21:46:15 -05:00
|
|
|
| Assign
|
2009-12-13 17:07:16 -05:00
|
|
|
| If
|
2009-12-14 10:00:31 -05:00
|
|
|
| Try
|
2009-12-14 23:03:51 -05:00
|
|
|
| Throw
|
2009-12-13 18:37:29 -05:00
|
|
|
| Return
|
2009-12-15 00:27:34 -05:00
|
|
|
| While
|
|
|
|
| For
|
2009-12-15 22:30:27 -05:00
|
|
|
| Switch
|
2009-12-24 19:49:23 -05:00
|
|
|
| Extends
|
2009-12-31 19:52:13 -05:00
|
|
|
| Splat
|
2010-01-01 12:31:05 -05:00
|
|
|
| Existence
|
2009-12-22 11:27:19 -05:00
|
|
|
| Comment
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# A block of expressions. Note that the Rewriter will convert some postfix
|
|
|
|
# forms into blocks for us, by altering the token stream.
|
2009-12-24 16:48:46 -05:00
|
|
|
Block:
|
2009-12-28 23:08:02 -05:00
|
|
|
INDENT Expressions OUTDENT { result = val[1] }
|
2010-01-03 13:59:17 -05:00
|
|
|
| INDENT OUTDENT { result = Expressions.new }
|
2009-12-24 16:48:46 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# Tokens that can terminate an expression.
|
2009-12-13 17:07:16 -05:00
|
|
|
Terminator:
|
|
|
|
"\n"
|
|
|
|
| ";"
|
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# All hard-coded values. These can be printed straight to JavaScript.
|
2009-12-13 17:07:16 -05:00
|
|
|
Literal:
|
2009-12-13 17:23:10 -05:00
|
|
|
NUMBER { result = LiteralNode.new(val[0]) }
|
|
|
|
| STRING { result = LiteralNode.new(val[0]) }
|
2009-12-15 09:11:27 -05:00
|
|
|
| JS { result = LiteralNode.new(val[0]) }
|
2009-12-13 18:37:29 -05:00
|
|
|
| REGEX { result = LiteralNode.new(val[0]) }
|
2009-12-14 23:11:28 -05:00
|
|
|
| BREAK { result = LiteralNode.new(val[0]) }
|
|
|
|
| CONTINUE { result = LiteralNode.new(val[0]) }
|
2010-01-16 11:24:10 -05:00
|
|
|
| TRUE { result = LiteralNode.new(Value.new(true)) }
|
|
|
|
| FALSE { result = LiteralNode.new(Value.new(false)) }
|
|
|
|
| YES { result = LiteralNode.new(Value.new(true)) }
|
|
|
|
| NO { result = LiteralNode.new(Value.new(false)) }
|
|
|
|
| ON { result = LiteralNode.new(Value.new(true)) }
|
|
|
|
| OFF { result = LiteralNode.new(Value.new(false)) }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# Assignment to a variable (or index).
|
2009-12-13 17:07:16 -05:00
|
|
|
Assign:
|
2009-12-28 23:08:02 -05:00
|
|
|
Value ASSIGN Expression { result = AssignNode.new(val[0], val[2]) }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# Assignment within an object literal (can be quoted).
|
2009-12-13 17:07:16 -05:00
|
|
|
AssignObj:
|
2009-12-28 23:08:02 -05:00
|
|
|
IDENTIFIER ASSIGN Expression { result = AssignNode.new(ValueNode.new(val[0]), val[2], :object) }
|
|
|
|
| STRING ASSIGN Expression { result = AssignNode.new(ValueNode.new(LiteralNode.new(val[0])), val[2], :object) }
|
2010-02-08 11:48:43 -05:00
|
|
|
| NUMBER ASSIGN Expression { result = AssignNode.new(ValueNode.new(LiteralNode.new(val[0])), val[2], :object) }
|
2009-12-22 11:50:43 -05:00
|
|
|
| Comment { result = val[0] }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# A return statement.
|
2009-12-13 18:37:29 -05:00
|
|
|
Return:
|
|
|
|
RETURN Expression { result = ReturnNode.new(val[1]) }
|
2010-01-06 21:21:42 -05:00
|
|
|
| RETURN { result = ReturnNode.new(ValueNode.new(Value.new('null'))) }
|
2009-12-13 18:37:29 -05:00
|
|
|
;
|
|
|
|
|
2009-12-22 11:27:19 -05:00
|
|
|
# A comment.
|
|
|
|
Comment:
|
|
|
|
COMMENT { result = CommentNode.new(val[0]) }
|
|
|
|
;
|
|
|
|
|
2009-12-13 17:07:16 -05:00
|
|
|
# Arithmetic and logical operators
|
|
|
|
# For Ruby's Operator precedence, see:
|
|
|
|
# https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
|
|
|
|
Operation:
|
2009-12-29 21:46:15 -05:00
|
|
|
'!' Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| '!!' Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| '-' Expression = UMINUS { result = OpNode.new(val[0], val[1]) }
|
2010-01-26 22:14:18 -05:00
|
|
|
| '+' Expression = UPLUS { result = OpNode.new(val[0], val[1]) }
|
2009-12-29 21:46:15 -05:00
|
|
|
| NOT Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| '~' Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| '--' Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| '++' Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| DELETE Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| TYPEOF Expression { result = OpNode.new(val[0], val[1]) }
|
|
|
|
| Expression '--' { result = OpNode.new(val[1], val[0], nil, true) }
|
|
|
|
| Expression '++' { result = OpNode.new(val[1], val[0], nil, true) }
|
|
|
|
|
|
|
|
| Expression '*' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '/' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '%' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
|
|
|
|
| Expression '+' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '-' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
|
|
|
|
| Expression '<<' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '>>' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '>>>' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
|
|
|
|
| Expression '&' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '|' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '^' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
|
|
|
|
| Expression '<=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '<' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '>' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '>=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
|
|
|
|
| Expression '==' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '!=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression IS Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression ISNT Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
|
|
|
|
| Expression '&&' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '||' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression AND Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression OR Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
2010-01-16 23:03:54 -05:00
|
|
|
| Expression '?' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
2009-12-29 21:46:15 -05:00
|
|
|
|
|
|
|
| Expression '-=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '+=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '/=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '*=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '%=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '||=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
|
|
|
| Expression '&&=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
2010-01-16 22:17:55 -05:00
|
|
|
| Expression '?=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
2009-12-29 21:46:15 -05:00
|
|
|
|
|
|
|
| Expression INSTANCEOF Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
2010-01-05 23:29:43 -05:00
|
|
|
| Expression IN Expression { result = OpNode.new(val[1], val[0], val[2]) }
|
2009-12-28 23:08:02 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# The existence operator.
|
2010-01-01 12:31:05 -05:00
|
|
|
Existence:
|
|
|
|
Expression '?' { result = ExistenceNode.new(val[0]) }
|
|
|
|
;
|
|
|
|
|
2009-12-28 23:08:02 -05:00
|
|
|
# Function definition.
|
|
|
|
Code:
|
2010-01-26 00:40:58 -05:00
|
|
|
PARAM_START ParamList PARAM_END
|
|
|
|
FuncGlyph Block { result = CodeNode.new(val[1], val[4], val[3]) }
|
2010-01-26 02:15:08 -05:00
|
|
|
| FuncGlyph Block { result = CodeNode.new([], val[1], val[0]) }
|
2010-01-13 20:59:57 -05:00
|
|
|
;
|
|
|
|
|
|
|
|
# The symbols to signify functions, and bound functions.
|
|
|
|
FuncGlyph:
|
2010-01-26 10:52:05 -05:00
|
|
|
'->' { result = :func }
|
|
|
|
| '=>' { result = :boundfunc }
|
2009-12-17 09:07:42 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# The parameters to a function definition.
|
2009-12-13 17:07:16 -05:00
|
|
|
ParamList:
|
2009-12-31 17:50:12 -05:00
|
|
|
Param { result = val }
|
|
|
|
| ParamList "," Param { result = val[0] << val[2] }
|
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# A Parameter (or ParamSplat) in a function definition.
|
2009-12-31 17:50:12 -05:00
|
|
|
Param:
|
|
|
|
PARAM
|
2010-01-12 23:49:47 -05:00
|
|
|
| PARAM "." "." "." { result = SplatNode.new(val[0]) }
|
2009-12-31 19:52:13 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# A regular splat.
|
2009-12-31 19:52:13 -05:00
|
|
|
Splat:
|
2010-01-12 23:49:47 -05:00
|
|
|
Expression "." "." "." { result = SplatNode.new(val[0]) }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# Expressions that can be treated as values.
|
2009-12-14 10:00:31 -05:00
|
|
|
Value:
|
2009-12-18 07:11:01 -05:00
|
|
|
IDENTIFIER { result = ValueNode.new(val[0]) }
|
2009-12-25 19:20:28 -05:00
|
|
|
| Literal { result = ValueNode.new(val[0]) }
|
2009-12-18 07:11:01 -05:00
|
|
|
| Array { result = ValueNode.new(val[0]) }
|
|
|
|
| Object { result = ValueNode.new(val[0]) }
|
|
|
|
| Parenthetical { result = ValueNode.new(val[0]) }
|
2010-01-05 22:49:51 -05:00
|
|
|
| Range { result = ValueNode.new(val[0]) }
|
2010-02-02 20:36:46 -05:00
|
|
|
| This { result = ValueNode.new(val[0]) }
|
2009-12-14 10:00:31 -05:00
|
|
|
| Value Accessor { result = val[0] << val[1] }
|
|
|
|
| Invocation Accessor { result = ValueNode.new(val[0], [val[1]]) }
|
2009-12-13 20:29:44 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# Accessing into an object or array, through dot or index notation.
|
2009-12-13 20:29:44 -05:00
|
|
|
Accessor:
|
|
|
|
PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
|
2010-01-23 23:30:55 -05:00
|
|
|
| PROTOTYPE_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], :prototype) }
|
|
|
|
| SOAK_ACCESS IDENTIFIER { result = AccessorNode.new(val[1], :soak) }
|
2009-12-13 20:29:44 -05:00
|
|
|
| Index { result = val[0] }
|
2010-01-26 20:59:52 -05:00
|
|
|
| Slice { result = SliceNode.new(val[0]) }
|
2009-12-13 20:29:44 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# Indexing into an object or array.
|
2009-12-13 20:29:44 -05:00
|
|
|
Index:
|
2010-01-26 20:59:52 -05:00
|
|
|
INDEX_START Expression INDEX_END { result = IndexNode.new(val[1]) }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# An object literal.
|
2009-12-13 17:07:16 -05:00
|
|
|
Object:
|
2009-12-16 21:01:47 -05:00
|
|
|
"{" AssignList "}" { result = ObjectNode.new(val[1]) }
|
2009-12-15 00:27:34 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# Assignment within an object literal (comma or newline separated).
|
2009-12-13 17:07:16 -05:00
|
|
|
AssignList:
|
2009-12-29 09:25:56 -05:00
|
|
|
/* nothing */ { result = [] }
|
2009-12-13 17:07:16 -05:00
|
|
|
| AssignObj { result = val }
|
|
|
|
| AssignList "," AssignObj { result = val[0] << val[2] }
|
|
|
|
| AssignList Terminator AssignObj { result = val[0] << val[2] }
|
2009-12-29 10:20:18 -05:00
|
|
|
| AssignList ","
|
|
|
|
Terminator AssignObj { result = val[0] << val[3] }
|
2009-12-29 09:25:56 -05:00
|
|
|
| INDENT AssignList OUTDENT { result = val[1] }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# All flavors of function call (instantiation, super, and regular).
|
2009-12-13 17:07:16 -05:00
|
|
|
Call:
|
2009-12-13 23:59:12 -05:00
|
|
|
Invocation { result = val[0] }
|
2009-12-14 10:00:31 -05:00
|
|
|
| NEW Invocation { result = val[1].new_instance }
|
2009-12-17 09:07:42 -05:00
|
|
|
| Super { result = val[0] }
|
2009-12-13 23:45:18 -05:00
|
|
|
;
|
|
|
|
|
2009-12-24 19:49:23 -05:00
|
|
|
# Extending an object's prototype.
|
|
|
|
Extends:
|
2009-12-25 16:57:47 -05:00
|
|
|
Value EXTENDS Value { result = ExtendsNode.new(val[0], val[2]) }
|
2009-12-24 19:49:23 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# A generic function invocation.
|
2009-12-13 23:45:18 -05:00
|
|
|
Invocation:
|
2010-01-03 10:19:39 -05:00
|
|
|
Value Arguments { result = CallNode.new(val[0], val[1]) }
|
|
|
|
| Invocation Arguments { result = CallNode.new(val[0], val[1]) }
|
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# The list of arguments to a function invocation.
|
2010-01-03 10:19:39 -05:00
|
|
|
Arguments:
|
2010-01-26 20:59:52 -05:00
|
|
|
CALL_START ArgList CALL_END { result = val[1] }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# Calling super.
|
2009-12-17 09:07:42 -05:00
|
|
|
Super:
|
2010-01-26 20:59:52 -05:00
|
|
|
SUPER CALL_START ArgList CALL_END { result = CallNode.new(Value.new('super'), val[2]) }
|
2009-12-17 09:07:42 -05:00
|
|
|
;
|
|
|
|
|
2010-02-02 20:36:46 -05:00
|
|
|
# This references, either naked or to a property.
|
|
|
|
This:
|
|
|
|
'@' { result = ThisNode.new }
|
|
|
|
| '@' IDENTIFIER { result = ThisNode.new(val[1]) }
|
|
|
|
;
|
|
|
|
|
2009-12-25 19:20:28 -05:00
|
|
|
# The range literal.
|
|
|
|
Range:
|
2010-01-01 10:15:22 -05:00
|
|
|
"[" Expression
|
|
|
|
"." "." Expression "]" { result = RangeNode.new(val[1], val[4]) }
|
|
|
|
| "[" Expression
|
|
|
|
"." "." "." Expression "]" { result = RangeNode.new(val[1], val[5], true) }
|
2009-12-25 19:20:28 -05:00
|
|
|
;
|
|
|
|
|
2010-01-26 20:59:52 -05:00
|
|
|
# The slice literal.
|
|
|
|
Slice:
|
|
|
|
INDEX_START Expression "." "."
|
|
|
|
Expression INDEX_END { result = RangeNode.new(val[1], val[4]) }
|
|
|
|
| INDEX_START Expression "." "." "."
|
|
|
|
Expression INDEX_END { result = RangeNode.new(val[1], val[5], true) }
|
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# The array literal.
|
2009-12-13 17:07:16 -05:00
|
|
|
Array:
|
2009-12-16 20:48:37 -05:00
|
|
|
"[" ArgList "]" { result = ArrayNode.new(val[1]) }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
# A list of arguments to a method call, or as the contents of an array.
|
2009-12-13 17:07:16 -05:00
|
|
|
ArgList:
|
2009-12-13 17:23:10 -05:00
|
|
|
/* nothing */ { result = [] }
|
|
|
|
| Expression { result = val }
|
2010-01-01 10:38:28 -05:00
|
|
|
| INDENT Expression { result = [val[1]] }
|
2009-12-13 17:23:10 -05:00
|
|
|
| ArgList "," Expression { result = val[0] << val[2] }
|
2009-12-13 20:29:44 -05:00
|
|
|
| ArgList Terminator Expression { result = val[0] << val[2] }
|
2009-12-29 10:20:18 -05:00
|
|
|
| ArgList "," Terminator Expression { result = val[0] << val[3] }
|
2010-01-01 10:38:28 -05:00
|
|
|
| ArgList "," INDENT Expression { result = val[0] << val[3] }
|
|
|
|
| ArgList OUTDENT { result = val[0] }
|
2009-12-13 17:07:16 -05:00
|
|
|
;
|
|
|
|
|
2010-01-13 19:56:35 -05:00
|
|
|
# Just simple, comma-separated, required arguments (no fancy syntax).
|
|
|
|
SimpleArgs:
|
|
|
|
Expression { result = val[0] }
|
|
|
|
| SimpleArgs "," Expression { result = ([val[0]] << val[2]).flatten }
|
|
|
|
;
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# Try/catch/finally exception handling blocks.
|
2009-12-14 10:00:31 -05:00
|
|
|
Try:
|
2009-12-26 22:29:59 -05:00
|
|
|
TRY Block Catch { result = TryNode.new(val[1], val[2][0], val[2][1]) }
|
2009-12-30 00:22:27 -05:00
|
|
|
| TRY Block FINALLY Block { result = TryNode.new(val[1], nil, nil, val[3]) }
|
2009-12-26 22:29:59 -05:00
|
|
|
| TRY Block Catch
|
2009-12-28 23:08:02 -05:00
|
|
|
FINALLY Block { result = TryNode.new(val[1], val[2][0], val[2][1], val[4]) }
|
2009-12-24 02:01:39 -05:00
|
|
|
;
|
|
|
|
|
|
|
|
# A catch clause.
|
|
|
|
Catch:
|
2009-12-30 00:22:27 -05:00
|
|
|
CATCH IDENTIFIER Block { result = [val[1], val[2]] }
|
2009-12-14 23:03:51 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# Throw an exception.
|
2009-12-14 23:03:51 -05:00
|
|
|
Throw:
|
2010-01-03 15:59:33 -05:00
|
|
|
THROW Expression { result = ThrowNode.new(val[1]) }
|
2009-12-14 10:00:31 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# Parenthetical expressions.
|
2009-12-13 23:25:00 -05:00
|
|
|
Parenthetical:
|
2009-12-30 21:44:51 -05:00
|
|
|
"(" Expression ")" { result = ParentheticalNode.new(val[1], val[0].line) }
|
2009-12-13 23:25:00 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# The while loop. (there is no do..while).
|
2009-12-15 00:27:34 -05:00
|
|
|
While:
|
2009-12-30 14:32:59 -05:00
|
|
|
WHILE Expression Block { result = WhileNode.new(val[1], val[2]) }
|
2010-01-09 11:51:32 -05:00
|
|
|
| WHILE Expression { result = WhileNode.new(val[1], nil) }
|
2010-01-13 21:27:22 -05:00
|
|
|
| Expression WHILE Expression { result = WhileNode.new(val[2], Expressions.wrap(val[0])) }
|
2009-12-15 00:27:34 -05:00
|
|
|
;
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# Array comprehensions, including guard and current index.
|
2009-12-25 16:57:47 -05:00
|
|
|
# Looks a little confusing, check nodes.rb for the arguments to ForNode.
|
2009-12-15 00:27:34 -05:00
|
|
|
For:
|
2009-12-25 16:39:33 -05:00
|
|
|
Expression FOR
|
2010-01-01 11:54:59 -05:00
|
|
|
ForVariables ForSource { result = ForNode.new(val[0], val[3], val[2][0], val[2][1]) }
|
|
|
|
| FOR ForVariables ForSource Block { result = ForNode.new(val[3], val[2], val[1][0], val[1][1]) }
|
2009-12-25 16:39:33 -05:00
|
|
|
;
|
|
|
|
|
2009-12-25 16:40:57 -05:00
|
|
|
# An array comprehension has variables for the current element and index.
|
2009-12-25 16:39:33 -05:00
|
|
|
ForVariables:
|
|
|
|
IDENTIFIER { result = val }
|
|
|
|
| IDENTIFIER "," IDENTIFIER { result = [val[0], val[2]] }
|
|
|
|
;
|
|
|
|
|
2009-12-25 16:40:57 -05:00
|
|
|
# The source of the array comprehension can optionally be filtered.
|
|
|
|
ForSource:
|
2010-01-01 11:54:59 -05:00
|
|
|
IN Expression { result = {:source => val[1]} }
|
2010-01-11 00:01:16 -05:00
|
|
|
| OF Expression { result = {:source => val[1], :object => true} }
|
2010-01-01 11:54:59 -05:00
|
|
|
| ForSource
|
|
|
|
WHEN Expression { result = val[0].merge(:filter => val[2]) }
|
|
|
|
| ForSource
|
|
|
|
BY Expression { result = val[0].merge(:step => val[2]) }
|
2009-12-15 00:27:34 -05:00
|
|
|
;
|
|
|
|
|
2009-12-24 04:33:59 -05:00
|
|
|
# Switch/When blocks.
|
2009-12-15 22:30:27 -05:00
|
|
|
Switch:
|
2009-12-28 23:08:02 -05:00
|
|
|
SWITCH Expression INDENT
|
|
|
|
Whens OUTDENT { result = val[3].rewrite_condition(val[1]) }
|
|
|
|
| SWITCH Expression INDENT
|
|
|
|
Whens ELSE Block OUTDENT { result = val[3].rewrite_condition(val[1]).add_else(val[5]) }
|
2009-12-15 22:30:27 -05:00
|
|
|
;
|
|
|
|
|
2009-12-24 04:33:59 -05:00
|
|
|
# The inner list of whens.
|
|
|
|
Whens:
|
|
|
|
When { result = val[0] }
|
|
|
|
| Whens When { result = val[0] << val[1] }
|
2009-12-15 22:30:27 -05:00
|
|
|
;
|
|
|
|
|
2009-12-24 04:33:59 -05:00
|
|
|
# An individual when.
|
|
|
|
When:
|
2010-01-13 19:56:35 -05:00
|
|
|
LEADING_WHEN SimpleArgs Block { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
|
|
|
|
| LEADING_WHEN SimpleArgs Block
|
2010-01-03 22:25:38 -05:00
|
|
|
Terminator { result = IfNode.new(val[1], val[2], nil, {:statement => true}) }
|
2010-01-09 13:25:44 -05:00
|
|
|
| Comment Terminator When { result = val[2].add_comment(val[0]) }
|
2009-12-15 22:30:27 -05:00
|
|
|
;
|
|
|
|
|
2010-01-06 01:27:58 -05:00
|
|
|
# The most basic form of "if".
|
2009-12-28 23:08:02 -05:00
|
|
|
IfBlock:
|
2009-12-29 21:46:15 -05:00
|
|
|
IF Expression Block { result = IfNode.new(val[1], val[2]) }
|
2009-12-28 23:08:02 -05:00
|
|
|
;
|
|
|
|
|
2009-12-18 00:49:23 -05:00
|
|
|
# An elsif portion of an if-else block.
|
|
|
|
ElsIf:
|
2009-12-30 18:59:33 -05:00
|
|
|
ELSE IfBlock { result = val[1].force_statement }
|
2009-12-18 00:49:23 -05:00
|
|
|
;
|
|
|
|
|
|
|
|
# Multiple elsifs can be chained together.
|
|
|
|
ElsIfs:
|
|
|
|
ElsIf { result = val[0] }
|
|
|
|
| ElsIfs ElsIf { result = val[0].add_else(val[1]) }
|
|
|
|
;
|
|
|
|
|
|
|
|
# Terminating else bodies are strictly optional.
|
|
|
|
ElseBody
|
2009-12-24 16:48:46 -05:00
|
|
|
/* nothing */ { result = nil }
|
|
|
|
| ELSE Block { result = val[1] }
|
2009-12-18 00:49:23 -05:00
|
|
|
;
|
|
|
|
|
|
|
|
# All the alternatives for ending an if-else block.
|
|
|
|
IfEnd:
|
|
|
|
ElseBody { result = val[0] }
|
|
|
|
| ElsIfs ElseBody { result = val[0].add_else(val[1]) }
|
|
|
|
;
|
|
|
|
|
|
|
|
# The full complement of if blocks, including postfix one-liner ifs and unlesses.
|
|
|
|
If:
|
2009-12-28 23:08:02 -05:00
|
|
|
IfBlock IfEnd { result = val[0].add_else(val[1]) }
|
2010-01-03 18:11:53 -05:00
|
|
|
| Expression IF Expression { result = IfNode.new(val[2], Expressions.wrap(val[0]), nil, {:statement => true}) }
|
2010-01-03 13:59:17 -05:00
|
|
|
| Expression UNLESS Expression { result = IfNode.new(val[2], Expressions.wrap(val[0]), nil, {:statement => true, :invert => true}) }
|
2009-12-18 00:49:23 -05:00
|
|
|
;
|
|
|
|
|
2009-12-13 17:07:16 -05:00
|
|
|
end
|
|
|
|
|
2009-12-17 22:13:29 -05:00
|
|
|
---- header
|
|
|
|
module CoffeeScript
|
|
|
|
|
2009-12-13 17:07:16 -05:00
|
|
|
---- inner
|
2009-12-17 22:22:35 -05:00
|
|
|
# Lex and parse a CoffeeScript.
|
2009-12-17 10:04:43 -05:00
|
|
|
def parse(code)
|
2009-12-17 22:22:35 -05:00
|
|
|
# Uncomment the following line to enable grammar debugging, in combination
|
|
|
|
# with the -g flag in the Rake build task.
|
2009-12-13 17:07:16 -05:00
|
|
|
# @yydebug = true
|
|
|
|
@tokens = Lexer.new.tokenize(code)
|
|
|
|
do_parse
|
|
|
|
end
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# Retrieve the next token from the list.
|
2009-12-13 17:07:16 -05:00
|
|
|
def next_token
|
|
|
|
@tokens.shift
|
2009-12-17 10:04:43 -05:00
|
|
|
end
|
|
|
|
|
2009-12-17 22:22:35 -05:00
|
|
|
# Raise a custom error class that knows about line numbers.
|
2009-12-17 10:04:43 -05:00
|
|
|
def on_error(error_token_id, error_value, value_stack)
|
2009-12-17 22:13:29 -05:00
|
|
|
raise ParseError.new(token_to_str(error_token_id), error_value, value_stack)
|
|
|
|
end
|
|
|
|
|
|
|
|
---- footer
|
|
|
|
end
|