Fix multiline stab clause with trailing identifier (#20)

This commit is contained in:
Jonatan Kłosko 2021-12-27 22:56:00 +01:00 committed by GitHub
parent 1b3ecf7765
commit 94d6471cc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 185 additions and 62 deletions

View File

@ -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
)
)
),

102
src/grammar.json generated
View File

@ -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": {

16
src/parser.c generated
View File

@ -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),

View File

@ -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
=====================================