-
Notifications
You must be signed in to change notification settings - Fork 2k
/
grammar.coffee
1003 lines (884 loc) · 48.7 KB
/
grammar.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison)
# from this grammar file. Jison is a bottom-up parser generator, similar in
# style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript.
# It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](https://en.wikipedia.org/wiki/LR_grammar)
# type grammars. To create the Jison parser, we list the pattern to match
# on the left-hand side, and the action to take (usually the creation of syntax
# tree nodes) on the right. As the parser runs, it
# shifts tokens from our token stream, from left to right, and
# [attempts to match](https://en.wikipedia.org/wiki/Bottom-up_parsing)
# the token sequence against the rules below. When a match can be made, it
# reduces into the [nonterminal](https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols)
# (the enclosing name at the top), and we proceed from there.
#
# If you run the `cake build:parser` command, Jison constructs a parse table
# from our rules and saves it into `lib/parser.js`.
# The only dependency is on the **Jison.Parser**.
{Parser} = require 'jison'
# Jison DSL
# ---------
# Since we're going to be wrapped in a function by Jison in any case, if our
# action immediately returns a value, we can optimize by removing the function
# wrapper and just returning the value directly.
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
# Our handy DSL for Jison grammar generation, thanks to
# [Tim Caswell](https://github.com/creationix). For every rule in the grammar,
# we pass the pattern-defining string, the action to run, and extra options,
# optionally. If no action is specified, we simply pass the value of the
# previous nonterminal.
o = (patternString, action, options) ->
patternString = patternString.replace /\s{2,}/g, ' '
patternCount = patternString.split(' ').length
if action
# This code block does string replacements in the generated `parser.js`
# file, replacing the calls to the `LOC` function and other strings as
# listed below.
action = if match = unwrap.exec action then match[1] else "(#{action}())"
# All runtime functions we need are defined on `yy`
action = action.replace /\bnew /g, '$&yy.'
action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
# Returns strings of functions to add to `parser.js` which add extra data
# that nodes may have, such as comments or location data. Location data
# is added to the first parameter passed in, and the parameter is returned.
# If the parameter is not a node, it will just be passed through unaffected.
getAddDataToNodeFunctionString = (first, last, forceUpdateLocation = yes) ->
"yy.addDataToNode(yy, @#{first}, #{if first[0] is '$' then '$$' else '$'}#{first}, #{if last then "@#{last}, #{if last[0] is '$' then '$$' else '$'}#{last}" else 'null, null'}, #{if forceUpdateLocation then 'true' else 'false'})"
# This code replaces the calls to `LOC` with the `yy.addDataToNode` string
# defined above. The `LOC` function, when used below in the grammar rules,
# is used to make sure that newly created node class objects get correct
# location data assigned to them. By default, the grammar will assign the
# location data spanned by *all* of the tokens on the left (e.g. a string
# such as `'Body TERMINATOR Line'`) to the “top-level” node returned by
# the grammar rule (the function on the right). But for “inner” node class
# objects created by grammar rules, they won’t get correct location data
# assigned to them without adding `LOC`.
# For example, consider the grammar rule `'NEW_TARGET . Property'`, which
# is handled by a function that returns
# `new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)`.
# The `1` in `LOC(1)` refers to the first token (`NEW_TARGET`) and the `3`
# in `LOC(3)` refers to the third token (`Property`). In order for the
# `new IdentifierLiteral` to get assigned the location data corresponding
# to `new` in the source code, we use
# `LOC(1)(new IdentifierLiteral ...)` to mean “assign the location data of
# the *first* token of this grammar rule (`NEW_TARGET`) to this
# `new IdentifierLiteral`”. The `LOC(3)` means “assign the location data of
# the *third* token of this grammar rule (`Property`) to this
# `new Access`”.
returnsLoc = /^LOC/.test action
action = action.replace /LOC\(([0-9]*)\)/g, getAddDataToNodeFunctionString('$1')
# A call to `LOC` with two arguments, e.g. `LOC(2,4)`, sets the location
# data for the generated node on both of the referenced tokens (the second
# and fourth in this example).
action = action.replace /LOC\(([0-9]*),\s*([0-9]*)\)/g, getAddDataToNodeFunctionString('$1', '$2')
performActionFunctionString = "$$ = #{getAddDataToNodeFunctionString(1, patternCount, not returnsLoc)}(#{action});"
else
performActionFunctionString = '$$ = $1;'
[patternString, performActionFunctionString, options]
# Grammatical Rules
# -----------------
# In all of the rules that follow, you'll see the name of the nonterminal as
# the key to a list of alternative matches. With each match's action, the
# dollar-sign variables are provided by Jison as references to the value of
# their numeric position, so in this rule:
#
# 'Expression UNLESS Expression'
#
# `$1` would be the value of the first `Expression`, `$2` would be the token
# for the `UNLESS` terminal, and `$3` would be the value of the second
# `Expression`.
grammar =
# The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
# all parsing must end here.
Root: [
o '', -> new Root new Block
o 'Body', -> new Root $1
]
# Any list of statements and expressions, separated by line breaks or semicolons.
Body: [
o 'Line', -> Block.wrap [$1]
o 'Body TERMINATOR Line', -> $1.push $3
o 'Body TERMINATOR'
]
# Block and statements, which make up a line in a body. FuncDirective is a
# statement, but not included in Statement because that results in an ambiguous
# grammar.
Line: [
o 'Expression'
o 'ExpressionLine'
o 'Statement'
o 'FuncDirective'
]
FuncDirective: [
o 'YieldReturn'
o 'AwaitReturn'
]
# Pure statements which cannot be expressions.
Statement: [
o 'Return'
o 'STATEMENT', -> new StatementLiteral $1
o 'Import'
o 'Export'
]
# All the different types of expressions in our language. The basic unit of
# CoffeeScript is the **Expression** -- everything that can be an expression
# is one. Blocks serve as the building blocks of many other rules, making
# them somewhat circular.
Expression: [
o 'Value'
o 'Code'
o 'Operation'
o 'Assign'
o 'If'
o 'Try'
o 'While'
o 'For'
o 'Switch'
o 'Class'
o 'Throw'
o 'Yield'
]
# Expressions which are written in single line and would otherwise require being
# wrapped in braces: E.g `a = b if do -> f a is 1`, `if f (a) -> a*2 then ...`,
# `for x in do (obj) -> f obj when x > 8 then f x`
ExpressionLine: [
o 'CodeLine'
o 'IfLine'
o 'OperationLine'
]
Yield: [
o 'YIELD', -> new Op $1, new Value new Literal ''
o 'YIELD Expression', -> new Op $1, $2
o 'YIELD INDENT Object OUTDENT', -> new Op $1, $3
o 'YIELD FROM Expression', -> new Op $1.concat($2), $3
]
# An indented block of expressions. Note that the [Rewriter](rewriter.html)
# will convert some postfix forms into blocks for us, by adjusting the
# token stream.
Block: [
o 'INDENT OUTDENT', -> new Block
o 'INDENT Body OUTDENT', -> $2
]
Identifier: [
o 'IDENTIFIER', -> new IdentifierLiteral $1
o 'JSX_TAG', -> new JSXTag $1.toString(),
tagNameLocationData: $1.tagNameToken[2]
closingTagOpeningBracketLocationData: $1.closingTagOpeningBracketToken?[2]
closingTagSlashLocationData: $1.closingTagSlashToken?[2]
closingTagNameLocationData: $1.closingTagNameToken?[2]
closingTagClosingBracketLocationData: $1.closingTagClosingBracketToken?[2]
]
Property: [
o 'PROPERTY', -> new PropertyName $1.toString()
]
# Alphanumerics are separated from the other **Literal** matchers because
# they can also serve as keys in object literals.
AlphaNumeric: [
o 'NUMBER', -> new NumberLiteral $1.toString(), parsedValue: $1.parsedValue
o 'String'
]
String: [
o 'STRING', ->
new StringLiteral(
$1.slice 1, -1 # strip artificial quotes and unwrap to primitive string
quote: $1.quote
initialChunk: $1.initialChunk
finalChunk: $1.finalChunk
indent: $1.indent
double: $1.double
heregex: $1.heregex
)
o 'STRING_START Interpolations STRING_END', -> new StringWithInterpolations Block.wrap($2), quote: $1.quote, startQuote: LOC(1)(new Literal $1.toString())
]
Interpolations: [
o 'InterpolationChunk', -> [$1]
o 'Interpolations InterpolationChunk', -> $1.concat $2
]
InterpolationChunk: [
o 'INTERPOLATION_START Body INTERPOLATION_END', -> new Interpolation $2
o 'INTERPOLATION_START INDENT Body OUTDENT INTERPOLATION_END', -> new Interpolation $3
o 'INTERPOLATION_START INTERPOLATION_END', -> new Interpolation
o 'String', -> $1
]
# The .toString() calls here and elsewhere are to convert `String` objects
# back to primitive strings now that we've retrieved stowaway extra properties
Regex: [
o 'REGEX', -> new RegexLiteral $1.toString(), delimiter: $1.delimiter, heregexCommentTokens: $1.heregexCommentTokens
o 'REGEX_START Invocation REGEX_END', -> new RegexWithInterpolations $2, heregexCommentTokens: $3.heregexCommentTokens
]
# All of our immediate values. Generally these can be passed straight
# through and printed to JavaScript.
Literal: [
o 'AlphaNumeric'
o 'JS', -> new PassthroughLiteral $1.toString(), here: $1.here, generated: $1.generated
o 'Regex'
o 'UNDEFINED', -> new UndefinedLiteral $1
o 'NULL', -> new NullLiteral $1
o 'BOOL', -> new BooleanLiteral $1.toString(), originalValue: $1.original
o 'INFINITY', -> new InfinityLiteral $1.toString(), originalValue: $1.original
o 'NAN', -> new NaNLiteral $1
]
# Assignment of a variable, property, or index to a value.
Assign: [
o 'Assignable = Expression', -> new Assign $1, $3
o 'Assignable = TERMINATOR Expression', -> new Assign $1, $4
o 'Assignable = INDENT Expression OUTDENT', -> new Assign $1, $4
]
# 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 'ObjAssignable', -> new Value $1
o 'ObjRestValue'
o 'ObjAssignable : Expression', -> new Assign LOC(1)(new Value $1), $3, 'object',
operatorToken: LOC(2)(new Literal $2)
o 'ObjAssignable :
INDENT Expression OUTDENT', -> new Assign LOC(1)(new Value $1), $4, 'object',
operatorToken: LOC(2)(new Literal $2)
o 'SimpleObjAssignable = Expression', -> new Assign LOC(1)(new Value $1), $3, null,
operatorToken: LOC(2)(new Literal $2)
o 'SimpleObjAssignable =
INDENT Expression OUTDENT', -> new Assign LOC(1)(new Value $1), $4, null,
operatorToken: LOC(2)(new Literal $2)
]
SimpleObjAssignable: [
o 'Identifier'
o 'Property'
o 'ThisProperty'
]
ObjAssignable: [
o 'SimpleObjAssignable'
o '[ Expression ]', -> new Value new ComputedPropertyName $2
o '@ [ Expression ]', -> new Value LOC(1)(new ThisLiteral $1), [LOC(3)(new ComputedPropertyName($3))], 'this'
o 'AlphaNumeric'
]
# Object literal spread properties.
ObjRestValue: [
o 'SimpleObjAssignable ...', -> new Splat new Value $1
o '... SimpleObjAssignable', -> new Splat new Value($2), postfix: no
o 'ObjSpreadExpr ...', -> new Splat $1
o '... ObjSpreadExpr', -> new Splat $2, postfix: no
]
ObjSpreadExpr: [
o 'ObjSpreadIdentifier'
o 'Object'
o 'Parenthetical'
o 'Super'
o 'This'
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2.soak, $1
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
o 'SimpleObjAssignable OptFuncExist Arguments', -> new Call (new Value $1), $3, $2.soak
o 'ObjSpreadExpr OptFuncExist Arguments', -> new Call $1, $3, $2.soak
]
ObjSpreadIdentifier: [
o 'SimpleObjAssignable Accessor', -> (new Value $1).add $2
o 'ObjSpreadExpr Accessor', -> (new Value $1).add $2
]
# A return statement from a function body.
Return: [
o 'RETURN Expression', -> new Return $2
o 'RETURN INDENT Object OUTDENT', -> new Return new Value $3
o 'RETURN', -> new Return
]
YieldReturn: [
o 'YIELD RETURN Expression', -> new YieldReturn $3, returnKeyword: LOC(2)(new Literal $2)
o 'YIELD RETURN', -> new YieldReturn null, returnKeyword: LOC(2)(new Literal $2)
]
AwaitReturn: [
o 'AWAIT RETURN Expression', -> new AwaitReturn $3, returnKeyword: LOC(2)(new Literal $2)
o 'AWAIT RETURN', -> new AwaitReturn null, returnKeyword: LOC(2)(new Literal $2)
]
# The **Code** node is the function literal. It’s defined by an indented block
# of **Block** preceded by a function arrow, with an optional parameter list.
Code: [
o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4, LOC(1)(new Literal $1)
o 'FuncGlyph Block', -> new Code [], $2, $1
]
# The Codeline is the **Code** node with **Line** instead of indented **Block**.
CodeLine: [
o 'PARAM_START ParamList PARAM_END FuncGlyph Line', -> new Code $2, LOC(5)(Block.wrap [$5]), $4,
LOC(1)(new Literal $1)
o 'FuncGlyph Line', -> new Code [], LOC(2)(Block.wrap [$2]), $1
]
# CoffeeScript has two different symbols for functions. `->` is for ordinary
# functions, and `=>` is for functions bound to the current value of *this*.
FuncGlyph: [
o '->', -> new FuncGlyph $1
o '=>', -> new FuncGlyph $1
]
# An optional, trailing comma.
OptComma: [
o ''
o ','
]
# The list of parameters that a function accepts can be of any length.
ParamList: [
o '', -> []
o 'Param', -> [$1]
o 'ParamList , Param', -> $1.concat $3
o 'ParamList OptComma TERMINATOR Param', -> $1.concat $4
o 'ParamList OptComma INDENT ParamList OptComma OUTDENT', -> $1.concat $4
]
# A single parameter in a function definition can be ordinary, or a splat
# that hoovers up the remaining arguments.
Param: [
o 'ParamVar', -> new Param $1
o 'ParamVar ...', -> new Param $1, null, on
o '... ParamVar', -> new Param $2, null, postfix: no
o 'ParamVar = Expression', -> new Param $1, $3
o '...', -> new Expansion
]
# Function Parameters
ParamVar: [
o 'Identifier'
o 'ThisProperty'
o 'Array'
o 'Object'
]
# A splat that occurs outside of a parameter list.
Splat: [
o 'Expression ...', -> new Splat $1
o '... Expression', -> new Splat $2, {postfix: no}
]
# Variables and properties that can be assigned to.
SimpleAssignable: [
o 'Identifier', -> new Value $1
o 'Value Accessor', -> $1.add $2
o 'Code Accessor', -> new Value($1).add $2
o 'ThisProperty'
]
# Everything that can be assigned to.
Assignable: [
o 'SimpleAssignable'
o 'Array', -> new Value $1
o 'Object', -> new Value $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 Value $1
o 'Parenthetical', -> new Value $1
o 'Range', -> new Value $1
o 'Invocation', -> new Value $1
o 'DoIife', -> new Value $1
o 'This'
o 'Super', -> new Value $1
o 'MetaProperty', -> new Value $1
]
# A `super`-based expression that can be used as a value.
Super: [
o 'SUPER . Property', -> new Super LOC(3)(new Access $3), LOC(1)(new Literal $1)
o 'SUPER INDEX_START Expression INDEX_END', -> new Super LOC(3)(new Index $3), LOC(1)(new Literal $1)
o 'SUPER INDEX_START INDENT Expression OUTDENT INDEX_END', -> new Super LOC(4)(new Index $4), LOC(1)(new Literal $1)
]
# A “meta-property” access e.g. `new.target` or `import.meta`, where
# something that looks like a property is referenced on a keyword.
MetaProperty: [
o 'NEW_TARGET . Property', -> new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)
o 'IMPORT_META . Property', -> new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)
]
# The general group of accessors into an object, by property, by prototype
# or by array index or slice.
Accessor: [
o '. Property', -> new Access $2
o '?. Property', -> new Access $2, soak: yes
o ':: Property', -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes), LOC(2)(new Access $2)]
o '?:: Property', -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes, soak: yes), LOC(2)(new Access $2)]
o '::', -> new Access new PropertyName('prototype'), shorthand: yes
o '?::', -> new Access new PropertyName('prototype'), shorthand: yes, soak: yes
o 'Index'
]
# Indexing into an object or array using bracket notation.
Index: [
o 'INDEX_START IndexValue INDEX_END', -> $2
o 'INDEX_START INDENT IndexValue OUTDENT INDEX_END', -> $3
o 'INDEX_SOAK Index', -> extend $2, soak: yes
]
IndexValue: [
o 'Expression', -> new Index $1
o 'Slice', -> new Slice $1
]
# In CoffeeScript, an object literal is simply a list of assignments.
Object: [
o '{ AssignList OptComma }', -> new Obj $2, $1.generated
]
# 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 OptComma TERMINATOR AssignObj', -> $1.concat $4
o 'AssignList OptComma INDENT AssignList OptComma OUTDENT', -> $1.concat $4
]
# Class definitions have optional bodies of prototype property assignments,
# and optional references to the superclass.
Class: [
o 'CLASS', -> new Class
o 'CLASS Block', -> new Class null, null, $2
o 'CLASS EXTENDS Expression', -> new Class null, $3
o 'CLASS EXTENDS Expression Block', -> new Class null, $3, $4
o 'CLASS SimpleAssignable', -> new Class $2
o 'CLASS SimpleAssignable Block', -> new Class $2, null, $3
o 'CLASS SimpleAssignable EXTENDS Expression', -> new Class $2, $4
o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5
]
Import: [
o 'IMPORT String', -> new ImportDeclaration null, $2
o 'IMPORT String ASSERT Object', -> new ImportDeclaration null, $2, $4
o 'IMPORT ImportDefaultSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, null), $4
o 'IMPORT ImportDefaultSpecifier FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, null), $4, $6
o 'IMPORT ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause(null, $2), $4
o 'IMPORT ImportNamespaceSpecifier FROM String ASSERT Object', -> new ImportDeclaration new ImportClause(null, $2), $4, $6
o 'IMPORT { } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5
o 'IMPORT { } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5, $7
o 'IMPORT { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7
o 'IMPORT { ImportSpecifierList OptComma } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7, $9
o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String', -> new ImportDeclaration new ImportClause($2, $4), $6
o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, $4), $6, $8
o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9
o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9, $11
]
ImportSpecifierList: [
o 'ImportSpecifier', -> [$1]
o 'ImportSpecifierList , ImportSpecifier', -> $1.concat $3
o 'ImportSpecifierList OptComma TERMINATOR ImportSpecifier', -> $1.concat $4
o 'INDENT ImportSpecifierList OptComma OUTDENT', -> $2
o 'ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', -> $1.concat $4
]
ImportSpecifier: [
o 'Identifier', -> new ImportSpecifier $1
o 'Identifier AS Identifier', -> new ImportSpecifier $1, $3
o 'DEFAULT', -> new ImportSpecifier LOC(1)(new DefaultLiteral $1)
o 'DEFAULT AS Identifier', -> new ImportSpecifier LOC(1)(new DefaultLiteral($1)), $3
]
ImportDefaultSpecifier: [
o 'Identifier', -> new ImportDefaultSpecifier $1
]
ImportNamespaceSpecifier: [
o 'IMPORT_ALL AS Identifier', -> new ImportNamespaceSpecifier new Literal($1), $3
]
Export: [
o 'EXPORT { }', -> new ExportNamedDeclaration new ExportSpecifierList []
o 'EXPORT { ExportSpecifierList OptComma }', -> new ExportNamedDeclaration new ExportSpecifierList $3
o 'EXPORT Class', -> new ExportNamedDeclaration $2
o 'EXPORT Identifier = Expression', -> new ExportNamedDeclaration LOC(2,4)(new Assign $2, $4, null,
moduleDeclaration: 'export')
o 'EXPORT Identifier = TERMINATOR Expression', -> new ExportNamedDeclaration LOC(2,5)(new Assign $2, $5, null,
moduleDeclaration: 'export')
o 'EXPORT Identifier = INDENT Expression OUTDENT', -> new ExportNamedDeclaration LOC(2,6)(new Assign $2, $5, null,
moduleDeclaration: 'export')
o 'EXPORT DEFAULT Expression', -> new ExportDefaultDeclaration $3
o 'EXPORT DEFAULT INDENT Object OUTDENT', -> new ExportDefaultDeclaration new Value $4
o 'EXPORT EXPORT_ALL FROM String', -> new ExportAllDeclaration new Literal($2), $4
o 'EXPORT EXPORT_ALL FROM String ASSERT Object', -> new ExportAllDeclaration new Literal($2), $4, $6
o 'EXPORT { } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList([]), $5
o 'EXPORT { } FROM String ASSERT Object', -> new ExportNamedDeclaration new ExportSpecifierList([]), $5, $7
o 'EXPORT { ExportSpecifierList OptComma } FROM String', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
o 'EXPORT { ExportSpecifierList OptComma } FROM String ASSERT Object', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7, $9
]
ExportSpecifierList: [
o 'ExportSpecifier', -> [$1]
o 'ExportSpecifierList , ExportSpecifier', -> $1.concat $3
o 'ExportSpecifierList OptComma TERMINATOR ExportSpecifier', -> $1.concat $4
o 'INDENT ExportSpecifierList OptComma OUTDENT', -> $2
o 'ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', -> $1.concat $4
]
ExportSpecifier: [
o 'Identifier', -> new ExportSpecifier $1
o 'Identifier AS Identifier', -> new ExportSpecifier $1, $3
o 'Identifier AS DEFAULT', -> new ExportSpecifier $1, LOC(3)(new DefaultLiteral $3)
o 'DEFAULT', -> new ExportSpecifier LOC(1)(new DefaultLiteral $1)
o 'DEFAULT AS Identifier', -> new ExportSpecifier LOC(1)(new DefaultLiteral($1)), $3
]
# Ordinary function invocation, or a chained series of calls.
Invocation: [
o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2.soak
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2.soak
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2.soak, $1
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
]
# An optional existence check on a function.
OptFuncExist: [
o '', -> soak: no
o 'FUNC_EXIST', -> soak: yes
]
# The list of arguments to a function call.
Arguments: [
o 'CALL_START CALL_END', -> []
o 'CALL_START ArgList OptComma CALL_END', -> $2.implicit = $1.generated; $2
]
# A reference to the *this* current object.
This: [
o 'THIS', -> new Value new ThisLiteral $1
o '@', -> new Value new ThisLiteral $1
]
# A reference to a property on *this*.
ThisProperty: [
o '@ Property', -> new Value LOC(1)(new ThisLiteral $1), [LOC(2)(new Access($2))], 'this'
]
# The array literal.
Array: [
o '[ ]', -> new Arr []
o '[ Elisions ]', -> new Arr $2
o '[ ArgElisionList OptElisions ]', -> new Arr [].concat $2, $3
]
# Inclusive and exclusive range dots.
RangeDots: [
o '..', -> exclusive: no
o '...', -> exclusive: yes
]
# The CoffeeScript range literal.
Range: [
o '[ Expression RangeDots Expression ]', -> new Range $2, $4, if $3.exclusive then 'exclusive' else 'inclusive'
o '[ ExpressionLine RangeDots Expression ]', -> new Range $2, $4, if $3.exclusive then 'exclusive' else 'inclusive'
]
# Array slice literals.
Slice: [
o 'Expression RangeDots Expression', -> new Range $1, $3, if $2.exclusive then 'exclusive' else 'inclusive'
o 'Expression RangeDots', -> new Range $1, null, if $2.exclusive then 'exclusive' else 'inclusive'
o 'ExpressionLine RangeDots Expression', -> new Range $1, $3, if $2.exclusive then 'exclusive' else 'inclusive'
o 'ExpressionLine RangeDots', -> new Range $1, null, if $2.exclusive then 'exclusive' else 'inclusive'
o 'RangeDots Expression', -> new Range null, $2, if $1.exclusive then 'exclusive' else 'inclusive'
o 'RangeDots', -> new Range null, null, if $1.exclusive then 'exclusive' else 'inclusive'
]
# The **ArgList** is the list of objects passed into a function call
# (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o 'Arg', -> [$1]
o 'ArgList , Arg', -> $1.concat $3
o 'ArgList OptComma TERMINATOR Arg', -> $1.concat $4
o 'INDENT ArgList OptComma OUTDENT', -> $2
o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
]
# Valid arguments are Blocks or Splats.
Arg: [
o 'Expression'
o 'ExpressionLine'
o 'Splat'
o '...', -> new Expansion
]
# The **ArgElisionList** is the list of objects, contents of an array literal
# (i.e. comma-separated expressions and elisions). Newlines work as well.
ArgElisionList: [
o 'ArgElision'
o 'ArgElisionList , ArgElision', -> $1.concat $3
o 'ArgElisionList OptComma TERMINATOR ArgElision', -> $1.concat $4
o 'INDENT ArgElisionList OptElisions OUTDENT', -> $2.concat $3
o 'ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT', -> $1.concat $2, $4, $5
]
ArgElision: [
o 'Arg', -> [$1]
o 'Elisions Arg', -> $1.concat $2
]
OptElisions: [
o 'OptComma', -> []
o ', Elisions', -> [].concat $2
]
Elisions: [
o 'Elision', -> [$1]
o 'Elisions Elision', -> $1.concat $2
]
Elision: [
o ',', -> new Elision
o 'Elision TERMINATOR', -> $1
]
# 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 'ExpressionLine'
o 'SimpleArgs , Expression', -> [].concat $1, $3
o 'SimpleArgs , ExpressionLine', -> [].concat $1, $3
]
# The variants of *try/catch/finally* exception handling blocks.
Try: [
o 'TRY Block', -> new Try $2
o 'TRY Block Catch', -> new Try $2, $3
o 'TRY Block FINALLY Block', -> new Try $2, null, $4, LOC(3)(new Literal $3)
o 'TRY Block Catch FINALLY Block', -> new Try $2, $3, $5, LOC(4)(new Literal $4)
]
# A catch clause names its error and runs a block of code.
Catch: [
o 'CATCH Identifier Block', -> new Catch $3, $2
o 'CATCH Object Block', -> new Catch $3, LOC(2)(new Value($2))
o 'CATCH Block', -> new Catch $2
]
# Throw an exception object.
Throw: [
o 'THROW Expression', -> new Throw $2
o 'THROW INDENT Object OUTDENT', -> new Throw new Value $3
]
# 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 '( Body )', -> new Parens $2
o '( INDENT Body OUTDENT )', -> new Parens $3
]
# The condition portion of a while loop.
WhileLineSource: [
o 'WHILE ExpressionLine', -> new While $2
o 'WHILE ExpressionLine WHEN ExpressionLine', -> new While $2, guard: $4
o 'UNTIL ExpressionLine', -> new While $2, invert: true
o 'UNTIL ExpressionLine WHEN ExpressionLine', -> new While $2, invert: true, guard: $4
]
WhileSource: [
o 'WHILE Expression', -> new While $2
o 'WHILE Expression WHEN Expression', -> new While $2, guard: $4
o 'WHILE ExpressionLine WHEN Expression', -> new While $2, guard: $4
o 'UNTIL Expression', -> new While $2, invert: true
o 'UNTIL Expression WHEN Expression', -> new While $2, invert: true, guard: $4
o 'UNTIL ExpressionLine WHEN Expression', -> new While $2, invert: true, guard: $4
]
# 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.addBody $2
o 'WhileLineSource Block', -> $1.addBody $2
o 'Statement WhileSource', -> (Object.assign $2, postfix: yes).addBody LOC(1) Block.wrap([$1])
o 'Expression WhileSource', -> (Object.assign $2, postfix: yes).addBody LOC(1) Block.wrap([$1])
o 'Loop', -> $1
]
Loop: [
o 'LOOP Block', -> new While(LOC(1)(new BooleanLiteral 'true'), isLoop: yes).addBody $2
o 'LOOP Expression', -> new While(LOC(1)(new BooleanLiteral 'true'), isLoop: yes).addBody LOC(2) Block.wrap [$2]
]
# 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 'Statement ForBody', -> $2.postfix = yes; $2.addBody $1
o 'Expression ForBody', -> $2.postfix = yes; $2.addBody $1
o 'ForBody Block', -> $1.addBody $2
o 'ForLineBody Block', -> $1.addBody $2
]
ForBody: [
o 'FOR Range', -> new For [], source: (LOC(2) new Value($2))
o 'FOR Range BY Expression', -> new For [], source: (LOC(2) new Value($2)), step: $4
o 'ForStart ForSource', -> $1.addSource $2
]
ForLineBody: [
o 'FOR Range BY ExpressionLine', -> new For [], source: (LOC(2) new Value($2)), step: $4
o 'ForStart ForLineSource', -> $1.addSource $2
]
ForStart: [
o 'FOR ForVariables', -> new For [], name: $2[0], index: $2[1]
o 'FOR AWAIT ForVariables', ->
[name, index] = $3
new For [], {name, index, await: yes, awaitTag: (LOC(2) new Literal($2))}
o 'FOR OWN ForVariables', ->
[name, index] = $3
new For [], {name, index, own: yes, ownTag: (LOC(2) new Literal($2))}
]
# An array of all accepted values for a variable inside the loop.
# This enables support for pattern matching.
ForValue: [
o 'Identifier'
o 'ThisProperty'
o 'Array', -> new Value $1
o 'Object', -> new Value $1
]
# 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 'ForValue', -> [$1]
o 'ForValue , ForValue', -> [$1, $3]
]
# The source of a comprehension is an array or object with an optional guard
# clause. If it’s an array comprehension, you can also choose to step through
# in fixed-size increments.
ForSource: [
o 'FORIN Expression', -> source: $2
o 'FOROF Expression', -> source: $2, object: yes
o 'FORIN Expression WHEN Expression', -> source: $2, guard: $4
o 'FORIN ExpressionLine WHEN Expression', -> source: $2, guard: $4
o 'FOROF Expression WHEN Expression', -> source: $2, guard: $4, object: yes
o 'FOROF ExpressionLine WHEN Expression', -> source: $2, guard: $4, object: yes
o 'FORIN Expression BY Expression', -> source: $2, step: $4
o 'FORIN ExpressionLine BY Expression', -> source: $2, step: $4
o 'FORIN Expression WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
o 'FORIN ExpressionLine WHEN Expression BY Expression', -> source: $2, guard: $4, step: $6
o 'FORIN Expression WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6
o 'FORIN ExpressionLine WHEN ExpressionLine BY Expression', -> source: $2, guard: $4, step: $6
o 'FORIN Expression BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
o 'FORIN ExpressionLine BY Expression WHEN Expression', -> source: $2, step: $4, guard: $6
o 'FORIN Expression BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6
o 'FORIN ExpressionLine BY ExpressionLine WHEN Expression', -> source: $2, step: $4, guard: $6
o 'FORFROM Expression', -> source: $2, from: yes
o 'FORFROM Expression WHEN Expression', -> source: $2, guard: $4, from: yes
o 'FORFROM ExpressionLine WHEN Expression', -> source: $2, guard: $4, from: yes
]
ForLineSource: [
o 'FORIN ExpressionLine', -> source: $2
o 'FOROF ExpressionLine', -> source: $2, object: yes
o 'FORIN Expression WHEN ExpressionLine', -> source: $2, guard: $4
o 'FORIN ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4
o 'FOROF Expression WHEN ExpressionLine', -> source: $2, guard: $4, object: yes
o 'FOROF ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, object: yes
o 'FORIN Expression BY ExpressionLine', -> source: $2, step: $4
o 'FORIN ExpressionLine BY ExpressionLine', -> source: $2, step: $4
o 'FORIN Expression WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6
o 'FORIN ExpressionLine WHEN Expression BY ExpressionLine', -> source: $2, guard: $4, step: $6
o 'FORIN Expression WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
o 'FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
o 'FORIN Expression BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
o 'FORIN ExpressionLine BY Expression WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
o 'FORIN Expression BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
o 'FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine', -> source: $2, step: $4, guard: $6
o 'FORFROM ExpressionLine', -> source: $2, from: yes
o 'FORFROM Expression WHEN ExpressionLine', -> source: $2, guard: $4, from: yes
o 'FORFROM ExpressionLine WHEN ExpressionLine', -> source: $2, guard: $4, from: yes
]
Switch: [
o 'SWITCH Expression INDENT Whens OUTDENT', -> new Switch $2, $4
o 'SWITCH ExpressionLine INDENT Whens OUTDENT', -> new Switch $2, $4
o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, LOC(5,6) $6
o 'SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, LOC(5,6) $6
o 'SWITCH INDENT Whens OUTDENT', -> new Switch null, $3
o 'SWITCH INDENT Whens ELSE Block OUTDENT', -> new Switch null, $3, LOC(4,5) $5
]
Whens: [
o 'When', -> [$1]
o 'Whens When', -> $1.concat $2
]
# An individual **When** clause, with action.
When: [
o 'LEADING_WHEN SimpleArgs Block', -> new SwitchWhen $2, $3
o 'LEADING_WHEN SimpleArgs Block TERMINATOR', -> LOC(1, 3) new SwitchWhen $2, $3
]
# 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.
IfBlock: [
o 'IF Expression Block', -> new If $2, $3, type: $1
o 'IfBlock ELSE IF Expression Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3
]
# The full complement of *if* expressions, including postfix one-liner
# *if* and *unless*.
If: [
o 'IfBlock'
o 'IfBlock ELSE Block', -> $1.addElse $3
o 'Statement POST_IF Expression', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
o 'Expression POST_IF Expression', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
]
IfBlockLine: [
o 'IF ExpressionLine Block', -> new If $2, $3, type: $1
o 'IfBlockLine ELSE IF ExpressionLine Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3
]
IfLine: [
o 'IfBlockLine'
o 'IfBlockLine ELSE Block', -> $1.addElse $3
o 'Statement POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
o 'Expression POST_IF ExpressionLine', -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
]
# 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*
# -type rule, but in order to make the precedence binding possible, separate
# rules are necessary.
OperationLine: [
o 'UNARY ExpressionLine', -> new Op $1, $2
o 'DO ExpressionLine', -> new Op $1, $2
o 'DO_IIFE CodeLine', -> new Op $1, $2
]
Operation: [
o 'UNARY Expression', -> new Op $1.toString(), $2, undefined, undefined, originalOperator: $1.original
o 'DO Expression', -> new Op $1, $2
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 'AWAIT Expression', -> new Op $1, $2
o 'AWAIT INDENT Object OUTDENT', -> new Op $1, $3
o '-- SimpleAssignable', -> new Op '--', $2
o '++ SimpleAssignable', -> new Op '++', $2
o 'SimpleAssignable --', -> new Op '--', $1, null, true
o 'SimpleAssignable ++', -> new Op '++', $1, null, true
# [The existential operator](https://coffeescript.org/#existential-operator).
o 'Expression ?', -> new Existence $1
o 'Expression + Expression', -> new Op '+' , $1, $3
o 'Expression - Expression', -> new Op '-' , $1, $3
o 'Expression MATH Expression', -> new Op $2, $1, $3
o 'Expression ** Expression', -> new Op $2, $1, $3
o 'Expression SHIFT Expression', -> new Op $2, $1, $3
o 'Expression COMPARE Expression', -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original
o 'Expression & Expression', -> new Op $2, $1, $3
o 'Expression ^ Expression', -> new Op $2, $1, $3
o 'Expression | Expression', -> new Op $2, $1, $3
o 'Expression && Expression', -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original
o 'Expression || Expression', -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original
o 'Expression BIN? Expression', -> new Op $2, $1, $3
o 'Expression RELATION Expression', -> new Op $2.toString(), $1, $3, undefined, invertOperator: $2.invert?.original ? $2.invert
o 'SimpleAssignable COMPOUND_ASSIGN
Expression', -> new Assign $1, $3, $2.toString(), originalContext: $2.original
o 'SimpleAssignable COMPOUND_ASSIGN
INDENT Expression OUTDENT', -> new Assign $1, $4, $2.toString(), originalContext: $2.original
o 'SimpleAssignable COMPOUND_ASSIGN TERMINATOR
Expression', -> new Assign $1, $4, $2.toString(), originalContext: $2.original
]
DoIife: [
o 'DO_IIFE Code', -> new Op $1 , $2
]
# Precedence
# ----------
# 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)
#
# And not:
#
# (2 + 3) * 4
operators = [
['right', 'DO_IIFE']
['left', '.', '?.', '::', '?::']
['left', 'CALL_START', 'CALL_END']
['nonassoc', '++', '--']
['left', '?']
['right', 'UNARY', 'DO']
['right', 'AWAIT']
['right', '**']
['right', 'UNARY_MATH']
['left', 'MATH']
['left', '+', '-']
['left', 'SHIFT']
['left', 'RELATION']
['left', 'COMPARE']
['left', '&']
['left', '^']
['left', '|']
['left', '&&']
['left', '||']
['left', 'BIN?']
['nonassoc', 'INDENT', 'OUTDENT']
['right', 'YIELD']
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT']
['left', 'POST_IF']
]
# Wrapping Up
# -----------
# Finally, now that 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 = []
for name, alternatives of grammar
grammar[name] = for alt in alternatives
for token in alt[0].split ' '
tokens.push token unless grammar[token]
alt[1] = "return #{alt[1]}" if name is 'Root'
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](http://dinosaur.compilertools.net/yacc/index.html)).
exports.parser = new Parser
tokens : tokens.join ' '