Repository: ruby/prism
Pull request #1841 (2023-11-15 22:55:48)

Track the then keyword for conditionals


Patch:
diff --git a/config.yml b/config.yml
index bd5afc7d..6f12a513 100644
--- a/config.yml
+++ b/config.yml
@@ -1385,6 +1385,8 @@ nodes:
         type: location?
       - name: predicate
         type: node
+      - name: then_keyword_loc
+        type: location?
       - name: statements
         type: node?
         kind: StatementsNode
@@ -2446,6 +2448,8 @@ nodes:
         type: location
       - name: predicate
         type: node
+      - name: then_keyword_loc
+        type: location?
       - name: statements
         type: node?
         kind: StatementsNode
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
index 36242176..1fba3706 100644
--- a/lib/prism/desugar_compiler.rb
+++ b/lib/prism/desugar_compiler.rb
@@ -188,6 +188,7 @@ module Prism
       IfNode.new(
         node.operator_loc,
         DefinedNode.new(nil, read_class.new(*arguments, node.name_loc), nil, node.operator_loc, node.name_loc),
+        node.operator_loc,
         StatementsNode.new([read_class.new(*arguments, node.name_loc)], node.location),
         ElseNode.new(
           node.operator_loc,
diff --git a/src/prism.c b/src/prism.c
index c98062f4..17051e23 100644
--- a/src/prism.c
+++ b/src/prism.c
@@ -3206,6 +3206,7 @@ static pm_if_node_t *
 pm_if_node_create(pm_parser_t *parser,
     const pm_token_t *if_keyword,
     pm_node_t *predicate,
+    const pm_token_t *then_keyword,
     pm_statements_node_t *statements,
     pm_node_t *consequent,
     const pm_token_t *end_keyword
@@ -3235,6 +3236,7 @@ pm_if_node_create(pm_parser_t *parser,
         },
         .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
         .predicate = predicate,
+        .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
         .statements = statements,
         .consequent = consequent,
         .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
         },
         .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
         .predicate = predicate,
+        .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
         .statements = statements,
         .consequent = NULL,
         .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
  * Allocate and initialize an if node from a ternary expression.
  */
 static pm_if_node_t *
-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) {
+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) {
     pm_assert_value_expression(parser, predicate);
     pm_conditional_predicate(predicate);
 
@@ -3303,6 +3306,7 @@ pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, pm_node_t *
         },
         .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
         .predicate = predicate,
+        .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
         .statements = if_statements,
         .consequent = (pm_node_t *)else_node,
         .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) {
  * Allocate a new UnlessNode node.
  */
 static pm_unless_node_t *
-pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements) {
+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) {
     pm_conditional_predicate(predicate);
     pm_unless_node_t *node = PM_ALLOC_NODE(parser, pm_unless_node_t);
 
@@ -5370,6 +5374,7 @@ pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t
         },
         .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
         .predicate = predicate,
+        .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
         .statements = statements,
         .consequent = NULL,
         .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
         },
         .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
         .predicate = predicate,
+        .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
         .statements = statements,
         .consequent = NULL,
         .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
 }
 
 static inline pm_node_t *
-parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context) {
+parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword) {
     context_push(parser, PM_CONTEXT_PREDICATE);
     pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
     pm_node_t *predicate = parse_value_expression(parser, binding_power, error_id);
 
     // Predicates are closed by a term, a "then", or a term and then a "then".
     bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-    predicate_closed |= accept1(parser, PM_TOKEN_KEYWORD_THEN);
+
+    if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
+        predicate_closed = true;
+        *then_keyword = parser->previous;
+    }
+
     if (!predicate_closed) {
         pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
     }
@@ -11858,7 +11869,9 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex
 static inline pm_node_t *
 parse_conditional(pm_parser_t *parser, pm_context_t context) {
     pm_token_t keyword = parser->previous;
-    pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context);
+    pm_token_t then_keyword = not_provided(parser);
+
+    pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword);
     pm_statements_node_t *statements = NULL;
 
     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) {
 
     switch (context) {
         case PM_CONTEXT_IF:
-            parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, statements, NULL, &end_keyword);
+            parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
             break;
         case PM_CONTEXT_UNLESS:
-            parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, statements);
+            parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
             break;
         default:
             assert(false && "unreachable");
@@ -11890,14 +11903,14 @@ parse_conditional(pm_parser_t *parser, pm_context_t context) {
     if (context == PM_CONTEXT_IF) {
         while (accept1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
             pm_token_t elsif_keyword = parser->previous;
-            pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF);
+            pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword);
             pm_accepts_block_stack_push(parser, true);
             pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF);
             pm_accepts_block_stack_pop(parser);
 
             accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
 
-            pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, statements, NULL, &end_keyword);
+            pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
             ((pm_if_node_t *) current)->consequent = elsif;
             current = elsif;
         }
@@ -16179,6 +16192,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
             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);
         }
         case PM_TOKEN_QUESTION_MARK: {
+            pm_token_t qmark = parser->current;
             parser_lex(parser);
             pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_TRUE);
 
@@ -16192,7 +16206,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
                 pm_token_t colon = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
                 pm_node_t *false_expression = (pm_node_t *) pm_missing_node_create(parser, colon.start, colon.end);
 
-                return (pm_node_t *) pm_if_node_ternary_create(parser, node, true_expression, &colon, false_expression);
+                return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
             }
 
             accept1(parser, PM_TOKEN_NEWLINE);
@@ -16201,7 +16215,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
             pm_token_t colon = parser->previous;
             pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, PM_ERR_TERNARY_EXPRESSION_FALSE);
 
-            return (pm_node_t *) pm_if_node_ternary_create(parser, node, true_expression, &colon, false_expression);
+            return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
         }
         case PM_TOKEN_COLON_COLON: {
             parser_lex(parser);


Test patch:
diff --git a/test/prism/snapshots/endless_range_in_conditional.txt b/test/prism/snapshots/endless_range_in_conditional.txt
index 27447e95..2c13dc28 100644
--- a/test/prism/snapshots/endless_range_in_conditional.txt
+++ b/test/prism/snapshots/endless_range_in_conditional.txt
@@ -15,6 +15,7 @@
         │   │   │   └── flags: decimal
         │   │   ├── operator_loc: (1,4)-(1,6) = ".."
         │   │   └── flags: ∅
+        │   ├── then_keyword_loc: ∅
         │   ├── statements: ∅
         │   ├── consequent: ∅
         │   └── end_keyword_loc: (1,10)-(1,13) = "end"
@@ -28,6 +29,7 @@
         │   │   │   └── flags: decimal
         │   │   ├── operator_loc: (2,3)-(2,5) = ".."
         │   │   └── flags: ∅
+        │   ├── then_keyword_loc: ∅
         │   ├── statements: ∅
         │   ├── consequent: ∅
         │   └── end_keyword_loc: (2,9)-(2,12) = "end"
@@ -41,6 +43,7 @@
             │   ├── right: ∅
             │   ├── operator_loc: (3,4)-(3,6) = ".."
             │   └── flags: ∅
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (3,9)-(3,12) = "end"
diff --git a/test/prism/snapshots/if.txt b/test/prism/snapshots/if.txt
index 645870fe..50e4116d 100644
--- a/test/prism/snapshots/if.txt
+++ b/test/prism/snapshots/if.txt
@@ -7,6 +7,7 @@
         │   ├── if_keyword_loc: (1,0)-(1,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (1,3)-(1,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,9)-(1,10))
         │   │   └── body: (length: 1)
@@ -18,6 +19,7 @@
         │   ├── if_keyword_loc: (3,0)-(3,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (3,3)-(3,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (4,0)-(4,1))
         │   │   └── body: (length: 1)
@@ -37,6 +39,7 @@
         │   ├── if_keyword_loc: (6,0)-(6,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (6,3)-(6,7))
+        │   ├── then_keyword_loc: (6,8)-(6,12) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (6,13)-(6,17))
         │   │   └── body: (length: 1)
@@ -46,6 +49,7 @@
         │   │   ├── if_keyword_loc: (6,18)-(6,23) = "elsif"
         │   │   ├── predicate:
         │   │   │   @ FalseNode (location: (6,24)-(6,29))
+        │   │   ├── then_keyword_loc: (6,30)-(6,34) = "then"
         │   │   ├── statements:
         │   │   │   @ StatementsNode (location: (6,35)-(6,40))
         │   │   │   └── body: (length: 1)
@@ -55,6 +59,7 @@
         │   │   │   ├── if_keyword_loc: (6,41)-(6,46) = "elsif"
         │   │   │   ├── predicate:
         │   │   │   │   @ NilNode (location: (6,47)-(6,50))
+        │   │   │   ├── then_keyword_loc: (6,51)-(6,55) = "then"
         │   │   │   ├── statements:
         │   │   │   │   @ StatementsNode (location: (6,56)-(6,59))
         │   │   │   │   └── body: (length: 1)
@@ -74,6 +79,7 @@
         │   ├── if_keyword_loc: (8,2)-(8,4) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (8,5)-(8,9))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (8,0)-(8,1))
         │   │   └── body: (length: 1)
@@ -85,6 +91,7 @@
         │   ├── if_keyword_loc: (10,6)-(10,8) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (10,9)-(10,13))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (10,0)-(10,5))
         │   │   └── body: (length: 1)
@@ -97,6 +104,7 @@
         │   ├── if_keyword_loc: (12,5)-(12,7) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (12,8)-(12,12))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (12,0)-(12,4))
         │   │   └── body: (length: 1)
@@ -109,6 +117,7 @@
         │   ├── if_keyword_loc: (14,7)-(14,9) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (14,10)-(14,14))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (14,0)-(14,6))
         │   │   └── body: (length: 1)
@@ -130,6 +139,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :exit_loop
+        │   ├── then_keyword_loc: (16,13)-(16,17) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (16,18)-(16,26))
         │   │   └── body: (length: 1)
@@ -156,6 +166,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: (19,0)-(19,4) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (19,5)-(19,8))
         │   │   └── body: (length: 1)
@@ -184,6 +195,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :c
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (22,0)-(22,6))
         │   │   └── body: (length: 1)
@@ -200,6 +212,7 @@
         │   │           │   ├── block: ∅
         │   │           │   ├── flags: variable_call
         │   │           │   └── name: :b
+        │   │           ├── then_keyword_loc: ∅
         │   │           ├── statements:
         │   │           │   @ StatementsNode (location: (22,0)-(22,1))
         │   │           │   └── body: (length: 1)
@@ -221,6 +234,7 @@
         │   ├── if_keyword_loc: (24,0)-(24,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (24,3)-(24,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (25,2)-(25,6))
         │   │   └── body: (length: 1)
@@ -285,6 +299,7 @@
         │   │   │   @ IntegerNode (location: (29,11)-(29,12))
         │   │   │   └── flags: decimal
         │   │   └── operator_loc: (29,8)-(29,10) = "in"
+        │   ├── then_keyword_loc: ∅
         │   ├── statements: ∅
         │   ├── consequent:
         │   │   @ IfNode (location: (30,0)-(31,3))
@@ -306,6 +321,7 @@
         │   │   │   │   @ ConstantReadNode (location: (30,14)-(30,15))
         │   │   │   │   └── name: :B
         │   │   │   └── operator_loc: (30,11)-(30,13) = "in"
+        │   │   ├── then_keyword_loc: ∅
         │   │   ├── statements: ∅
         │   │   ├── consequent: ∅
         │   │   └── end_keyword_loc: (31,0)-(31,3) = "end"
@@ -315,6 +331,7 @@
             ├── predicate:
             │   @ IntegerNode (location: (33,3)-(33,4))
             │   └── flags: decimal
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (34,2)-(35,5))
             │   └── body: (length: 1)
@@ -355,6 +372,7 @@
             │   ├── predicate:
             │   │   @ IntegerNode (location: (36,6)-(36,7))
             │   │   └── flags: decimal
+            │   ├── then_keyword_loc: ∅
             │   ├── statements:
             │   │   @ StatementsNode (location: (37,2)-(38,5))
             │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/method_calls.txt b/test/prism/snapshots/method_calls.txt
index 7981b504..0f77a9f8 100644
--- a/test/prism/snapshots/method_calls.txt
+++ b/test/prism/snapshots/method_calls.txt
@@ -688,6 +688,7 @@
         │   │   │   ├── flags: variable_call
         │   │   │   └── name: :qux
         │   │   └── operator_loc: (51,26)-(51,29) = "and"
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (51,0)-(51,10))
         │   │   └── body: (length: 1)
@@ -1835,6 +1836,7 @@
         │   │   │       │   ├── block: ∅
         │   │   │       │   ├── flags: variable_call
         │   │   │       │   └── name: :x
+        │   │   │       ├── then_keyword_loc: ∅
         │   │   │       ├── statements:
         │   │   │       │   @ StatementsNode (location: (121,4)-(123,7))
         │   │   │       │   └── body: (length: 1)
diff --git a/test/prism/snapshots/methods.txt b/test/prism/snapshots/methods.txt
index 4bc8fead..ce23a282 100644
--- a/test/prism/snapshots/methods.txt
+++ b/test/prism/snapshots/methods.txt
@@ -773,6 +773,7 @@
         │   │       │   ├── if_keyword_loc: (99,11)-(99,13) = "if"
         │   │       │   ├── predicate:
         │   │       │   │   @ TrueNode (location: (99,14)-(99,18))
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (99,0)-(99,10))
         │   │       │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/patterns.txt b/test/prism/snapshots/patterns.txt
index d8f4935b..0e8c31c8 100644
--- a/test/prism/snapshots/patterns.txt
+++ b/test/prism/snapshots/patterns.txt
@@ -3466,6 +3466,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (154,20)-(154,23))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (154,13)-(154,16))
         │   │       │   │   └── body: (length: 1)
@@ -3501,6 +3502,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (155,18)-(155,21))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (155,13)-(155,14))
         │   │       │   │   └── body: (length: 1)
@@ -3535,6 +3537,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (156,20)-(156,23))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (156,13)-(156,16))
         │   │       │   │   └── body: (length: 1)
@@ -3568,6 +3571,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (157,19)-(157,22))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (157,13)-(157,15))
         │   │       │   │   └── body: (length: 1)
@@ -3604,6 +3608,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (158,19)-(158,22))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (158,13)-(158,15))
         │   │       │   │   └── body: (length: 1)
@@ -3640,6 +3645,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (159,21)-(159,24))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (159,13)-(159,17))
         │   │       │   │   └── body: (length: 1)
@@ -3677,6 +3683,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (160,24)-(160,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (160,13)-(160,20))
         │   │       │   │   └── body: (length: 1)
@@ -3714,6 +3721,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (161,23)-(161,26))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (161,13)-(161,19))
         │   │       │   │   └── body: (length: 1)
@@ -3751,6 +3759,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (162,22)-(162,25))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (162,13)-(162,18))
         │   │       │   │   └── body: (length: 1)
@@ -3789,6 +3798,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (163,22)-(163,25))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (163,13)-(163,18))
         │   │       │   │   └── body: (length: 1)
@@ -3826,6 +3836,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (164,24)-(164,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (164,13)-(164,20))
         │   │       │   │   └── body: (length: 1)
@@ -3863,6 +3874,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (165,24)-(165,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (165,13)-(165,20))
         │   │       │   │   └── body: (length: 1)
@@ -3904,6 +3916,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (166,24)-(166,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (166,13)-(166,20))
         │   │       │   │   └── body: (length: 1)
@@ -3945,6 +3958,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (167,24)-(167,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (167,13)-(167,20))
         │   │       │   │   └── body: (length: 1)
@@ -3987,6 +4001,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (168,24)-(168,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (168,13)-(168,20))
         │   │       │   │   └── body: (length: 1)
@@ -4029,6 +4044,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (169,24)-(169,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (169,13)-(169,20))
         │   │       │   │   └── body: (length: 1)
@@ -4067,6 +4083,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (170,24)-(170,27))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (170,13)-(170,20))
         │   │       │   │   └── body: (length: 1)
@@ -4105,6 +4122,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (171,22)-(171,25))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (171,13)-(171,18))
         │   │       │   │   └── body: (length: 1)
@@ -4143,6 +4161,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (172,20)-(172,23))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (172,13)-(172,16))
         │   │       │   │   └── body: (length: 1)
@@ -4176,6 +4195,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (173,21)-(173,24))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (173,13)-(173,17))
         │   │       │   │   └── body: (length: 1)
@@ -4209,6 +4229,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (174,21)-(174,24))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (174,13)-(174,17))
         │   │       │   │   └── body: (length: 1)
@@ -4242,6 +4263,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (175,22)-(175,25))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (175,13)-(175,18))
         │   │       │   │   └── body: (length: 1)
@@ -4275,6 +4297,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (176,25)-(176,28))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (176,13)-(176,21))
         │   │       │   │   └── body: (length: 1)
@@ -4309,6 +4332,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (177,25)-(177,28))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (177,13)-(177,21))
         │   │       │   │   └── body: (length: 1)
@@ -4342,6 +4366,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (178,29)-(178,32))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (178,13)-(178,25))
         │   │       │   │   └── body: (length: 1)
@@ -4375,6 +4400,7 @@
         │   │       │   │   @ LocalVariableReadNode (location: (179,27)-(179,30))
         │   │       │   │   ├── name: :baz
         │   │       │   │   └── depth: 0
+        │   │       │   ├── then_keyword_loc: ∅
         │   │       │   ├── statements:
         │   │       │   │   @ StatementsNode (location: (179,13)-(179,23))
         │   │       │   │   └── body: (length: 1)
@@ -4422,6 +4448,7 @@
         │   │   │   ├── opening_loc: (181,8)-(181,9) = "["
         │   │   │   └── closing_loc: (181,9)-(181,10) = "]"
         │   │   └── operator_loc: (181,5)-(181,7) = "in"
+        │   ├── then_keyword_loc: ∅
         │   ├── statements: ∅
         │   ├── consequent: ∅
         │   └── end_keyword_loc: (182,0)-(182,3) = "end"
diff --git a/test/prism/snapshots/rescue.txt b/test/prism/snapshots/rescue.txt
index a4cd6c1b..0574af2f 100644
--- a/test/prism/snapshots/rescue.txt
+++ b/test/prism/snapshots/rescue.txt
@@ -96,6 +96,7 @@
         │       ├── if_keyword_loc: ∅
         │       ├── predicate:
         │       │   @ NilNode (location: (14,11)-(14,14))
+        │       ├── then_keyword_loc: (14,15)-(14,16) = "?"
         │       ├── statements:
         │       │   @ StatementsNode (location: (14,17)-(14,18))
         │       │   └── body: (length: 1)
@@ -266,6 +267,7 @@
         │   │   │   └── rescue_expression:
         │   │   │       @ NilNode (location: (22,18)-(22,21))
         │   │   └── operator_loc: (22,5)-(22,6) = "="
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (23,2)-(23,5))
         │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/bug191.txt b/test/prism/snapshots/seattlerb/bug191.txt
index a54a5847..20901df1 100644
--- a/test/prism/snapshots/seattlerb/bug191.txt
+++ b/test/prism/snapshots/seattlerb/bug191.txt
@@ -16,6 +16,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :a
+        │   ├── then_keyword_loc: (1,2)-(1,3) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,4)-(1,6))
         │   │   └── body: (length: 1)
@@ -56,6 +57,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :a
+            ├── then_keyword_loc: (3,2)-(3,3) = "?"
             ├── statements:
             │   @ StatementsNode (location: (3,4)-(3,6))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/bug_comma.txt b/test/prism/snapshots/seattlerb/bug_comma.txt
index 53b8baed..f4b71ff4 100644
--- a/test/prism/snapshots/seattlerb/bug_comma.txt
+++ b/test/prism/snapshots/seattlerb/bug_comma.txt
@@ -35,6 +35,7 @@
             │   ├── block: ∅
             │   ├── flags: ∅
             │   └── name: :test
+            ├── then_keyword_loc: (1,16)-(1,20) = "then"
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (1,21)-(1,24) = "end"
diff --git a/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt b/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
index c9249d7e..0c1df7c2 100644
--- a/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
+++ b/test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt
@@ -29,6 +29,7 @@
             │   │               │   │   ├── value_loc: (1,9)-(1,10) = "c"
             │   │               │   │   ├── closing_loc: ∅
             │   │               │   │   └── unescaped: "c"
+            │   │               │   ├── then_keyword_loc: ∅
             │   │               │   ├── statements:
             │   │               │   │   @ StatementsNode (location: (2,0)-(2,1))
             │   │               │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/case_in_if_unless_post_mod.txt b/test/prism/snapshots/seattlerb/case_in_if_unless_post_mod.txt
index b058ee02..03f29769 100644
--- a/test/prism/snapshots/seattlerb/case_in_if_unless_post_mod.txt
+++ b/test/prism/snapshots/seattlerb/case_in_if_unless_post_mod.txt
@@ -17,6 +17,7 @@
             │   │   │   ├── if_keyword_loc: (2,5)-(2,7) = "if"
             │   │   │   ├── predicate:
             │   │   │   │   @ TrueNode (location: (2,8)-(2,12))
+            │   │   │   ├── then_keyword_loc: ∅
             │   │   │   ├── statements:
             │   │   │   │   @ StatementsNode (location: (2,3)-(2,4))
             │   │   │   │   └── body: (length: 1)
@@ -40,6 +41,7 @@
             │       │   ├── keyword_loc: (4,5)-(4,11) = "unless"
             │       │   ├── predicate:
             │       │   │   @ FalseNode (location: (4,12)-(4,17))
+            │       │   ├── then_keyword_loc: ∅
             │       │   ├── statements:
             │       │   │   @ StatementsNode (location: (4,3)-(4,4))
             │       │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/cond_unary_minus.txt b/test/prism/snapshots/seattlerb/cond_unary_minus.txt
index 28c354b8..0d112d72 100644
--- a/test/prism/snapshots/seattlerb/cond_unary_minus.txt
+++ b/test/prism/snapshots/seattlerb/cond_unary_minus.txt
@@ -8,6 +8,7 @@
             ├── predicate:
             │   @ IntegerNode (location: (1,3)-(1,5))
             │   └── flags: decimal
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (1,7)-(1,10) = "end"
diff --git a/test/prism/snapshots/seattlerb/difficult1_line_numbers.txt b/test/prism/snapshots/seattlerb/difficult1_line_numbers.txt
index 9656a2a4..c0dda242 100644
--- a/test/prism/snapshots/seattlerb/difficult1_line_numbers.txt
+++ b/test/prism/snapshots/seattlerb/difficult1_line_numbers.txt
@@ -7,6 +7,7 @@
             ├── if_keyword_loc: (1,0)-(1,2) = "if"
             ├── predicate:
             │   @ TrueNode (location: (1,3)-(1,7))
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (2,2)-(11,11))
             │   └── body: (length: 10)
diff --git a/test/prism/snapshots/seattlerb/difficult1_line_numbers2.txt b/test/prism/snapshots/seattlerb/difficult1_line_numbers2.txt
index 4aacf660..bb2f1116 100644
--- a/test/prism/snapshots/seattlerb/difficult1_line_numbers2.txt
+++ b/test/prism/snapshots/seattlerb/difficult1_line_numbers2.txt
@@ -7,6 +7,7 @@
         │   ├── if_keyword_loc: (1,0)-(1,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (1,3)-(1,7))
+        │   ├── then_keyword_loc: (1,8)-(1,12) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (2,2)-(5,6))
         │   │   └── body: (length: 4)
diff --git a/test/prism/snapshots/seattlerb/difficult2_.txt b/test/prism/snapshots/seattlerb/difficult2_.txt
index 8d896623..9929ca03 100644
--- a/test/prism/snapshots/seattlerb/difficult2_.txt
+++ b/test/prism/snapshots/seattlerb/difficult2_.txt
@@ -8,6 +8,7 @@
         │   ├── predicate:
         │   │   @ IntegerNode (location: (1,0)-(1,1))
         │   │   └── flags: decimal
+        │   ├── then_keyword_loc: (1,2)-(1,3) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,4)-(1,9))
         │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/difficult3_4.txt b/test/prism/snapshots/seattlerb/difficult3_4.txt
index 7172e296..c363006c 100644
--- a/test/prism/snapshots/seattlerb/difficult3_4.txt
+++ b/test/prism/snapshots/seattlerb/difficult3_4.txt
@@ -21,6 +21,7 @@
             │   │   ├── block: ∅
             │   │   ├── flags: variable_call
             │   │   └── name: :b
+            │   ├── then_keyword_loc: (1,4)-(1,5) = "?"
             │   ├── statements:
             │   │   @ StatementsNode (location: (1,6)-(1,10))
             │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/difficult7_.txt b/test/prism/snapshots/seattlerb/difficult7_.txt
index 2e21faf7..33cdcb21 100644
--- a/test/prism/snapshots/seattlerb/difficult7_.txt
+++ b/test/prism/snapshots/seattlerb/difficult7_.txt
@@ -41,6 +41,7 @@
             │   │   │   │   │           │   ├── block: ∅
             │   │   │   │   │           │   ├── flags: variable_call
             │   │   │   │   │           │   └── name: :b
+            │   │   │   │   │           ├── then_keyword_loc: (2,22)-(2,23) = "?"
             │   │   │   │   │           ├── statements:
             │   │   │   │   │           │   @ StatementsNode (location: (2,24)-(2,27))
             │   │   │   │   │           │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/flip2_env_lvar.txt b/test/prism/snapshots/seattlerb/flip2_env_lvar.txt
index 2be8280e..146d8cdd 100644
--- a/test/prism/snapshots/seattlerb/flip2_env_lvar.txt
+++ b/test/prism/snapshots/seattlerb/flip2_env_lvar.txt
@@ -31,6 +31,7 @@
             │   │   └── name: :b
             │   ├── operator_loc: (1,4)-(1,6) = ".."
             │   └── flags: ∅
+            ├── then_keyword_loc: (1,8)-(1,12) = "then"
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (1,13)-(1,16) = "end"
diff --git a/test/prism/snapshots/seattlerb/float_with_if_modifier.txt b/test/prism/snapshots/seattlerb/float_with_if_modifier.txt
index 798dba2d..5cf12848 100644
--- a/test/prism/snapshots/seattlerb/float_with_if_modifier.txt
+++ b/test/prism/snapshots/seattlerb/float_with_if_modifier.txt
@@ -7,6 +7,7 @@
             ├── if_keyword_loc: (1,3)-(1,5) = "if"
             ├── predicate:
             │   @ TrueNode (location: (1,6)-(1,10))
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (1,0)-(1,3))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/if_elsif.txt b/test/prism/snapshots/seattlerb/if_elsif.txt
index bc526814..8ce1864e 100644
--- a/test/prism/snapshots/seattlerb/if_elsif.txt
+++ b/test/prism/snapshots/seattlerb/if_elsif.txt
@@ -8,6 +8,7 @@
             ├── predicate:
             │   @ IntegerNode (location: (1,3)-(1,4))
             │   └── flags: decimal
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent:
             │   @ IfNode (location: (1,6)-(1,18))
@@ -15,6 +16,7 @@
             │   ├── predicate:
             │   │   @ IntegerNode (location: (1,12)-(1,13))
             │   │   └── flags: decimal
+            │   ├── then_keyword_loc: ∅
             │   ├── statements: ∅
             │   ├── consequent: ∅
             │   └── end_keyword_loc: (1,15)-(1,18) = "end"
diff --git a/test/prism/snapshots/seattlerb/if_symbol.txt b/test/prism/snapshots/seattlerb/if_symbol.txt
index 4a8ff3c6..e4358bed 100644
--- a/test/prism/snapshots/seattlerb/if_symbol.txt
+++ b/test/prism/snapshots/seattlerb/if_symbol.txt
@@ -24,6 +24,7 @@
             │   ├── block: ∅
             │   ├── flags: ∅
             │   └── name: :f
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (1,9)-(1,12) = "end"
diff --git a/test/prism/snapshots/seattlerb/integer_with_if_modifier.txt b/test/prism/snapshots/seattlerb/integer_with_if_modifier.txt
index 86632cca..7e0c8a23 100644
--- a/test/prism/snapshots/seattlerb/integer_with_if_modifier.txt
+++ b/test/prism/snapshots/seattlerb/integer_with_if_modifier.txt
@@ -7,6 +7,7 @@
             ├── if_keyword_loc: (1,5)-(1,7) = "if"
             ├── predicate:
             │   @ TrueNode (location: (1,8)-(1,12))
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (1,0)-(1,5))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/parse_if_not_canonical.txt b/test/prism/snapshots/seattlerb/parse_if_not_canonical.txt
index 8a19497f..5990f23a 100644
--- a/test/prism/snapshots/seattlerb/parse_if_not_canonical.txt
+++ b/test/prism/snapshots/seattlerb/parse_if_not_canonical.txt
@@ -36,6 +36,7 @@
             │   ├── block: ∅
             │   ├── flags: ∅
             │   └── name: :!
+            ├── then_keyword_loc: (1,16)-(1,20) = "then"
             ├── statements:
             │   @ StatementsNode (location: (1,21)-(1,26))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/parse_if_not_noncanonical.txt b/test/prism/snapshots/seattlerb/parse_if_not_noncanonical.txt
index 8a19497f..5990f23a 100644
--- a/test/prism/snapshots/seattlerb/parse_if_not_noncanonical.txt
+++ b/test/prism/snapshots/seattlerb/parse_if_not_noncanonical.txt
@@ -36,6 +36,7 @@
             │   ├── block: ∅
             │   ├── flags: ∅
             │   └── name: :!
+            ├── then_keyword_loc: (1,16)-(1,20) = "then"
             ├── statements:
             │   @ StatementsNode (location: (1,21)-(1,26))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/parse_line_return.txt b/test/prism/snapshots/seattlerb/parse_line_return.txt
index b28b44b5..f735c8a3 100644
--- a/test/prism/snapshots/seattlerb/parse_line_return.txt
+++ b/test/prism/snapshots/seattlerb/parse_line_return.txt
@@ -15,6 +15,7 @@
             │           ├── if_keyword_loc: (2,8)-(2,10) = "if"
             │           ├── predicate:
             │           │   @ TrueNode (location: (2,11)-(2,15))
+            │           ├── then_keyword_loc: (2,16)-(2,20) = "then"
             │           ├── statements:
             │           │   @ StatementsNode (location: (3,10)-(3,19))
             │           │   └── body: (length: 1)
diff --git a/test/prism/snapshots/seattlerb/str_interp_ternary_or_label.txt b/test/prism/snapshots/seattlerb/str_interp_ternary_or_label.txt
index 0be62344..31fd9fca 100644
--- a/test/prism/snapshots/seattlerb/str_interp_ternary_or_label.txt
+++ b/test/prism/snapshots/seattlerb/str_interp_ternary_or_label.txt
@@ -34,6 +34,7 @@
             │       │           │   ├── block: ∅
             │       │           │   ├── flags: ∅
             │       │           │   └── name: :b?
+            │       │           ├── then_keyword_loc: (1,8)-(1,9) = "?"
             │       │           ├── statements:
             │       │           │   @ StatementsNode (location: (1,10)-(1,17))
             │       │           │   └── body: (length: 1)
diff --git a/test/prism/snapshots/ternary_operator.txt b/test/prism/snapshots/ternary_operator.txt
index 04d46ae5..72fd10c2 100644
--- a/test/prism/snapshots/ternary_operator.txt
+++ b/test/prism/snapshots/ternary_operator.txt
@@ -16,6 +16,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :a
+        │   ├── then_keyword_loc: (1,2)-(1,3) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,4)-(1,5))
         │   │   └── body: (length: 1)
@@ -60,6 +61,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :a
+        │   ├── then_keyword_loc: (3,2)-(3,3) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (3,4)-(3,14))
         │   │   └── body: (length: 1)
@@ -114,6 +116,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: ∅
         │   │   └── name: :empty?
+        │   ├── then_keyword_loc: (5,6)-(5,7) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (5,7)-(5,11))
         │   │   └── body: (length: 1)
@@ -140,6 +143,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: ∅
         │   │   └── name: :empty?
+        │   ├── then_keyword_loc: (7,6)-(7,7) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (7,7)-(7,12))
         │   │   └── body: (length: 1)
@@ -166,6 +170,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: ∅
         │   │   └── name: :empty?
+        │   ├── then_keyword_loc: (9,6)-(9,7) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (9,7)-(9,10))
         │   │   └── body: (length: 1)
@@ -192,6 +197,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: ∅
         │   │   └── name: :a?
+        │   ├── then_keyword_loc: (11,2)-(11,3) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (11,3)-(11,6))
         │   │   └── body: (length: 1)
@@ -218,6 +224,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :a
+        │   ├── then_keyword_loc: (13,2)-(13,3) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (13,3)-(13,7))
         │   │   └── body: (length: 1)
@@ -262,6 +269,7 @@
             │   ├── block: ∅
             │   ├── flags: ∅
             │   └── name: :nil?
+            ├── then_keyword_loc: (15,4)-(15,5) = "?"
             ├── statements:
             │   @ StatementsNode (location: (15,5)-(15,10))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/unless.txt b/test/prism/snapshots/unless.txt
index f398a74d..ce1a4766 100644
--- a/test/prism/snapshots/unless.txt
+++ b/test/prism/snapshots/unless.txt
@@ -7,6 +7,7 @@
         │   ├── keyword_loc: (1,0)-(1,6) = "unless"
         │   ├── predicate:
         │   │   @ TrueNode (location: (1,7)-(1,11))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,13)-(1,14))
         │   │   └── body: (length: 1)
@@ -18,6 +19,7 @@
         │   ├── keyword_loc: (3,0)-(3,6) = "unless"
         │   ├── predicate:
         │   │   @ TrueNode (location: (3,7)-(3,11))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (4,0)-(4,1))
         │   │   └── body: (length: 1)
@@ -37,6 +39,7 @@
         │   ├── keyword_loc: (6,2)-(6,8) = "unless"
         │   ├── predicate:
         │   │   @ TrueNode (location: (6,9)-(6,13))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (6,0)-(6,1))
         │   │   └── body: (length: 1)
@@ -48,6 +51,7 @@
         │   ├── keyword_loc: (8,6)-(8,12) = "unless"
         │   ├── predicate:
         │   │   @ TrueNode (location: (8,13)-(8,17))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (8,0)-(8,5))
         │   │   └── body: (length: 1)
@@ -60,6 +64,7 @@
         │   ├── keyword_loc: (10,5)-(10,11) = "unless"
         │   ├── predicate:
         │   │   @ TrueNode (location: (10,12)-(10,16))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (10,0)-(10,4))
         │   │   └── body: (length: 1)
@@ -72,6 +77,7 @@
         │   ├── keyword_loc: (12,7)-(12,13) = "unless"
         │   ├── predicate:
         │   │   @ TrueNode (location: (12,14)-(12,18))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (12,0)-(12,6))
         │   │   └── body: (length: 1)
@@ -93,6 +99,7 @@
             │   ├── block: ∅
             │   ├── flags: ∅
             │   └── name: :bar?
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (14,0)-(14,10))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/unparser/corpus/literal/control.txt b/test/prism/snapshots/unparser/corpus/literal/control.txt
index be8daff0..9e4b5234 100644
--- a/test/prism/snapshots/unparser/corpus/literal/control.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/control.txt
@@ -41,6 +41,7 @@
         │       │       ├── if_keyword_loc: ∅
         │       │       ├── predicate:
         │       │       │   @ TrueNode (location: (8,7)-(8,11))
+        │       │       ├── then_keyword_loc: (8,12)-(8,13) = "?"
         │       │       ├── statements:
         │       │       │   @ StatementsNode (location: (8,14)-(8,15))
         │       │       │   └── body: (length: 1)
@@ -65,6 +66,7 @@
         │   │   │       ├── if_keyword_loc: ∅
         │   │   │       ├── predicate:
         │   │   │       │   @ TrueNode (location: (9,6)-(9,10))
+        │   │   │       ├── then_keyword_loc: (9,11)-(9,12) = "?"
         │   │   │       ├── statements:
         │   │   │       │   @ StatementsNode (location: (9,13)-(9,14))
         │   │   │       │   └── body: (length: 1)
@@ -90,6 +92,7 @@
         │   │   │       ├── if_keyword_loc: ∅
         │   │   │       ├── predicate:
         │   │   │       │   @ TrueNode (location: (10,5)-(10,9))
+        │   │   │       ├── then_keyword_loc: (10,10)-(10,11) = "?"
         │   │   │       ├── statements:
         │   │   │       │   @ StatementsNode (location: (10,12)-(10,13))
         │   │   │       │   └── body: (length: 1)
@@ -117,6 +120,7 @@
                 │       ├── if_keyword_loc: (11,13)-(11,15) = "if"
                 │       ├── predicate:
                 │       │   @ TrueNode (location: (11,16)-(11,20))
+                │       ├── then_keyword_loc: ∅
                 │       ├── statements:
                 │       │   @ StatementsNode (location: (12,2)-(12,3))
                 │       │   └── body: (length: 1)
diff --git a/test/prism/snapshots/unparser/corpus/literal/dstr.txt b/test/prism/snapshots/unparser/corpus/literal/dstr.txt
index 9f3cbbb0..6bc70930 100644
--- a/test/prism/snapshots/unparser/corpus/literal/dstr.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/dstr.txt
@@ -7,6 +7,7 @@
         │   ├── if_keyword_loc: (1,0)-(1,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (1,3)-(1,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (2,2)-(2,8))
         │   │   └── body: (length: 1)
@@ -30,6 +31,7 @@
         │   ├── if_keyword_loc: (4,0)-(4,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (4,3)-(4,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (5,2)-(10,3))
         │   │   └── body: (length: 2)
@@ -188,6 +190,7 @@
         │   ├── if_keyword_loc: (26,0)-(26,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (26,3)-(26,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (27,2)-(27,19))
         │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/unparser/corpus/literal/flipflop.txt b/test/prism/snapshots/unparser/corpus/literal/flipflop.txt
index e23a6b3a..5ba5daf2 100644
--- a/test/prism/snapshots/unparser/corpus/literal/flipflop.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/flipflop.txt
@@ -79,6 +79,7 @@
         │   │   │           └── flags: ∅
         │   │   ├── opening_loc: (1,3)-(1,4) = "("
         │   │   └── closing_loc: (1,22)-(1,23) = ")"
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (2,2)-(2,5))
         │   │   └── body: (length: 1)
@@ -170,6 +171,7 @@
             │   │           └── flags: exclude_end
             │   ├── opening_loc: (4,3)-(4,4) = "("
             │   └── closing_loc: (4,23)-(4,24) = ")"
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (5,2)-(5,5))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/unparser/corpus/literal/if.txt b/test/prism/snapshots/unparser/corpus/literal/if.txt
index 57382c40..594552bd 100644
--- a/test/prism/snapshots/unparser/corpus/literal/if.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/if.txt
@@ -12,6 +12,7 @@
         │   │   ├── closing_loc: (1,7)-(1,8) = "/"
         │   │   ├── unescaped: "foo"
         │   │   └── flags: ∅
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (2,2)-(2,5))
         │   │   └── body: (length: 1)
@@ -32,6 +33,7 @@
         │   ├── predicate:
         │   │   @ IntegerNode (location: (4,3)-(4,4))
         │   │   └── flags: decimal
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (5,2)-(5,3))
         │   │   └── body: (length: 1)
@@ -44,6 +46,7 @@
         │   ├── predicate:
         │   │   @ IntegerNode (location: (7,3)-(7,4))
         │   │   └── flags: decimal
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (8,2)-(8,3))
         │   │   └── body: (length: 1)
@@ -64,6 +67,7 @@
         │   ├── predicate:
         │   │   @ IntegerNode (location: (12,7)-(12,8))
         │   │   └── flags: decimal
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (13,2)-(13,5))
         │   │   └── body: (length: 1)
@@ -75,6 +79,7 @@
         │   ├── predicate:
         │   │   @ IntegerNode (location: (15,7)-(15,8))
         │   │   └── flags: decimal
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (16,2)-(16,3))
         │   │   └── body: (length: 1)
@@ -95,6 +100,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: ∅
         │   ├── statements: ∅
         │   ├── consequent: ∅
         │   └── end_keyword_loc: (19,0)-(19,3) = "end"
@@ -113,6 +119,7 @@
         │   │           │   @ LocalVariableReadNode (location: (22,15)-(22,18))
         │   │           │   ├── name: :foo
         │   │           │   └── depth: 0
+        │   │           ├── then_keyword_loc: ∅
         │   │           ├── statements:
         │   │           │   @ StatementsNode (location: (22,2)-(22,11))
         │   │           │   └── body: (length: 1)
@@ -151,6 +158,7 @@
         │   │           │   @ LocalVariableReadNode (location: (26,19)-(26,22))
         │   │           │   ├── name: :foo
         │   │           │   └── depth: 0
+        │   │           ├── then_keyword_loc: ∅
         │   │           ├── statements:
         │   │           │   @ StatementsNode (location: (26,2)-(26,11))
         │   │           │   └── body: (length: 1)
@@ -187,6 +195,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (29,2)-(29,11))
         │   │   └── body: (length: 1)
@@ -247,6 +256,7 @@
             │   │   └── closing_loc: (33,0)-(33,1) = "}"
             │   ├── flags: ∅
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (34,2)-(35,5))
             │   └── body: (length: 2)
diff --git a/test/prism/snapshots/unparser/corpus/literal/pattern.txt b/test/prism/snapshots/unparser/corpus/literal/pattern.txt
index f687b728..61e947a3 100644
--- a/test/prism/snapshots/unparser/corpus/literal/pattern.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/pattern.txt
@@ -124,6 +124,7 @@
         │   │   │   │   ├── if_keyword_loc: (10,6)-(10,8) = "if"
         │   │   │   │   ├── predicate:
         │   │   │   │   │   @ TrueNode (location: (10,9)-(10,13))
+        │   │   │   │   ├── then_keyword_loc: ∅
         │   │   │   │   ├── statements:
         │   │   │   │   │   @ StatementsNode (location: (10,3)-(10,5))
         │   │   │   │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/unparser/corpus/literal/send.txt b/test/prism/snapshots/unparser/corpus/literal/send.txt
index 9e286813..5a3e7ce6 100644
--- a/test/prism/snapshots/unparser/corpus/literal/send.txt
+++ b/test/prism/snapshots/unparser/corpus/literal/send.txt
@@ -398,6 +398,7 @@
         │   │   │   ├── block: ∅
         │   │   │   ├── flags: variable_call
         │   │   │   └── name: :foo
+        │   │   ├── then_keyword_loc: ∅
         │   │   ├── statements: ∅
         │   │   ├── consequent: ∅
         │   │   └── end_keyword_loc: (36,0)-(36,3) = "end"
diff --git a/test/prism/snapshots/unparser/corpus/semantic/and.txt b/test/prism/snapshots/unparser/corpus/semantic/and.txt
index ae4d01a7..eb780a73 100644
--- a/test/prism/snapshots/unparser/corpus/semantic/and.txt
+++ b/test/prism/snapshots/unparser/corpus/semantic/and.txt
@@ -168,6 +168,7 @@
         │   │   │   ├── operator_loc: (4,13)-(4,16) = "..."
         │   │   │   └── flags: exclude_end
         │   │   └── operator_loc: (4,9)-(4,11) = "or"
+        │   ├── then_keyword_loc: ∅
         │   ├── statements: ∅
         │   ├── consequent: ∅
         │   └── end_keyword_loc: (5,0)-(5,3) = "end"
@@ -228,6 +229,7 @@
             │   │   ├── operator_loc: (7,14)-(7,17) = "..."
             │   │   └── flags: exclude_end
             │   └── operator_loc: (7,9)-(7,12) = "and"
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (8,0)-(8,3) = "end"
diff --git a/test/prism/snapshots/unparser/corpus/semantic/dstr.txt b/test/prism/snapshots/unparser/corpus/semantic/dstr.txt
index 75b60e52..bc675a56 100644
--- a/test/prism/snapshots/unparser/corpus/semantic/dstr.txt
+++ b/test/prism/snapshots/unparser/corpus/semantic/dstr.txt
@@ -221,6 +221,7 @@
         │   ├── if_keyword_loc: (77,0)-(77,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (77,3)-(77,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (78,2)-(78,8))
         │   │   └── body: (length: 1)
@@ -244,6 +245,7 @@
         │   ├── if_keyword_loc: (83,0)-(83,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (83,3)-(83,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (84,2)-(84,8))
         │   │   └── body: (length: 1)
@@ -273,6 +275,7 @@
         │   ├── if_keyword_loc: (89,0)-(89,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (89,3)-(89,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (90,2)-(90,8))
         │   │   └── body: (length: 1)
@@ -296,6 +299,7 @@
         │   ├── if_keyword_loc: (95,0)-(95,2) = "if"
         │   ├── predicate:
         │   │   @ TrueNode (location: (95,3)-(95,7))
+        │   ├── then_keyword_loc: ∅
         │   ├── statements:
         │   │   @ StatementsNode (location: (96,2)-(96,10))
         │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/ambiuous_quoted_label_in_ternary_operator.txt b/test/prism/snapshots/whitequark/ambiuous_quoted_label_in_ternary_operator.txt
index 529c7bb2..8951625c 100644
--- a/test/prism/snapshots/whitequark/ambiuous_quoted_label_in_ternary_operator.txt
+++ b/test/prism/snapshots/whitequark/ambiuous_quoted_label_in_ternary_operator.txt
@@ -16,6 +16,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :a
+            ├── then_keyword_loc: (1,2)-(1,3) = "?"
             ├── statements:
             │   @ StatementsNode (location: (1,4)-(1,10))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/cond_begin.txt b/test/prism/snapshots/whitequark/cond_begin.txt
index cc52c5fd..ab9d37aa 100644
--- a/test/prism/snapshots/whitequark/cond_begin.txt
+++ b/test/prism/snapshots/whitequark/cond_begin.txt
@@ -22,6 +22,7 @@
             │   │           └── name: :bar
             │   ├── opening_loc: (1,3)-(1,4) = "("
             │   └── closing_loc: (1,7)-(1,8) = ")"
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (1,10)-(1,13))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/cond_begin_masgn.txt b/test/prism/snapshots/whitequark/cond_begin_masgn.txt
index 4037a2a0..e7608fce 100644
--- a/test/prism/snapshots/whitequark/cond_begin_masgn.txt
+++ b/test/prism/snapshots/whitequark/cond_begin_masgn.txt
@@ -46,6 +46,7 @@
             │   │               └── name: :foo
             │   ├── opening_loc: (1,3)-(1,4) = "("
             │   └── closing_loc: (1,19)-(1,20) = ")"
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (1,22)-(1,25) = "end"
diff --git a/test/prism/snapshots/whitequark/cond_eflipflop.txt b/test/prism/snapshots/whitequark/cond_eflipflop.txt
index 9f4e79ce..60c6f130 100644
--- a/test/prism/snapshots/whitequark/cond_eflipflop.txt
+++ b/test/prism/snapshots/whitequark/cond_eflipflop.txt
@@ -72,6 +72,7 @@
             │   │   └── name: :bar
             │   ├── operator_loc: (3,6)-(3,9) = "..."
             │   └── flags: exclude_end
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (3,14)-(3,17) = "end"
diff --git a/test/prism/snapshots/whitequark/cond_iflipflop.txt b/test/prism/snapshots/whitequark/cond_iflipflop.txt
index 93aaf20f..b26c207b 100644
--- a/test/prism/snapshots/whitequark/cond_iflipflop.txt
+++ b/test/prism/snapshots/whitequark/cond_iflipflop.txt
@@ -72,6 +72,7 @@
             │   │   └── name: :bar
             │   ├── operator_loc: (3,6)-(3,8) = ".."
             │   └── flags: ∅
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (3,13)-(3,16) = "end"
diff --git a/test/prism/snapshots/whitequark/cond_match_current_line.txt b/test/prism/snapshots/whitequark/cond_match_current_line.txt
index e13cb573..ff771029 100644
--- a/test/prism/snapshots/whitequark/cond_match_current_line.txt
+++ b/test/prism/snapshots/whitequark/cond_match_current_line.txt
@@ -28,6 +28,7 @@
             │   ├── closing_loc: (3,7)-(3,8) = "/"
             │   ├── unescaped: "wat"
             │   └── flags: ∅
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (3,10)-(3,13) = "end"
diff --git a/test/prism/snapshots/whitequark/hash_label_end.txt b/test/prism/snapshots/whitequark/hash_label_end.txt
index 38152048..232cfdbe 100644
--- a/test/prism/snapshots/whitequark/hash_label_end.txt
+++ b/test/prism/snapshots/whitequark/hash_label_end.txt
@@ -24,6 +24,7 @@
         │   │   │       │   ├── block: ∅
         │   │   │       │   ├── flags: variable_call
         │   │   │       │   └── name: :a
+        │   │   │       ├── then_keyword_loc: (1,4)-(1,5) = "?"
         │   │   │       ├── statements:
         │   │   │       │   @ StatementsNode (location: (1,6)-(1,9))
         │   │   │       │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/if.txt b/test/prism/snapshots/whitequark/if.txt
index ccd906a0..efedd32d 100644
--- a/test/prism/snapshots/whitequark/if.txt
+++ b/test/prism/snapshots/whitequark/if.txt
@@ -16,6 +16,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: (1,7)-(1,11) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,12)-(1,15))
         │   │   └── body: (length: 1)
@@ -44,6 +45,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (3,8)-(3,11))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/if_else.txt b/test/prism/snapshots/whitequark/if_else.txt
index 56644ac9..a7fbb016 100644
--- a/test/prism/snapshots/whitequark/if_else.txt
+++ b/test/prism/snapshots/whitequark/if_else.txt
@@ -16,6 +16,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: (1,7)-(1,11) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,12)-(1,15))
         │   │   └── body: (length: 1)
@@ -60,6 +61,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (3,8)-(3,11))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/if_elsif.txt b/test/prism/snapshots/whitequark/if_elsif.txt
index 7f0c3b87..991b7741 100644
--- a/test/prism/snapshots/whitequark/if_elsif.txt
+++ b/test/prism/snapshots/whitequark/if_elsif.txt
@@ -16,6 +16,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (1,8)-(1,11))
             │   └── body: (length: 1)
@@ -43,6 +44,7 @@
             │   │   ├── block: ∅
             │   │   ├── flags: variable_call
             │   │   └── name: :baz
+            │   ├── then_keyword_loc: ∅
             │   ├── statements:
             │   │   @ StatementsNode (location: (1,24)-(1,25))
             │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/if_masgn__24.txt b/test/prism/snapshots/whitequark/if_masgn__24.txt
index 75168eb0..ab02456f 100644
--- a/test/prism/snapshots/whitequark/if_masgn__24.txt
+++ b/test/prism/snapshots/whitequark/if_masgn__24.txt
@@ -36,6 +36,7 @@
             │   │               └── name: :foo
             │   ├── opening_loc: (1,3)-(1,4) = "("
             │   └── closing_loc: (1,14)-(1,15) = ")"
+            ├── then_keyword_loc: ∅
             ├── statements: ∅
             ├── consequent: ∅
             └── end_keyword_loc: (1,17)-(1,20) = "end"
diff --git a/test/prism/snapshots/whitequark/if_mod.txt b/test/prism/snapshots/whitequark/if_mod.txt
index 8ef98ce5..e1ead013 100644
--- a/test/prism/snapshots/whitequark/if_mod.txt
+++ b/test/prism/snapshots/whitequark/if_mod.txt
@@ -16,6 +16,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (1,0)-(1,3))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/if_nl_then.txt b/test/prism/snapshots/whitequark/if_nl_then.txt
index 8a1a9302..2146c246 100644
--- a/test/prism/snapshots/whitequark/if_nl_then.txt
+++ b/test/prism/snapshots/whitequark/if_nl_then.txt
@@ -16,6 +16,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: (2,0)-(2,4) = "then"
             ├── statements:
             │   @ StatementsNode (location: (2,5)-(2,8))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/if_while_after_class__since_32.txt b/test/prism/snapshots/whitequark/if_while_after_class__since_32.txt
index 90f021d6..daafa272 100644
--- a/test/prism/snapshots/whitequark/if_while_after_class__since_32.txt
+++ b/test/prism/snapshots/whitequark/if_while_after_class__since_32.txt
@@ -13,6 +13,7 @@
         │   │   │   ├── if_keyword_loc: (1,6)-(1,8) = "if"
         │   │   │   ├── predicate:
         │   │   │   │   @ TrueNode (location: (1,9)-(1,13))
+        │   │   │   ├── then_keyword_loc: ∅
         │   │   │   ├── statements:
         │   │   │   │   @ StatementsNode (location: (1,15)-(1,21))
         │   │   │   │   └── body: (length: 1)
@@ -71,6 +72,7 @@
         │   │   │   ├── if_keyword_loc: (5,7)-(5,9) = "if"
         │   │   │   ├── predicate:
         │   │   │   │   @ TrueNode (location: (5,10)-(5,14))
+        │   │   │   ├── then_keyword_loc: ∅
         │   │   │   ├── statements:
         │   │   │   │   @ StatementsNode (location: (5,16)-(5,22))
         │   │   │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/ruby_bug_10279.txt b/test/prism/snapshots/whitequark/ruby_bug_10279.txt
index be4105ff..3a8edf72 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_10279.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_10279.txt
@@ -18,6 +18,7 @@
             │       │   ├── if_keyword_loc: (1,4)-(1,6) = "if"
             │       │   ├── predicate:
             │       │   │   @ TrueNode (location: (1,7)-(1,11))
+            │       │   ├── then_keyword_loc: (1,12)-(1,16) = "then"
             │       │   ├── statements:
             │       │   │   @ StatementsNode (location: (1,17)-(1,19))
             │       │   │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/ruby_bug_10653.txt b/test/prism/snapshots/whitequark/ruby_bug_10653.txt
index 3d57b453..418bce94 100644
--- a/test/prism/snapshots/whitequark/ruby_bug_10653.txt
+++ b/test/prism/snapshots/whitequark/ruby_bug_10653.txt
@@ -7,6 +7,7 @@
         │   ├── if_keyword_loc: ∅
         │   ├── predicate:
         │   │   @ FalseNode (location: (1,0)-(1,5))
+        │   ├── then_keyword_loc: (1,6)-(1,7) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,8)-(1,20))
         │   │   └── body: (length: 1)
@@ -54,6 +55,7 @@
         │   ├── if_keyword_loc: ∅
         │   ├── predicate:
         │   │   @ FalseNode (location: (3,0)-(3,5))
+        │   ├── then_keyword_loc: (3,6)-(3,7) = "?"
         │   ├── statements:
         │   │   @ StatementsNode (location: (3,8)-(3,16))
         │   │   └── body: (length: 1)
@@ -101,6 +103,7 @@
             ├── if_keyword_loc: ∅
             ├── predicate:
             │   @ TrueNode (location: (5,0)-(5,4))
+            ├── then_keyword_loc: (5,5)-(5,6) = "?"
             ├── statements:
             │   @ StatementsNode (location: (5,7)-(5,27))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/ternary.txt b/test/prism/snapshots/whitequark/ternary.txt
index 1d25aecd..7a74f5ca 100644
--- a/test/prism/snapshots/whitequark/ternary.txt
+++ b/test/prism/snapshots/whitequark/ternary.txt
@@ -16,6 +16,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: (1,4)-(1,5) = "?"
             ├── statements:
             │   @ StatementsNode (location: (1,6)-(1,7))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/ternary_ambiguous_symbol.txt b/test/prism/snapshots/whitequark/ternary_ambiguous_symbol.txt
index 206ca095..13c426b8 100644
--- a/test/prism/snapshots/whitequark/ternary_ambiguous_symbol.txt
+++ b/test/prism/snapshots/whitequark/ternary_ambiguous_symbol.txt
@@ -30,6 +30,7 @@
             │   │           └── name: :foo
             │   ├── opening_loc: (1,4)-(1,5) = "("
             │   └── closing_loc: (1,8)-(1,9) = ")"
+            ├── then_keyword_loc: (1,9)-(1,10) = "?"
             ├── statements:
             │   @ StatementsNode (location: (1,10)-(1,11))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/unless.txt b/test/prism/snapshots/whitequark/unless.txt
index c37f9968..666ab7d5 100644
--- a/test/prism/snapshots/whitequark/unless.txt
+++ b/test/prism/snapshots/whitequark/unless.txt
@@ -16,6 +16,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: (1,11)-(1,15) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,16)-(1,19))
         │   │   └── body: (length: 1)
@@ -44,6 +45,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (3,12)-(3,15))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/unless_else.txt b/test/prism/snapshots/whitequark/unless_else.txt
index 5c9c3480..86b16a5c 100644
--- a/test/prism/snapshots/whitequark/unless_else.txt
+++ b/test/prism/snapshots/whitequark/unless_else.txt
@@ -16,6 +16,7 @@
         │   │   ├── block: ∅
         │   │   ├── flags: variable_call
         │   │   └── name: :foo
+        │   ├── then_keyword_loc: (1,11)-(1,15) = "then"
         │   ├── statements:
         │   │   @ StatementsNode (location: (1,16)-(1,19))
         │   │   └── body: (length: 1)
@@ -60,6 +61,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (3,12)-(3,15))
             │   └── body: (length: 1)
diff --git a/test/prism/snapshots/whitequark/unless_mod.txt b/test/prism/snapshots/whitequark/unless_mod.txt
index 2229c37e..07b5ee93 100644
--- a/test/prism/snapshots/whitequark/unless_mod.txt
+++ b/test/prism/snapshots/whitequark/unless_mod.txt
@@ -16,6 +16,7 @@
             │   ├── block: ∅
             │   ├── flags: variable_call
             │   └── name: :foo
+            ├── then_keyword_loc: ∅
             ├── statements:
             │   @ StatementsNode (location: (1,0)-(1,3))
             │   └── body: (length: 1)