From 94d6471cc8cdfaf2808f6079036ded44a308db41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Mon, 27 Dec 2021 22:56:00 +0100 Subject: [PATCH] Fix multiline stab clause with trailing identifier (#20) --- grammar.js | 21 ++++++-- src/grammar.json | 102 +++++++++++++++++++------------------- src/parser.c | 16 +++--- test/corpus/do_end.txt | 108 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 62 deletions(-) diff --git a/grammar.js b/grammar.js index f7cc50a..6bd3f61 100644 --- a/grammar.js +++ b/grammar.js @@ -672,11 +672,22 @@ module.exports = grammar({ ), _call_arguments_without_parentheses: ($) => - // Right precedence, because `fun1 fun2 x, y` is `fun1(fun2(x, y))` - prec.right( - choice( - seq(sep1($._expression, ","), optional(seq(",", $.keywords))), - $.keywords + // In stab clauses a newline can either separate multiple body expressions + // or multiple stab clauses, this falls under the $.body conflict. Given a + // multiline stab clause with trailing identifier like `1 -> 1 \n x \n 2 -> x`, + // there are two matching interpretations: + // * `x` as identifier and `2` as stab argument + // * `x 2` call as stab argument + // Similarly for `Mod.fun` or `mod.fun` the newline should terminate the call. + // Consequently, we reject the second interpretation using dynamic precedence + prec.dynamic( + -1, + // Right precedence, because `fun1 fun2 x, y` is `fun1(fun2(x, y))` + prec.right( + choice( + seq(sep1($._expression, ","), optional(seq(",", $.keywords))), + $.keywords + ) ) ), diff --git a/src/grammar.json b/src/grammar.json index 50559d5..4806dda 100644 --- a/src/grammar.json +++ b/src/grammar.json @@ -4791,24 +4791,46 @@ ] }, "_call_arguments_without_parentheses": { - "type": "PREC_RIGHT", - "value": 0, + "type": "PREC_DYNAMIC", + "value": -1, "content": { - "type": "CHOICE", - "members": [ - { - "type": "SEQ", - "members": [ - { - "type": "SEQ", - "members": [ - { - "type": "SYMBOL", - "name": "_expression" - }, - { - "type": "REPEAT", - "content": { + "type": "PREC_RIGHT", + "value": 0, + "content": { + "type": "CHOICE", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "_expression" + }, + { + "type": "REPEAT", + "content": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "," + }, + { + "type": "SYMBOL", + "name": "_expression" + } + ] + } + } + ] + }, + { + "type": "CHOICE", + "members": [ + { "type": "SEQ", "members": [ { @@ -4817,41 +4839,23 @@ }, { "type": "SYMBOL", - "name": "_expression" + "name": "keywords" } ] + }, + { + "type": "BLANK" } - } - ] - }, - { - "type": "CHOICE", - "members": [ - { - "type": "SEQ", - "members": [ - { - "type": "STRING", - "value": "," - }, - { - "type": "SYMBOL", - "name": "keywords" - } - ] - }, - { - "type": "BLANK" - } - ] - } - ] - }, - { - "type": "SYMBOL", - "name": "keywords" - } - ] + ] + } + ] + }, + { + "type": "SYMBOL", + "name": "keywords" + } + ] + } } }, "do_block": { diff --git a/src/parser.c b/src/parser.c index 769fef3..f4f42ec 100644 --- a/src/parser.c +++ b/src/parser.c @@ -380813,8 +380813,8 @@ static const TSParseActionEntry ts_parse_actions[] = { [3028] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym__items_with_trailing_separator_repeat1, 2), [3030] = {.entry = {.count = 1, .reusable = false}}, REDUCE(aux_sym__items_with_trailing_separator_repeat1, 2), [3032] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym__items_with_trailing_separator_repeat1, 2), SHIFT_REPEAT(741), - [3035] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 2), - [3037] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 2), + [3035] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 2, .dynamic_precedence = -1), + [3037] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 2, .dynamic_precedence = -1), [3039] = {.entry = {.count = 1, .reusable = false}}, SHIFT(315), [3041] = {.entry = {.count = 1, .reusable = true}}, SHIFT(5471), [3043] = {.entry = {.count = 1, .reusable = true}}, SHIFT(5469), @@ -380961,8 +380961,8 @@ static const TSParseActionEntry ts_parse_actions[] = { [3325] = {.entry = {.count = 1, .reusable = false}}, SHIFT(1257), [3327] = {.entry = {.count = 1, .reusable = false}}, SHIFT(1256), [3329] = {.entry = {.count = 1, .reusable = false}}, SHIFT(1253), - [3331] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 1), - [3333] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 1), + [3331] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 1, .dynamic_precedence = -1), + [3333] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 1, .dynamic_precedence = -1), [3335] = {.entry = {.count = 1, .reusable = false}}, SHIFT(443), [3337] = {.entry = {.count = 1, .reusable = false}}, SHIFT(337), [3339] = {.entry = {.count = 1, .reusable = false}}, SHIFT(630), @@ -381019,10 +381019,10 @@ static const TSParseActionEntry ts_parse_actions[] = { [3442] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_block, 6), [3444] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_block, 6), [3446] = {.entry = {.count = 1, .reusable = false}}, SHIFT(1245), - [3448] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 4), - [3450] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 4), - [3452] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 3), - [3454] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 3), + [3448] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 4, .dynamic_precedence = -1), + [3450] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 4, .dynamic_precedence = -1), + [3452] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__call_arguments_without_parentheses, 3, .dynamic_precedence = -1), + [3454] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym__call_arguments_without_parentheses, 3, .dynamic_precedence = -1), [3456] = {.entry = {.count = 1, .reusable = false}}, SHIFT(1497), [3458] = {.entry = {.count = 1, .reusable = false}}, SHIFT(309), [3460] = {.entry = {.count = 1, .reusable = false}}, SHIFT(1500), diff --git a/test/corpus/do_end.txt b/test/corpus/do_end.txt index 588a22d..8fc1527 100644 --- a/test/corpus/do_end.txt +++ b/test/corpus/do_end.txt @@ -575,6 +575,114 @@ fun do->end (do_block (stab_clause)))) + +===================================== +stab clause / edge cases / trailing call in multiline clause +===================================== + +fun do + 1 -> + 1 + x + + 1 -> + 1 +end + +fun do + 1 -> + 1 + Mod.fun + + 1 -> + 1 +end + +fun do + 1 -> + 1 + mod.fun + + 1 -> + 1 +end + +fun do + 1 -> + 1 + + x 1 -> + 1 +end + +--- + +(source + (call + (identifier) + (do_block + (stab_clause + (arguments + (integer)) + (body + (integer) + (identifier))) + (stab_clause + (arguments + (integer)) + (body + (integer))))) + (call + (identifier) + (do_block + (stab_clause + (arguments + (integer)) + (body + (integer) + (call + (dot + (alias) + (identifier))))) + (stab_clause + (arguments + (integer)) + (body + (integer))))) + (call + (identifier) + (do_block + (stab_clause + (arguments + (integer)) + (body + (integer) + (call + (dot + (identifier) + (identifier))))) + (stab_clause + (arguments + (integer)) + (body + (integer))))) + (call + (identifier) + (do_block + (stab_clause + (arguments + (integer)) + (body + (integer))) + (stab_clause + (arguments + (call + (identifier) + (arguments + (integer)))) + (body + (integer)))))) + ===================================== pattern matching =====================================