prism 0.30.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +3 -1
- data/config.yml +185 -126
- data/docs/serialization.md +3 -0
- data/ext/prism/api_node.c +2843 -2085
- data/ext/prism/extconf.rb +1 -1
- data/ext/prism/extension.c +35 -25
- data/ext/prism/extension.h +2 -2
- data/include/prism/ast.h +1048 -69
- data/include/prism/defines.h +9 -0
- data/include/prism/diagnostic.h +11 -3
- data/include/prism/options.h +55 -1
- data/include/prism/parser.h +27 -3
- data/include/prism/regexp.h +2 -1
- data/include/prism/util/pm_integer.h +6 -6
- data/include/prism/util/pm_newline_list.h +11 -0
- data/include/prism/util/pm_string.h +1 -0
- data/include/prism/version.h +3 -3
- data/lib/prism/desugar_compiler.rb +111 -74
- data/lib/prism/dispatcher.rb +2 -1
- data/lib/prism/dot_visitor.rb +21 -31
- data/lib/prism/dsl.rb +656 -471
- data/lib/prism/ffi.rb +3 -0
- data/lib/prism/inspect_visitor.rb +285 -57
- data/lib/prism/mutation_compiler.rb +5 -5
- data/lib/prism/node.rb +2282 -4754
- data/lib/prism/node_ext.rb +72 -11
- data/lib/prism/parse_result/errors.rb +65 -0
- data/lib/prism/parse_result/newlines.rb +28 -28
- data/lib/prism/parse_result.rb +25 -2
- data/lib/prism/reflection.rb +7 -7
- data/lib/prism/serialize.rb +468 -610
- data/lib/prism/translation/parser/compiler.rb +18 -18
- data/lib/prism/translation/parser/lexer.rb +1 -1
- data/lib/prism/translation/parser.rb +3 -3
- data/lib/prism/translation/ripper.rb +14 -14
- data/lib/prism/translation/ruby_parser.rb +43 -7
- data/prism.gemspec +3 -1
- data/rbi/prism/dsl.rbi +521 -0
- data/rbi/prism/node.rbi +1456 -5616
- data/rbi/prism.rbi +16 -16
- data/sig/prism/dsl.rbs +189 -305
- data/sig/prism/node.rbs +702 -603
- data/sig/prism/parse_result.rbs +2 -0
- data/src/diagnostic.c +22 -6
- data/src/node.c +277 -284
- data/src/options.c +18 -0
- data/src/prettyprint.c +99 -108
- data/src/prism.c +1282 -760
- data/src/regexp.c +72 -4
- data/src/serialize.c +165 -50
- data/src/token_type.c +2 -2
- data/src/util/pm_integer.c +14 -14
- data/src/util/pm_newline_list.c +29 -0
- data/src/util/pm_string.c +9 -5
- metadata +4 -2
data/lib/prism/node_ext.rb
CHANGED
@@ -21,7 +21,10 @@ module Prism
|
|
21
21
|
# Returns a numeric value that represents the flags that were used to create
|
22
22
|
# the regular expression.
|
23
23
|
def options
|
24
|
-
o =
|
24
|
+
o = 0
|
25
|
+
o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
|
26
|
+
o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
|
27
|
+
o |= Regexp::MULTILINE if flags.anybits?(RegularExpressionFlags::MULTI_LINE)
|
25
28
|
o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
|
26
29
|
o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
|
27
30
|
o
|
@@ -69,11 +72,12 @@ module Prism
|
|
69
72
|
def to_interpolated
|
70
73
|
InterpolatedStringNode.new(
|
71
74
|
source,
|
75
|
+
-1,
|
76
|
+
location,
|
72
77
|
frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
|
73
78
|
opening_loc,
|
74
|
-
[copy(
|
75
|
-
closing_loc
|
76
|
-
location
|
79
|
+
[copy(location: content_loc, opening_loc: nil, closing_loc: nil)],
|
80
|
+
closing_loc
|
77
81
|
)
|
78
82
|
end
|
79
83
|
end
|
@@ -86,10 +90,12 @@ module Prism
|
|
86
90
|
def to_interpolated
|
87
91
|
InterpolatedXStringNode.new(
|
88
92
|
source,
|
93
|
+
-1,
|
94
|
+
location,
|
95
|
+
flags,
|
89
96
|
opening_loc,
|
90
|
-
[StringNode.new(source, 0, nil, content_loc, nil, unescaped
|
91
|
-
closing_loc
|
92
|
-
location
|
97
|
+
[StringNode.new(source, node_id, content_loc, 0, nil, content_loc, nil, unescaped)],
|
98
|
+
closing_loc
|
93
99
|
)
|
94
100
|
end
|
95
101
|
end
|
@@ -115,9 +121,9 @@ module Prism
|
|
115
121
|
deprecated("value", "numerator", "denominator")
|
116
122
|
|
117
123
|
if denominator == 1
|
118
|
-
IntegerNode.new(source,
|
124
|
+
IntegerNode.new(source, -1, location.chop, flags, numerator)
|
119
125
|
else
|
120
|
-
FloatNode.new(source, numerator.to_f / denominator
|
126
|
+
FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator)
|
121
127
|
end
|
122
128
|
end
|
123
129
|
end
|
@@ -195,7 +201,12 @@ module Prism
|
|
195
201
|
# continue to supply that API.
|
196
202
|
def child
|
197
203
|
deprecated("name", "name_loc")
|
198
|
-
|
204
|
+
|
205
|
+
if name
|
206
|
+
ConstantReadNode.new(source, -1, name_loc, 0, name)
|
207
|
+
else
|
208
|
+
MissingNode.new(source, -1, location, 0)
|
209
|
+
end
|
199
210
|
end
|
200
211
|
end
|
201
212
|
|
@@ -231,7 +242,12 @@ module Prism
|
|
231
242
|
# continue to supply that API.
|
232
243
|
def child
|
233
244
|
deprecated("name", "name_loc")
|
234
|
-
|
245
|
+
|
246
|
+
if name
|
247
|
+
ConstantReadNode.new(source, -1, name_loc, 0, name)
|
248
|
+
else
|
249
|
+
MissingNode.new(source, -1, location, 0)
|
250
|
+
end
|
235
251
|
end
|
236
252
|
end
|
237
253
|
|
@@ -444,4 +460,49 @@ module Prism
|
|
444
460
|
binary_operator_loc
|
445
461
|
end
|
446
462
|
end
|
463
|
+
|
464
|
+
class CaseMatchNode < Node
|
465
|
+
# Returns the else clause of the case match node. This method is deprecated
|
466
|
+
# in favor of #else_clause.
|
467
|
+
def consequent
|
468
|
+
deprecated("else_clause")
|
469
|
+
else_clause
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
class CaseNode < Node
|
474
|
+
# Returns the else clause of the case node. This method is deprecated in
|
475
|
+
# favor of #else_clause.
|
476
|
+
def consequent
|
477
|
+
deprecated("else_clause")
|
478
|
+
else_clause
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
class IfNode < Node
|
483
|
+
# Returns the subsequent if/elsif/else clause of the if node. This method is
|
484
|
+
# deprecated in favor of #subsequent.
|
485
|
+
def consequent
|
486
|
+
deprecated("subsequent")
|
487
|
+
subsequent
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
class RescueNode < Node
|
492
|
+
# Returns the subsequent rescue clause of the rescue node. This method is
|
493
|
+
# deprecated in favor of #subsequent.
|
494
|
+
def consequent
|
495
|
+
deprecated("subsequent")
|
496
|
+
subsequent
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
class UnlessNode < Node
|
501
|
+
# Returns the else clause of the unless node. This method is deprecated in
|
502
|
+
# favor of #else_clause.
|
503
|
+
def consequent
|
504
|
+
deprecated("else_clause")
|
505
|
+
else_clause
|
506
|
+
end
|
507
|
+
end
|
447
508
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
module Prism
|
6
|
+
class ParseResult < Result
|
7
|
+
# An object to represent the set of errors on a parse result. This object
|
8
|
+
# can be used to format the errors in a human-readable way.
|
9
|
+
class Errors
|
10
|
+
# The parse result that contains the errors.
|
11
|
+
attr_reader :parse_result
|
12
|
+
|
13
|
+
# Initialize a new set of errors from the given parse result.
|
14
|
+
def initialize(parse_result)
|
15
|
+
@parse_result = parse_result
|
16
|
+
end
|
17
|
+
|
18
|
+
# Formats the errors in a human-readable way and return them as a string.
|
19
|
+
def format
|
20
|
+
error_lines = {}
|
21
|
+
parse_result.errors.each do |error|
|
22
|
+
location = error.location
|
23
|
+
(location.start_line..location.end_line).each do |line|
|
24
|
+
error_lines[line] ||= []
|
25
|
+
error_lines[line] << error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
source_lines = parse_result.source.source.lines
|
30
|
+
source_lines << "" if error_lines.key?(source_lines.size + 1)
|
31
|
+
|
32
|
+
io = StringIO.new
|
33
|
+
source_lines.each.with_index(1) do |line, line_number|
|
34
|
+
io.puts(line)
|
35
|
+
|
36
|
+
(error_lines.delete(line_number) || []).each do |error|
|
37
|
+
location = error.location
|
38
|
+
|
39
|
+
case line_number
|
40
|
+
when location.start_line
|
41
|
+
io.print(" " * location.start_column + "^")
|
42
|
+
|
43
|
+
if location.start_line == location.end_line
|
44
|
+
if location.start_column != location.end_column
|
45
|
+
io.print("~" * (location.end_column - location.start_column - 1))
|
46
|
+
end
|
47
|
+
|
48
|
+
io.puts(" " + error.message)
|
49
|
+
else
|
50
|
+
io.puts("~" * (line.bytesize - location.start_column))
|
51
|
+
end
|
52
|
+
when location.end_line
|
53
|
+
io.puts("~" * location.end_column + " " + error.message)
|
54
|
+
else
|
55
|
+
io.puts("~" * line.bytesize)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
io.puts
|
61
|
+
io.string
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -45,7 +45,7 @@ module Prism
|
|
45
45
|
|
46
46
|
# Mark if/unless nodes as newlines.
|
47
47
|
def visit_if_node(node)
|
48
|
-
node.
|
48
|
+
node.newline_flag!(@lines)
|
49
49
|
super(node)
|
50
50
|
end
|
51
51
|
|
@@ -54,7 +54,7 @@ module Prism
|
|
54
54
|
# Permit statements lists to mark newlines within themselves.
|
55
55
|
def visit_statements_node(node)
|
56
56
|
node.body.each do |child|
|
57
|
-
child.
|
57
|
+
child.newline_flag!(@lines)
|
58
58
|
end
|
59
59
|
super(node)
|
60
60
|
end
|
@@ -62,93 +62,93 @@ module Prism
|
|
62
62
|
end
|
63
63
|
|
64
64
|
class Node
|
65
|
-
def
|
66
|
-
@
|
65
|
+
def newline_flag? # :nodoc:
|
66
|
+
@newline_flag ? true : false
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def newline_flag!(lines) # :nodoc:
|
70
70
|
line = location.start_line
|
71
71
|
unless lines[line]
|
72
72
|
lines[line] = true
|
73
|
-
@
|
73
|
+
@newline_flag = true
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
78
|
class BeginNode < Node
|
79
|
-
def
|
79
|
+
def newline_flag!(lines) # :nodoc:
|
80
80
|
# Never mark BeginNode with a newline flag, mark children instead.
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
84
|
class ParenthesesNode < Node
|
85
|
-
def
|
85
|
+
def newline_flag!(lines) # :nodoc:
|
86
86
|
# Never mark ParenthesesNode with a newline flag, mark children instead.
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
90
|
class IfNode < Node
|
91
|
-
def
|
92
|
-
predicate.
|
91
|
+
def newline_flag!(lines) # :nodoc:
|
92
|
+
predicate.newline_flag!(lines)
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
96
|
class UnlessNode < Node
|
97
|
-
def
|
98
|
-
predicate.
|
97
|
+
def newline_flag!(lines) # :nodoc:
|
98
|
+
predicate.newline_flag!(lines)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
102
|
class UntilNode < Node
|
103
|
-
def
|
104
|
-
predicate.
|
103
|
+
def newline_flag!(lines) # :nodoc:
|
104
|
+
predicate.newline_flag!(lines)
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
108
|
class WhileNode < Node
|
109
|
-
def
|
110
|
-
predicate.
|
109
|
+
def newline_flag!(lines) # :nodoc:
|
110
|
+
predicate.newline_flag!(lines)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
114
|
class RescueModifierNode < Node
|
115
|
-
def
|
116
|
-
expression.
|
115
|
+
def newline_flag!(lines) # :nodoc:
|
116
|
+
expression.newline_flag!(lines)
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
120
|
class InterpolatedMatchLastLineNode < Node
|
121
|
-
def
|
121
|
+
def newline_flag!(lines) # :nodoc:
|
122
122
|
first = parts.first
|
123
|
-
first.
|
123
|
+
first.newline_flag!(lines) if first
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
127
|
class InterpolatedRegularExpressionNode < Node
|
128
|
-
def
|
128
|
+
def newline_flag!(lines) # :nodoc:
|
129
129
|
first = parts.first
|
130
|
-
first.
|
130
|
+
first.newline_flag!(lines) if first
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
134
|
class InterpolatedStringNode < Node
|
135
|
-
def
|
135
|
+
def newline_flag!(lines) # :nodoc:
|
136
136
|
first = parts.first
|
137
|
-
first.
|
137
|
+
first.newline_flag!(lines) if first
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
141
|
class InterpolatedSymbolNode < Node
|
142
|
-
def
|
142
|
+
def newline_flag!(lines) # :nodoc:
|
143
143
|
first = parts.first
|
144
|
-
first.
|
144
|
+
first.newline_flag!(lines) if first
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
148
|
class InterpolatedXStringNode < Node
|
149
|
-
def
|
149
|
+
def newline_flag!(lines) # :nodoc:
|
150
150
|
first = parts.first
|
151
|
-
first.
|
151
|
+
first.newline_flag!(lines) if first
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
data/lib/prism/parse_result.rb
CHANGED
@@ -10,7 +10,11 @@ module Prism
|
|
10
10
|
# specialized and more performant `ASCIISource` if no multibyte characters
|
11
11
|
# are present in the source code.
|
12
12
|
def self.for(source, start_line = 1, offsets = [])
|
13
|
-
source.ascii_only?
|
13
|
+
if source.ascii_only?
|
14
|
+
ASCIISource.new(source, start_line, offsets)
|
15
|
+
else
|
16
|
+
new(source, start_line, offsets)
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
# The source code that this source object represents.
|
@@ -87,7 +91,12 @@ module Prism
|
|
87
91
|
# encodings, it is not captured here.
|
88
92
|
def code_units_offset(byte_offset, encoding)
|
89
93
|
byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding)
|
90
|
-
|
94
|
+
|
95
|
+
if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
|
96
|
+
byteslice.bytesize / 2
|
97
|
+
else
|
98
|
+
byteslice.length
|
99
|
+
end
|
91
100
|
end
|
92
101
|
|
93
102
|
# Returns the column number in code units for the given encoding for the
|
@@ -575,9 +584,11 @@ module Prism
|
|
575
584
|
# This is a result specific to the `parse` and `parse_file` methods.
|
576
585
|
class ParseResult < Result
|
577
586
|
autoload :Comments, "prism/parse_result/comments"
|
587
|
+
autoload :Errors, "prism/parse_result/errors"
|
578
588
|
autoload :Newlines, "prism/parse_result/newlines"
|
579
589
|
|
580
590
|
private_constant :Comments
|
591
|
+
private_constant :Errors
|
581
592
|
private_constant :Newlines
|
582
593
|
|
583
594
|
# The syntax tree that was parsed from the source code.
|
@@ -604,6 +615,12 @@ module Prism
|
|
604
615
|
def mark_newlines!
|
605
616
|
value.accept(Newlines.new(source.offsets.size)) # steep:ignore
|
606
617
|
end
|
618
|
+
|
619
|
+
# Returns a string representation of the syntax tree with the errors
|
620
|
+
# displayed inline.
|
621
|
+
def errors_format
|
622
|
+
Errors.new(self).format
|
623
|
+
end
|
607
624
|
end
|
608
625
|
|
609
626
|
# This is a result specific to the `lex` and `lex_file` methods.
|
@@ -694,5 +711,11 @@ module Prism
|
|
694
711
|
other.type == type &&
|
695
712
|
other.value == value
|
696
713
|
end
|
714
|
+
|
715
|
+
# Returns a string representation of this token.
|
716
|
+
def inspect
|
717
|
+
location
|
718
|
+
super
|
719
|
+
end
|
697
720
|
end
|
698
721
|
end
|
data/lib/prism/reflection.rb
CHANGED
@@ -112,7 +112,7 @@ module Prism
|
|
112
112
|
when :and_node
|
113
113
|
[NodeField.new(:left), NodeField.new(:right), LocationField.new(:operator_loc)]
|
114
114
|
when :arguments_node
|
115
|
-
[FlagsField.new(:flags, [:contains_keywords?, :contains_keyword_splat?]), NodeListField.new(:arguments)]
|
115
|
+
[FlagsField.new(:flags, [:contains_keywords?, :contains_keyword_splat?, :contains_splat?]), NodeListField.new(:arguments)]
|
116
116
|
when :array_node
|
117
117
|
[FlagsField.new(:flags, [:contains_splat?]), NodeListField.new(:elements), OptionalLocationField.new(:opening_loc), OptionalLocationField.new(:closing_loc)]
|
118
118
|
when :array_pattern_node
|
@@ -150,9 +150,9 @@ module Prism
|
|
150
150
|
when :capture_pattern_node
|
151
151
|
[NodeField.new(:value), NodeField.new(:target), LocationField.new(:operator_loc)]
|
152
152
|
when :case_match_node
|
153
|
-
[OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:
|
153
|
+
[OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:else_clause), LocationField.new(:case_keyword_loc), LocationField.new(:end_keyword_loc)]
|
154
154
|
when :case_node
|
155
|
-
[OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:
|
155
|
+
[OptionalNodeField.new(:predicate), NodeListField.new(:conditions), OptionalNodeField.new(:else_clause), LocationField.new(:case_keyword_loc), LocationField.new(:end_keyword_loc)]
|
156
156
|
when :class_node
|
157
157
|
[ConstantListField.new(:locals), LocationField.new(:class_keyword_loc), NodeField.new(:constant_path), OptionalLocationField.new(:inheritance_operator_loc), OptionalNodeField.new(:superclass), OptionalNodeField.new(:body), LocationField.new(:end_keyword_loc), ConstantField.new(:name)]
|
158
158
|
when :class_variable_and_write_node
|
@@ -236,7 +236,7 @@ module Prism
|
|
236
236
|
when :hash_pattern_node
|
237
237
|
[OptionalNodeField.new(:constant), NodeListField.new(:elements), OptionalNodeField.new(:rest), OptionalLocationField.new(:opening_loc), OptionalLocationField.new(:closing_loc)]
|
238
238
|
when :if_node
|
239
|
-
[OptionalLocationField.new(:if_keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:
|
239
|
+
[OptionalLocationField.new(:if_keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:subsequent), OptionalLocationField.new(:end_keyword_loc)]
|
240
240
|
when :imaginary_node
|
241
241
|
[NodeField.new(:numeric)]
|
242
242
|
when :implicit_node
|
@@ -360,13 +360,13 @@ module Prism
|
|
360
360
|
when :rescue_modifier_node
|
361
361
|
[NodeField.new(:expression), LocationField.new(:keyword_loc), NodeField.new(:rescue_expression)]
|
362
362
|
when :rescue_node
|
363
|
-
[LocationField.new(:keyword_loc), NodeListField.new(:exceptions), OptionalLocationField.new(:operator_loc), OptionalNodeField.new(:reference), OptionalNodeField.new(:statements), OptionalNodeField.new(:
|
363
|
+
[LocationField.new(:keyword_loc), NodeListField.new(:exceptions), OptionalLocationField.new(:operator_loc), OptionalNodeField.new(:reference), OptionalNodeField.new(:statements), OptionalNodeField.new(:subsequent)]
|
364
364
|
when :rest_parameter_node
|
365
365
|
[FlagsField.new(:flags, [:repeated_parameter?]), OptionalConstantField.new(:name), OptionalLocationField.new(:name_loc), LocationField.new(:operator_loc)]
|
366
366
|
when :retry_node
|
367
367
|
[]
|
368
368
|
when :return_node
|
369
|
-
[
|
369
|
+
[LocationField.new(:keyword_loc), OptionalNodeField.new(:arguments)]
|
370
370
|
when :self_node
|
371
371
|
[]
|
372
372
|
when :shareable_constant_node
|
@@ -394,7 +394,7 @@ module Prism
|
|
394
394
|
when :undef_node
|
395
395
|
[NodeListField.new(:names), LocationField.new(:keyword_loc)]
|
396
396
|
when :unless_node
|
397
|
-
[LocationField.new(:keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:
|
397
|
+
[LocationField.new(:keyword_loc), NodeField.new(:predicate), OptionalLocationField.new(:then_keyword_loc), OptionalNodeField.new(:statements), OptionalNodeField.new(:else_clause), OptionalLocationField.new(:end_keyword_loc)]
|
398
398
|
when :until_node
|
399
399
|
[FlagsField.new(:flags, [:begin_modifier?]), LocationField.new(:keyword_loc), OptionalLocationField.new(:closing_loc), NodeField.new(:predicate), OptionalNodeField.new(:statements)]
|
400
400
|
when :when_node
|