Skip to content

Commit fef0019

Browse files
committed
Track the then keyword for conditionals
1 parent 9f94f39 commit fef0019

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+176
-11
lines changed

config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,8 @@ nodes:
13851385
type: location?
13861386
- name: predicate
13871387
type: node
1388+
- name: then_keyword_loc
1389+
type: location?
13881390
- name: statements
13891391
type: node?
13901392
kind: StatementsNode
@@ -2446,6 +2448,8 @@ nodes:
24462448
type: location
24472449
- name: predicate
24482450
type: node
2451+
- name: then_keyword_loc
2452+
type: location?
24492453
- name: statements
24502454
type: node?
24512455
kind: StatementsNode

lib/prism/desugar_compiler.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ def desugar_or_write_defined_node(node, read_class, write_class, *arguments)
188188
IfNode.new(
189189
node.operator_loc,
190190
DefinedNode.new(nil, read_class.new(*arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
191+
node.operator_loc,
191192
StatementsNode.new([read_class.new(*arguments, node.name_loc)], node.location),
192193
ElseNode.new(
193194
node.operator_loc,

src/prism.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3206,6 +3206,7 @@ static pm_if_node_t *
32063206
pm_if_node_create(pm_parser_t *parser,
32073207
const pm_token_t *if_keyword,
32083208
pm_node_t *predicate,
3209+
const pm_token_t *then_keyword,
32093210
pm_statements_node_t *statements,
32103211
pm_node_t *consequent,
32113212
const pm_token_t *end_keyword
@@ -3235,6 +3236,7 @@ pm_if_node_create(pm_parser_t *parser,
32353236
},
32363237
.if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
32373238
.predicate = predicate,
3239+
.then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
32383240
.statements = statements,
32393241
.consequent = consequent,
32403242
.end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
@@ -3265,6 +3267,7 @@ pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_t
32653267
},
32663268
.if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
32673269
.predicate = predicate,
3270+
.then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
32683271
.statements = statements,
32693272
.consequent = NULL,
32703273
.end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
@@ -3277,7 +3280,7 @@ pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_t
32773280
* Allocate and initialize an if node from a ternary expression.
32783281
*/
32793282
static pm_if_node_t *
3280-
pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
3283+
pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
32813284
pm_assert_value_expression(parser, predicate);
32823285
pm_conditional_predicate(predicate);
32833286

@@ -3303,6 +3306,7 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, pm_node_t *
33033306
},
33043307
.if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
33053308
.predicate = predicate,
3309+
.then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
33063310
.statements = if_statements,
33073311
.consequent = (pm_node_t *)else_node,
33083312
.end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
@@ -5348,7 +5352,7 @@ pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
53485352
* Allocate a new UnlessNode node.
53495353
*/
53505354
static pm_unless_node_t *
5351-
pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements) {
5355+
pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, const pm_token_t *then_keyword, pm_statements_node_t *statements) {
53525356
pm_conditional_predicate(predicate);
53535357
pm_unless_node_t *node = PM_ALLOC_NODE(parser, pm_unless_node_t);
53545358

@@ -5370,6 +5374,7 @@ pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t
53705374
},
53715375
.keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
53725376
.predicate = predicate,
5377+
.then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
53735378
.statements = statements,
53745379
.consequent = NULL,
53755380
.end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
@@ -5400,6 +5405,7 @@ pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const
54005405
},
54015406
.keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
54025407
.predicate = predicate,
5408+
.then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
54035409
.statements = statements,
54045410
.consequent = NULL,
54055411
.end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
@@ -11839,14 +11845,19 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept
1183911845
}
1184011846

1184111847
static inline pm_node_t *
11842-
parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context) {
11848+
parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword) {
1184311849
context_push(parser, PM_CONTEXT_PREDICATE);
1184411850
pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
1184511851
pm_node_t *predicate = parse_value_expression(parser, binding_power, error_id);
1184611852

1184711853
// Predicates are closed by a term, a "then", or a term and then a "then".
1184811854
bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
11849-
predicate_closed |= accept1(parser, PM_TOKEN_KEYWORD_THEN);
11855+
11856+
if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
11857+
predicate_closed = true;
11858+
*then_keyword = parser->previous;
11859+
}
11860+
1185011861
if (!predicate_closed) {
1185111862
pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
1185211863
}
@@ -11858,7 +11869,9 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex
1185811869
static inline pm_node_t *
1185911870
parse_conditional(pm_parser_t *parser, pm_context_t context) {
1186011871
pm_token_t keyword = parser->previous;
11861-
pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context);
11872+
pm_token_t then_keyword = not_provided(parser);
11873+
11874+
pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword);
1186211875
pm_statements_node_t *statements = NULL;
1186311876

1186411877
if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
@@ -11873,10 +11886,10 @@ parse_conditional(pm_parser_t *parser, pm_context_t context) {
1187311886

1187411887
switch (context) {
1187511888
case PM_CONTEXT_IF:
11876-
parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, statements, NULL, &end_keyword);
11889+
parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
1187711890
break;
1187811891
case PM_CONTEXT_UNLESS:
11879-
parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, statements);
11892+
parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
1188011893
break;
1188111894
default:
1188211895
assert(false && "unreachable");
@@ -11890,14 +11903,14 @@ parse_conditional(pm_parser_t *parser, pm_context_t context) {
1189011903
if (context == PM_CONTEXT_IF) {
1189111904
while (accept1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
1189211905
pm_token_t elsif_keyword = parser->previous;
11893-
pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF);
11906+
pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword);
1189411907
pm_accepts_block_stack_push(parser, true);
1189511908
pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF);
1189611909
pm_accepts_block_stack_pop(parser);
1189711910

1189811911
accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
1189911912

11900-
pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, statements, NULL, &end_keyword);
11913+
pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
1190111914
((pm_if_node_t *) current)->consequent = elsif;
1190211915
current = elsif;
1190311916
}
@@ -16179,6 +16192,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
1617916192
return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
1618016193
}
1618116194
case PM_TOKEN_QUESTION_MARK: {
16195+
pm_token_t qmark = parser->current;
1618216196
parser_lex(parser);
1618316197
pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_TRUE);
1618416198

@@ -16192,7 +16206,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
1619216206
pm_token_t colon = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
1619316207
pm_node_t *false_expression = (pm_node_t *) pm_missing_node_create(parser, colon.start, colon.end);
1619416208

16195-
return (pm_node_t *) pm_if_node_ternary_create(parser, node, true_expression, &colon, false_expression);
16209+
return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
1619616210
}
1619716211

1619816212
accept1(parser, PM_TOKEN_NEWLINE);
@@ -16201,7 +16215,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
1620116215
pm_token_t colon = parser->previous;
1620216216
pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_FALSE);
1620316217

16204-
return (pm_node_t *) pm_if_node_ternary_create(parser, node, true_expression, &colon, false_expression);
16218+
return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
1620516219
}
1620616220
case PM_TOKEN_COLON_COLON: {
1620716221
parser_lex(parser);

test/prism/snapshots/endless_range_in_conditional.txt

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/prism/snapshots/if.txt

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/prism/snapshots/method_calls.txt

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/prism/snapshots/methods.txt

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)