Skip to content

Commit 3032cf5

Browse files
mjambonNathan Brahmsmaxbrunsfeld
authored
Optional chaining (#137)
* Add partial support for optional chaining: a?.b and a?.[b] but not f?.(x). * Update generated files * Undo experimental change * Add safe dereference for function calls * fixup! Add safe dereference for function calls * Add failing test case for optional chaining using a proper '?.' token for optional calls. * Simplify parsing of new_expression, avoid ?.( token Co-authored-by: Martin Jambon <Martin Jambon> Co-authored-by: Nathan Brahms <[email protected]> Co-authored-by: Max Brunsfeld <[email protected]>
1 parent feca6ec commit 3032cf5

File tree

5 files changed

+25686
-26455
lines changed

5 files changed

+25686
-26455
lines changed

grammar.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const PREC = {
2020
NEG: 10,
2121
INC: 11,
2222
CALL: 12,
23-
NEW: 13,
23+
NEW: 12,
2424
MEMBER: 14
2525
};
2626

@@ -75,6 +75,7 @@ module.exports = grammar({
7575
[$.assignment_pattern, $.assignment_expression],
7676
[$.computed_property_name, $.array],
7777
[$._for_header, $._expression],
78+
[$.call_expression, $.new_expression],
7879
],
7980

8081
word: $ => $.identifier,
@@ -625,18 +626,19 @@ module.exports = grammar({
625626
),
626627

627628
call_expression: $ => prec(PREC.CALL, seq(
628-
field('function', choice($._expression, $.super, $.function)),
629+
field('function', $._expression),
630+
optional('?.'),
629631
field('arguments', choice($.arguments, $.template_string))
630632
)),
631633

632-
new_expression: $ => prec.right(PREC.NEW, seq(
634+
new_expression: $ => prec(PREC.NEW, seq(
633635
'new',
634-
field('constructor', $._constructable_expression),
635-
field('arguments', optional($.arguments))
636+
field('constructor', $._expression),
637+
field('arguments', optional(prec.dynamic(1, $.arguments)))
636638
)),
637639

638640
_constructable_expression: $ => choice(
639-
// Primary Expression
641+
$.super,
640642
$.this,
641643
$.identifier,
642644
alias($._reserved_identifier, $.identifier),
@@ -668,19 +670,17 @@ module.exports = grammar({
668670
),
669671

670672
member_expression: $ => prec(PREC.MEMBER, seq(
671-
field('object', choice(
672-
$._expression,
673-
$.identifier,
674-
$.super,
675-
alias($._reserved_identifier, $.identifier)
676-
)),
677-
'.',
673+
field('object', $._expression),
674+
choice('.', '?.'),
678675
field('property', alias($.identifier, $.property_identifier))
679676
)),
680677

681678
subscript_expression: $ => prec.right(PREC.MEMBER, seq(
682-
field('object', choice($._expression, $.super)),
683-
'[', field('index', $._expressions), ']'
679+
field('object', $._expression),
680+
optional('?.'),
681+
'[',
682+
field('index', $._expressions),
683+
']'
684684
)),
685685

686686
_lhs_expression: $ => choice(

src/grammar.json

Lines changed: 62 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,23 +2688,22 @@
26882688
"type": "FIELD",
26892689
"name": "function",
26902690
"content": {
2691-
"type": "CHOICE",
2692-
"members": [
2693-
{
2694-
"type": "SYMBOL",
2695-
"name": "_expression"
2696-
},
2697-
{
2698-
"type": "SYMBOL",
2699-
"name": "super"
2700-
},
2701-
{
2702-
"type": "SYMBOL",
2703-
"name": "function"
2704-
}
2705-
]
2691+
"type": "SYMBOL",
2692+
"name": "_expression"
27062693
}
27072694
},
2695+
{
2696+
"type": "CHOICE",
2697+
"members": [
2698+
{
2699+
"type": "STRING",
2700+
"value": "?."
2701+
},
2702+
{
2703+
"type": "BLANK"
2704+
}
2705+
]
2706+
},
27082707
{
27092708
"type": "FIELD",
27102709
"name": "arguments",
@@ -2726,8 +2725,8 @@
27262725
}
27272726
},
27282727
"new_expression": {
2729-
"type": "PREC_RIGHT",
2730-
"value": 13,
2728+
"type": "PREC",
2729+
"value": 12,
27312730
"content": {
27322731
"type": "SEQ",
27332732
"members": [
@@ -2740,7 +2739,7 @@
27402739
"name": "constructor",
27412740
"content": {
27422741
"type": "SYMBOL",
2743-
"name": "_constructable_expression"
2742+
"name": "_expression"
27442743
}
27452744
},
27462745
{
@@ -2750,8 +2749,12 @@
27502749
"type": "CHOICE",
27512750
"members": [
27522751
{
2753-
"type": "SYMBOL",
2754-
"name": "arguments"
2752+
"type": "PREC_DYNAMIC",
2753+
"value": 1,
2754+
"content": {
2755+
"type": "SYMBOL",
2756+
"name": "arguments"
2757+
}
27552758
},
27562759
{
27572760
"type": "BLANK"
@@ -2765,6 +2768,10 @@
27652768
"_constructable_expression": {
27662769
"type": "CHOICE",
27672770
"members": [
2771+
{
2772+
"type": "SYMBOL",
2773+
"name": "super"
2774+
},
27682775
{
27692776
"type": "SYMBOL",
27702777
"name": "this"
@@ -2887,35 +2894,22 @@
28872894
"type": "FIELD",
28882895
"name": "object",
28892896
"content": {
2890-
"type": "CHOICE",
2891-
"members": [
2892-
{
2893-
"type": "SYMBOL",
2894-
"name": "_expression"
2895-
},
2896-
{
2897-
"type": "SYMBOL",
2898-
"name": "identifier"
2899-
},
2900-
{
2901-
"type": "SYMBOL",
2902-
"name": "super"
2903-
},
2904-
{
2905-
"type": "ALIAS",
2906-
"content": {
2907-
"type": "SYMBOL",
2908-
"name": "_reserved_identifier"
2909-
},
2910-
"named": true,
2911-
"value": "identifier"
2912-
}
2913-
]
2897+
"type": "SYMBOL",
2898+
"name": "_expression"
29142899
}
29152900
},
29162901
{
2917-
"type": "STRING",
2918-
"value": "."
2902+
"type": "CHOICE",
2903+
"members": [
2904+
{
2905+
"type": "STRING",
2906+
"value": "."
2907+
},
2908+
{
2909+
"type": "STRING",
2910+
"value": "?."
2911+
}
2912+
]
29192913
},
29202914
{
29212915
"type": "FIELD",
@@ -2943,19 +2937,22 @@
29432937
"type": "FIELD",
29442938
"name": "object",
29452939
"content": {
2946-
"type": "CHOICE",
2947-
"members": [
2948-
{
2949-
"type": "SYMBOL",
2950-
"name": "_expression"
2951-
},
2952-
{
2953-
"type": "SYMBOL",
2954-
"name": "super"
2955-
}
2956-
]
2940+
"type": "SYMBOL",
2941+
"name": "_expression"
29572942
}
29582943
},
2944+
{
2945+
"type": "CHOICE",
2946+
"members": [
2947+
{
2948+
"type": "STRING",
2949+
"value": "?."
2950+
},
2951+
{
2952+
"type": "BLANK"
2953+
}
2954+
]
2955+
},
29592956
{
29602957
"type": "STRING",
29612958
"value": "["
@@ -4514,7 +4511,7 @@
45144511
},
45154512
{
45164513
"type": "PATTERN",
4517-
"value": "[^*]*\\*+([^\\/*][^*]*\\*+)*"
4514+
"value": "[^*]*\\*+([^/*][^*]*\\*+)*"
45184515
},
45194516
{
45204517
"type": "STRING",
@@ -4676,7 +4673,7 @@
46764673
},
46774674
{
46784675
"type": "PATTERN",
4679-
"value": "[^\\/\\\\\\[\\n]"
4676+
"value": "[^/\\\\\\[\\n]"
46804677
}
46814678
]
46824679
}
@@ -5185,13 +5182,13 @@
51855182
"members": [
51865183
{
51875184
"type": "PATTERN",
5188-
"value": "[^\\x00-\\x1F\\s0-9:;`\"'@#.,|^&<=>+\\-*\\/\\\\%?!~()\\[\\]{}\\uFEFF\\u2060\\u200B\\u00A0]|\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}"
5185+
"value": "[^\\x00-\\x1F\\s0-9:;`\"'@#.,|^&<=>+\\-*/\\\\%?!~()\\[\\]{}\\uFEFF\\u2060\\u200B\\u00A0]|\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}"
51895186
},
51905187
{
51915188
"type": "REPEAT",
51925189
"content": {
51935190
"type": "PATTERN",
5194-
"value": "[^\\x00-\\x1F\\s:;`\"'@#.,|^&<=>+\\-*\\/\\\\%?!~()\\[\\]{}\\uFEFF\\u2060\\u200B\\u00A0]|\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}"
5191+
"value": "[^\\x00-\\x1F\\s:;`\"'@#.,|^&<=>+\\-*/\\\\%?!~()\\[\\]{}\\uFEFF\\u2060\\u200B\\u00A0]|\\\\u[0-9a-fA-F]{4}|\\\\u\\{[0-9a-fA-F]+\\}"
51955192
}
51965193
}
51975194
]
@@ -5930,6 +5927,10 @@
59305927
[
59315928
"_for_header",
59325929
"_expression"
5930+
],
5931+
[
5932+
"call_expression",
5933+
"new_expression"
59335934
]
59345935
],
59355936
"externals": [

0 commit comments

Comments
 (0)