prism 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -1
  3. data/Makefile +5 -5
  4. data/README.md +2 -2
  5. data/config.yml +26 -13
  6. data/docs/build_system.md +6 -6
  7. data/docs/building.md +1 -1
  8. data/docs/configuration.md +1 -0
  9. data/docs/encoding.md +68 -32
  10. data/docs/heredocs.md +1 -1
  11. data/docs/javascript.md +29 -1
  12. data/docs/releasing.md +4 -1
  13. data/docs/ruby_api.md +14 -0
  14. data/ext/prism/api_node.c +74 -45
  15. data/ext/prism/extconf.rb +91 -127
  16. data/ext/prism/extension.c +4 -1
  17. data/ext/prism/extension.h +1 -1
  18. data/include/prism/ast.h +148 -133
  19. data/include/prism/diagnostic.h +27 -1
  20. data/include/prism/enc/pm_encoding.h +42 -1
  21. data/include/prism/parser.h +6 -0
  22. data/include/prism/version.h +2 -2
  23. data/lib/prism/compiler.rb +3 -3
  24. data/lib/prism/debug.rb +4 -0
  25. data/lib/prism/desugar_compiler.rb +1 -0
  26. data/lib/prism/dispatcher.rb +14 -14
  27. data/lib/prism/dot_visitor.rb +4334 -0
  28. data/lib/prism/dsl.rb +11 -11
  29. data/lib/prism/ffi.rb +3 -3
  30. data/lib/prism/mutation_compiler.rb +6 -6
  31. data/lib/prism/node.rb +182 -113
  32. data/lib/prism/node_ext.rb +61 -3
  33. data/lib/prism/parse_result.rb +46 -12
  34. data/lib/prism/serialize.rb +124 -130
  35. data/lib/prism/visitor.rb +3 -3
  36. data/lib/prism.rb +1 -0
  37. data/prism.gemspec +5 -1
  38. data/rbi/prism.rbi +5565 -5540
  39. data/rbi/prism_static.rbi +138 -142
  40. data/sig/prism.rbs +47 -32
  41. data/src/diagnostic.c +61 -3
  42. data/src/enc/pm_big5.c +63 -0
  43. data/src/enc/pm_cp51932.c +57 -0
  44. data/src/enc/pm_euc_jp.c +10 -0
  45. data/src/enc/pm_gbk.c +5 -2
  46. data/src/enc/pm_tables.c +1478 -148
  47. data/src/node.c +33 -21
  48. data/src/prettyprint.c +1027 -925
  49. data/src/prism.c +925 -374
  50. data/src/regexp.c +12 -12
  51. data/src/serialize.c +36 -9
  52. metadata +6 -2
data/rbi/prism_static.rbi CHANGED
@@ -1,196 +1,192 @@
1
- # typed: true
1
+ class Prism::ParseResult
2
+ sig { returns(Prism::ProgramNode) }
3
+ def value; end
2
4
 
3
- module Prism
4
- class ParseResult
5
- sig { returns(ProgramNode) }
6
- def value; end
5
+ sig { returns(T::Array[Prism::Comment]) }
6
+ def comments; end
7
7
 
8
- sig { returns(T::Array[Comment]) }
9
- def comments; end
8
+ sig { returns(T::Array[Prism::ParseError]) }
9
+ def errors; end
10
10
 
11
- sig { returns(T::Array[ParseError]) }
12
- def errors; end
11
+ sig { returns(T::Array[Prism::ParseWarning]) }
12
+ def warnings; end
13
13
 
14
- sig { returns(T::Array[ParseWarning]) }
15
- def warnings; end
16
-
17
- sig { returns(Source) }
18
- def source; end
19
- end
14
+ sig { returns(Prism::Source) }
15
+ def source; end
16
+ end
20
17
 
21
- class ParseError
22
- sig { returns(String) }
23
- def message; end
18
+ class Prism::ParseError
19
+ sig { returns(String) }
20
+ def message; end
24
21
 
25
- sig { returns(Location) }
26
- def location; end
27
- end
22
+ sig { returns(Prism::Location) }
23
+ def location; end
24
+ end
28
25
 
29
- class ParseWarning
30
- sig { returns(String) }
31
- def message; end
26
+ class Prism::ParseWarning
27
+ sig { returns(String) }
28
+ def message; end
32
29
 
33
- sig { returns(Location) }
34
- def location; end
35
- end
30
+ sig { returns(Prism::Location) }
31
+ def location; end
32
+ end
36
33
 
37
- class Node
38
- sig { returns(T::Array[T.nilable(Node)]) }
39
- def child_nodes; end
34
+ class Prism::Node
35
+ sig { returns(T::Array[T.nilable(Prism::Node)]) }
36
+ def child_nodes; end
40
37
 
41
- sig { returns(Location) }
42
- def location; end
38
+ sig { returns(Prism::Location) }
39
+ def location; end
43
40
 
44
- sig { returns(String) }
45
- def slice; end
46
- end
41
+ sig { returns(String) }
42
+ def slice; end
43
+ end
47
44
 
48
- class Comment
49
- sig { returns(Location) }
50
- def location; end
45
+ class Prism::Comment
46
+ sig { returns(Prism::Location) }
47
+ def location; end
51
48
 
52
- sig { returns(T::Boolean) }
53
- def trailing?; end
54
- end
49
+ sig { returns(T::Boolean) }
50
+ def trailing?; end
51
+ end
55
52
 
56
- class InlineComment < Comment
57
- sig { override.returns(T::Boolean) }
58
- def trailing?; end
59
- end
53
+ class Prism::InlineComment < Prism::Comment
54
+ sig { override.returns(T::Boolean) }
55
+ def trailing?; end
56
+ end
60
57
 
61
- class EmbDocComment < Comment
62
- end
58
+ class Prism::EmbDocComment < Prism::Comment
59
+ end
63
60
 
64
- class DATAComment < Comment
65
- end
61
+ class Prism::DATAComment < Prism::Comment
62
+ end
66
63
 
67
- class Location
68
- sig { params(source: Source, start_offset: Integer, length: Integer).void }
69
- def initialize(source, start_offset, length); end
64
+ class Prism::Location
65
+ sig { params(source: Prism::Source, start_offset: Integer, length: Integer).void }
66
+ def initialize(source, start_offset, length); end
70
67
 
71
- sig { returns(String) }
72
- def slice; end
68
+ sig { returns(String) }
69
+ def slice; end
73
70
 
74
- sig { returns(T::Array[Comment]) }
75
- def comments; end
71
+ sig { returns(T::Array[Prism::Comment]) }
72
+ def comments; end
76
73
 
77
- sig { params(options: T.untyped).returns(Location) }
78
- def copy(**options); end
74
+ sig { params(options: T.untyped).returns(Prism::Location) }
75
+ def copy(**options); end
79
76
 
80
- sig { returns(Integer) }
81
- def start_offset; end
77
+ sig { returns(Integer) }
78
+ def start_offset; end
82
79
 
83
- sig { returns(Integer) }
84
- def end_offset; end
80
+ sig { returns(Integer) }
81
+ def end_offset; end
85
82
 
86
- sig { returns(Integer) }
87
- def start_line; end
83
+ sig { returns(Integer) }
84
+ def start_line; end
88
85
 
89
- sig { returns(Integer) }
90
- def end_line; end
86
+ sig { returns(Integer) }
87
+ def end_line; end
91
88
 
92
- sig { returns(Integer) }
93
- def start_column; end
89
+ sig { returns(Integer) }
90
+ def start_column; end
94
91
 
95
- sig { returns(Integer) }
96
- def end_column; end
97
- end
92
+ sig { returns(Integer) }
93
+ def end_column; end
94
+ end
98
95
 
99
- class Source
100
- sig { params(source: String, start_line: Integer, offsets: T::Array[Integer]).void }
101
- def initialize(source, start_line, offsets); end
96
+ class Prism::Source
97
+ sig { params(source: String, start_line: Integer, offsets: T::Array[Integer]).void }
98
+ def initialize(source, start_line, offsets); end
102
99
 
103
- sig { params(offset: Integer, length: Integer).returns(String) }
104
- def slice(offset, length); end
100
+ sig { params(offset: Integer, length: Integer).returns(String) }
101
+ def slice(offset, length); end
105
102
 
106
- sig { params(value: Integer).returns(Integer) }
107
- def line(value); end
103
+ sig { params(value: Integer).returns(Integer) }
104
+ def line(value); end
108
105
 
109
- sig { params(value: Integer).returns(Integer) }
110
- def line_offset(value); end
106
+ sig { params(value: Integer).returns(Integer) }
107
+ def line_offset(value); end
111
108
 
112
- sig { params(value: Integer).returns(Integer) }
113
- def column(value); end
109
+ sig { params(value: Integer).returns(Integer) }
110
+ def column(value); end
114
111
 
115
- sig { returns(String) }
116
- def source; end
112
+ sig { returns(String) }
113
+ def source; end
117
114
 
118
- sig { returns(T::Array[Integer]) }
119
- def offsets; end
120
- end
115
+ sig { returns(T::Array[Integer]) }
116
+ def offsets; end
117
+ end
121
118
 
122
- class Token
123
- sig { params(type: T.untyped, value: String, location: Location).void }
124
- def initialize(type, value, location); end
119
+ class Prism::Token
120
+ sig { params(type: T.untyped, value: String, location: Prism::Location).void }
121
+ def initialize(type, value, location); end
125
122
 
126
- sig { params(keys: T.untyped).returns(T.untyped) }
127
- def deconstruct_keys(keys); end
123
+ sig { params(keys: T.untyped).returns(T.untyped) }
124
+ def deconstruct_keys(keys); end
128
125
 
129
- sig { params(q: T.untyped).returns(T.untyped) }
130
- def pretty_print(q); end
126
+ sig { params(q: T.untyped).returns(T.untyped) }
127
+ def pretty_print(q); end
131
128
 
132
- sig { params(other: T.untyped).returns(T::Boolean) }
133
- def ==(other); end
129
+ sig { params(other: T.untyped).returns(T::Boolean) }
130
+ def ==(other); end
134
131
 
135
- sig { returns(T.untyped) }
136
- def type; end
132
+ sig { returns(T.untyped) }
133
+ def type; end
137
134
 
138
- sig { returns(String) }
139
- def value; end
135
+ sig { returns(String) }
136
+ def value; end
140
137
 
141
- sig { returns(Location) }
142
- def location; end
143
- end
138
+ sig { returns(Prism::Location) }
139
+ def location; end
140
+ end
144
141
 
145
- class NodeInspector
146
- sig { params(prefix: String).void }
147
- def initialize(prefix); end
142
+ class Prism::NodeInspector
143
+ sig { params(prefix: String).void }
144
+ def initialize(prefix); end
148
145
 
149
- sig { returns(String) }
150
- def prefix; end
146
+ sig { returns(String) }
147
+ def prefix; end
151
148
 
152
- sig { returns(String) }
153
- def output; end
149
+ sig { returns(String) }
150
+ def output; end
154
151
 
155
- # Appends a line to the output with the current prefix.
156
- sig { params(line: String).void }
157
- def <<(line); end
152
+ # Appends a line to the output with the current prefix.
153
+ sig { params(line: String).void }
154
+ def <<(line); end
158
155
 
159
- # This generates a string that is used as the header of the inspect output
160
- # for any given node.
161
- sig { params(node: Node).returns(String) }
162
- def header(node); end
156
+ # This generates a string that is used as the header of the inspect output
157
+ # for any given node.
158
+ sig { params(node: Prism::Node).returns(String) }
159
+ def header(node); end
163
160
 
164
- # Generates a string that represents a list of nodes. It handles properly
165
- # using the box drawing characters to make the output look nice.
166
- sig { params(prefix: String, nodes: T::Array[Node]).returns(String) }
167
- def list(prefix, nodes); end
161
+ # Generates a string that represents a list of nodes. It handles properly
162
+ # using the box drawing characters to make the output look nice.
163
+ sig { params(prefix: String, nodes: T::Array[Prism::Node]).returns(String) }
164
+ def list(prefix, nodes); end
168
165
 
169
- # Generates a string that represents a location field on a node.
170
- sig { params(value: Location).returns(String) }
171
- def location(value); end
166
+ # Generates a string that represents a location field on a node.
167
+ sig { params(value: Prism::Location).returns(String) }
168
+ def location(value); end
172
169
 
173
- # Generates a string that represents a child node.
174
- sig { params(node: Node, append: String).returns(String) }
175
- def child_node(node, append); end
170
+ # Generates a string that represents a child node.
171
+ sig { params(node: Prism::Node, append: String).returns(String) }
172
+ def child_node(node, append); end
176
173
 
177
- # Returns a new inspector that can be used to inspect a child node.
178
- sig { params(append: String).returns(NodeInspector) }
179
- def child_inspector(append); end
174
+ # Returns a new inspector that can be used to inspect a child node.
175
+ sig { params(append: String).returns(Prism::NodeInspector) }
176
+ def child_inspector(append); end
180
177
 
181
- # Returns the output as a string.
182
- sig { returns(String) }
183
- def to_str; end
184
- end
178
+ # Returns the output as a string.
179
+ sig { returns(String) }
180
+ def to_str; end
181
+ end
185
182
 
186
- class BasicVisitor
187
- sig { params(node: T.nilable(Node)).void }
188
- def visit(node); end
183
+ class Prism::BasicVisitor
184
+ sig { params(node: T.nilable(Prism::Node)).void }
185
+ def visit(node); end
189
186
 
190
- sig { params(nodes: T::Array[T.nilable(Node)]).void }
191
- def visit_all(nodes); end
187
+ sig { params(nodes: T::Array[T.nilable(Prism::Node)]).void }
188
+ def visit_all(nodes); end
192
189
 
193
- sig { params(node: Node).void }
194
- def visit_child_nodes(node); end
195
- end
190
+ sig { params(node: Prism::Node).void }
191
+ def visit_child_nodes(node); end
196
192
  end
data/sig/prism.rbs CHANGED
@@ -605,6 +605,35 @@ module Prism
605
605
 
606
606
  def inspect: (inspector: NodeInspector) -> String
607
607
  end
608
+ # Represents the use of a case statement for pattern matching.
609
+ #
610
+ # case true
611
+ # in false
612
+ # end
613
+ # ^^^^^^^^^
614
+ class CaseMatchNode < Node
615
+ attr_reader predicate: Node?
616
+ attr_reader conditions: Array[Node]
617
+ attr_reader consequent: ElseNode?
618
+ attr_reader case_keyword_loc: Location
619
+ attr_reader end_keyword_loc: Location
620
+
621
+ def initialize: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> void
622
+ def accept: (visitor: Visitor) -> void
623
+ def set_newline_flag: (newline_marked: Array[bool]) -> void
624
+ def child_nodes: () -> Array[Node?]
625
+ def deconstruct: () -> Array[Node?]
626
+
627
+ def copy: (**untyped) -> CaseMatchNode
628
+
629
+ def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, (Node | Array[Node] | String | Token | Array[Token] | Location)?]
630
+
631
+ def case_keyword: () -> String
632
+
633
+ def end_keyword: () -> String
634
+
635
+ def inspect: (inspector: NodeInspector) -> String
636
+ end
608
637
  # Represents the use of a case statement.
609
638
  #
610
639
  # case true
@@ -1632,11 +1661,12 @@ module Prism
1632
1661
  class IfNode < Node
1633
1662
  attr_reader if_keyword_loc: Location?
1634
1663
  attr_reader predicate: Node
1664
+ attr_reader then_keyword_loc: Location?
1635
1665
  attr_reader statements: StatementsNode?
1636
1666
  attr_reader consequent: Node?
1637
1667
  attr_reader end_keyword_loc: Location?
1638
1668
 
1639
- def initialize: (if_keyword_loc: Location?, predicate: Node, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> void
1669
+ def initialize: (if_keyword_loc: Location?, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> void
1640
1670
  def accept: (visitor: Visitor) -> void
1641
1671
  def set_newline_flag: (newline_marked: Array[bool]) -> void
1642
1672
  def child_nodes: () -> Array[Node?]
@@ -1648,6 +1678,8 @@ module Prism
1648
1678
 
1649
1679
  def if_keyword: () -> String?
1650
1680
 
1681
+ def then_keyword: () -> String?
1682
+
1651
1683
  def end_keyword: () -> String?
1652
1684
 
1653
1685
  def inspect: (inspector: NodeInspector) -> String
@@ -2471,9 +2503,9 @@ module Prism
2471
2503
  # ^^^^^^^^^^^^^^^^^^^^
2472
2504
  class MatchWriteNode < Node
2473
2505
  attr_reader call: CallNode
2474
- attr_reader locals: Array[Symbol]
2506
+ attr_reader targets: Array[Node]
2475
2507
 
2476
- def initialize: (call: CallNode, locals: Array[Symbol], location: Location) -> void
2508
+ def initialize: (call: CallNode, targets: Array[Node], location: Location) -> void
2477
2509
  def accept: (visitor: Visitor) -> void
2478
2510
  def set_newline_flag: (newline_marked: Array[bool]) -> void
2479
2511
  def child_nodes: () -> Array[Node?]
@@ -3334,26 +3366,6 @@ module Prism
3334
3366
 
3335
3367
  def inspect: (inspector: NodeInspector) -> String
3336
3368
  end
3337
- # Represents the use of compile-time string concatenation.
3338
- #
3339
- # "foo" "bar"
3340
- # ^^^^^^^^^^^
3341
- class StringConcatNode < Node
3342
- attr_reader left: Node
3343
- attr_reader right: Node
3344
-
3345
- def initialize: (left: Node, right: Node, location: Location) -> void
3346
- def accept: (visitor: Visitor) -> void
3347
- def set_newline_flag: (newline_marked: Array[bool]) -> void
3348
- def child_nodes: () -> Array[Node?]
3349
- def deconstruct: () -> Array[Node?]
3350
-
3351
- def copy: (**untyped) -> StringConcatNode
3352
-
3353
- def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, (Node | Array[Node] | String | Token | Array[Token] | Location)?]
3354
-
3355
- def inspect: (inspector: NodeInspector) -> String
3356
- end
3357
3369
  # Represents a string literal, a string contained within a `%w` list, or
3358
3370
  # plain string content within an interpolated string.
3359
3371
  #
@@ -3505,11 +3517,12 @@ module Prism
3505
3517
  class UnlessNode < Node
3506
3518
  attr_reader keyword_loc: Location
3507
3519
  attr_reader predicate: Node
3520
+ attr_reader then_keyword_loc: Location?
3508
3521
  attr_reader statements: StatementsNode?
3509
3522
  attr_reader consequent: ElseNode?
3510
3523
  attr_reader end_keyword_loc: Location?
3511
3524
 
3512
- def initialize: (keyword_loc: Location, predicate: Node, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> void
3525
+ def initialize: (keyword_loc: Location, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> void
3513
3526
  def accept: (visitor: Visitor) -> void
3514
3527
  def set_newline_flag: (newline_marked: Array[bool]) -> void
3515
3528
  def child_nodes: () -> Array[Node?]
@@ -3521,6 +3534,8 @@ module Prism
3521
3534
 
3522
3535
  def keyword: () -> String
3523
3536
 
3537
+ def then_keyword: () -> String?
3538
+
3524
3539
  def end_keyword: () -> String?
3525
3540
 
3526
3541
  def inspect: (inspector: NodeInspector) -> String
@@ -3803,6 +3818,9 @@ module Prism
3803
3818
  # Visit a CapturePatternNode node
3804
3819
  def visit_capture_pattern_node: (node: CapturePatternNode) -> void
3805
3820
 
3821
+ # Visit a CaseMatchNode node
3822
+ def visit_case_match_node: (node: CaseMatchNode) -> void
3823
+
3806
3824
  # Visit a CaseNode node
3807
3825
  def visit_case_node: (node: CaseNode) -> void
3808
3826
 
@@ -4133,9 +4151,6 @@ module Prism
4133
4151
  # Visit a StatementsNode node
4134
4152
  def visit_statements_node: (node: StatementsNode) -> void
4135
4153
 
4136
- # Visit a StringConcatNode node
4137
- def visit_string_concat_node: (node: StringConcatNode) -> void
4138
-
4139
4154
  # Visit a StringNode node
4140
4155
  def visit_string_node: (node: StringNode) -> void
4141
4156
 
@@ -4220,6 +4235,8 @@ module Prism
4220
4235
  def CallOrWriteNode: (receiver: Node?, call_operator_loc: Location?, message_loc: Location?, flags: Integer, read_name: Symbol, write_name: Symbol, operator_loc: Location, value: Node, location: Location) -> CallOrWriteNode
4221
4236
  # Create a new CapturePatternNode node
4222
4237
  def CapturePatternNode: (value: Node, target: Node, operator_loc: Location, location: Location) -> CapturePatternNode
4238
+ # Create a new CaseMatchNode node
4239
+ def CaseMatchNode: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> CaseMatchNode
4223
4240
  # Create a new CaseNode node
4224
4241
  def CaseNode: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> CaseNode
4225
4242
  # Create a new ClassNode node
@@ -4305,7 +4322,7 @@ module Prism
4305
4322
  # Create a new HashPatternNode node
4306
4323
  def HashPatternNode: (constant: Node?, elements: Array[Node], rest: Node?, opening_loc: Location?, closing_loc: Location?, location: Location) -> HashPatternNode
4307
4324
  # Create a new IfNode node
4308
- def IfNode: (if_keyword_loc: Location?, predicate: Node, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> IfNode
4325
+ def IfNode: (if_keyword_loc: Location?, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> IfNode
4309
4326
  # Create a new ImaginaryNode node
4310
4327
  def ImaginaryNode: (numeric: Node, location: Location) -> ImaginaryNode
4311
4328
  # Create a new ImplicitNode node
@@ -4367,7 +4384,7 @@ module Prism
4367
4384
  # Create a new MatchRequiredNode node
4368
4385
  def MatchRequiredNode: (value: Node, pattern: Node, operator_loc: Location, location: Location) -> MatchRequiredNode
4369
4386
  # Create a new MatchWriteNode node
4370
- def MatchWriteNode: (call: CallNode, locals: Array[Symbol], location: Location) -> MatchWriteNode
4387
+ def MatchWriteNode: (call: CallNode, targets: Array[Node], location: Location) -> MatchWriteNode
4371
4388
  # Create a new MissingNode node
4372
4389
  def MissingNode: (location: Location) -> MissingNode
4373
4390
  # Create a new ModuleNode node
@@ -4440,8 +4457,6 @@ module Prism
4440
4457
  def SplatNode: (operator_loc: Location, expression: Node?, location: Location) -> SplatNode
4441
4458
  # Create a new StatementsNode node
4442
4459
  def StatementsNode: (body: Array[Node], location: Location) -> StatementsNode
4443
- # Create a new StringConcatNode node
4444
- def StringConcatNode: (left: Node, right: Node, location: Location) -> StringConcatNode
4445
4460
  # Create a new StringNode node
4446
4461
  def StringNode: (flags: Integer, opening_loc: Location?, content_loc: Location, closing_loc: Location?, unescaped: String, location: Location) -> StringNode
4447
4462
  # Create a new SuperNode node
@@ -4453,7 +4468,7 @@ module Prism
4453
4468
  # Create a new UndefNode node
4454
4469
  def UndefNode: (names: Array[Node], keyword_loc: Location, location: Location) -> UndefNode
4455
4470
  # Create a new UnlessNode node
4456
- def UnlessNode: (keyword_loc: Location, predicate: Node, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> UnlessNode
4471
+ def UnlessNode: (keyword_loc: Location, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> UnlessNode
4457
4472
  # Create a new UntilNode node
4458
4473
  def UntilNode: (keyword_loc: Location, closing_loc: Location?, predicate: Node, statements: StatementsNode?, flags: Integer, location: Location) -> UntilNode
4459
4474
  # Create a new WhenNode node
data/src/diagnostic.c CHANGED
@@ -54,12 +54,14 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
54
54
  [PM_ERR_ALIAS_ARGUMENT] = "Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable",
55
55
  [PM_ERR_AMPAMPEQ_MULTI_ASSIGN] = "Unexpected `&&=` in a multiple assignment",
56
56
  [PM_ERR_ARGUMENT_AFTER_BLOCK] = "Unexpected argument after a block argument",
57
+ [PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = "Unexpected argument after `...`",
57
58
  [PM_ERR_ARGUMENT_BARE_HASH] = "Unexpected bare hash argument",
58
59
  [PM_ERR_ARGUMENT_BLOCK_MULTI] = "Multiple block arguments; only one block is allowed",
59
60
  [PM_ERR_ARGUMENT_FORMAL_CLASS] = "Invalid formal argument; formal argument cannot be a class variable",
60
61
  [PM_ERR_ARGUMENT_FORMAL_CONSTANT] = "Invalid formal argument; formal argument cannot be a constant",
61
62
  [PM_ERR_ARGUMENT_FORMAL_GLOBAL] = "Invalid formal argument; formal argument cannot be a global variable",
62
63
  [PM_ERR_ARGUMENT_FORMAL_IVAR] = "Invalid formal argument; formal argument cannot be an instance variable",
64
+ [PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = "Unexpected `...` in an non-parenthesized call",
63
65
  [PM_ERR_ARGUMENT_NO_FORWARDING_AMP] = "Unexpected `&` when the parent method is not forwarding",
64
66
  [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "Unexpected `...` when the parent method is not forwarding",
65
67
  [PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = "Unexpected `*` when the parent method is not forwarding",
@@ -85,6 +87,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
85
87
  [PM_ERR_CANNOT_PARSE_STRING_PART] = "Cannot parse the string part",
86
88
  [PM_ERR_CASE_EXPRESSION_AFTER_CASE] = "Expected an expression after `case`",
87
89
  [PM_ERR_CASE_EXPRESSION_AFTER_WHEN] = "Expected an expression after `when`",
90
+ [PM_ERR_CASE_MATCH_MISSING_PREDICATE] = "Expected a predicate for a case matching statement",
88
91
  [PM_ERR_CASE_MISSING_CONDITIONS] = "Expected a `when` or `in` clause after `case`",
89
92
  [PM_ERR_CASE_TERM] = "Expected an `end` to close the `case` statement",
90
93
  [PM_ERR_CLASS_IN_METHOD] = "Unexpected class definition in a method body",
@@ -199,7 +202,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
199
202
  [PM_ERR_PARAMETER_NAME_REPEAT] = "Repeated parameter name",
200
203
  [PM_ERR_PARAMETER_NO_DEFAULT] = "Expected a default value for the parameter",
201
204
  [PM_ERR_PARAMETER_NO_DEFAULT_KW] = "Expected a default value for the keyword parameter",
202
- [PM_ERR_PARAMETER_NUMBERED_RESERVED] = "Token reserved for a numbered parameter",
205
+ [PM_ERR_PARAMETER_NUMBERED_RESERVED] = "%.2s is reserved for a numbered parameter",
203
206
  [PM_ERR_PARAMETER_ORDER] = "Unexpected parameter order",
204
207
  [PM_ERR_PARAMETER_SPLAT_MULTI] = "Unexpected multiple `*` splat parameters",
205
208
  [PM_ERR_PARAMETER_STAR] = "Unexpected parameter `*`",
@@ -244,6 +247,7 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
244
247
  [PM_ERR_UNARY_RECEIVER_PLUS] = "Expected a receiver for unary `+`",
245
248
  [PM_ERR_UNARY_RECEIVER_TILDE] = "Expected a receiver for unary `~`",
246
249
  [PM_ERR_UNTIL_TERM] = "Expected an `end` to close the `until` statement",
250
+ [PM_ERR_VOID_EXPRESSION] = "Unexpected void value expression",
247
251
  [PM_ERR_WHILE_TERM] = "Expected an `end` to close the `while` statement",
248
252
  [PM_ERR_WRITE_TARGET_READONLY] = "Immutable variable as a write target",
249
253
  [PM_ERR_WRITE_TARGET_UNEXPECTED] = "Unexpected write target",
@@ -252,13 +256,16 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
252
256
  [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = "Ambiguous first argument; put parentheses or a space even after `+` operator",
253
257
  [PM_WARN_AMBIGUOUS_PREFIX_STAR] = "Ambiguous `*` has been interpreted as an argument prefix",
254
258
  [PM_WARN_AMBIGUOUS_SLASH] = "Ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator",
259
+ [PM_WARN_END_IN_METHOD] = "END in method; use at_exit",
255
260
  };
256
261
 
257
262
  static const char*
258
263
  pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
259
264
  assert(diag_id < PM_DIAGNOSTIC_ID_LEN);
265
+
260
266
  const char *message = diagnostic_messages[diag_id];
261
267
  assert(message);
268
+
262
269
  return message;
263
270
  }
264
271
 
@@ -270,7 +277,57 @@ pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *
270
277
  pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) calloc(sizeof(pm_diagnostic_t), 1);
271
278
  if (diagnostic == NULL) return false;
272
279
 
273
- *diagnostic = (pm_diagnostic_t) { .start = start, .end = end, .message = pm_diagnostic_message(diag_id) };
280
+ *diagnostic = (pm_diagnostic_t) {
281
+ .start = start,
282
+ .end = end,
283
+ .message = pm_diagnostic_message(diag_id),
284
+ .owned = false
285
+ };
286
+
287
+ pm_list_append(list, (pm_list_node_t *) diagnostic);
288
+ return true;
289
+ }
290
+
291
+ /**
292
+ * Append a diagnostic to the given list of diagnostics that is using a format
293
+ * string for its message.
294
+ */
295
+ bool
296
+ pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id, ...) {
297
+ va_list arguments;
298
+ va_start(arguments, diag_id);
299
+
300
+ const char *format = pm_diagnostic_message(diag_id);
301
+ int result = vsnprintf(NULL, 0, format, arguments);
302
+ va_end(arguments);
303
+
304
+ if (result < 0) {
305
+ return false;
306
+ }
307
+
308
+ pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) calloc(sizeof(pm_diagnostic_t), 1);
309
+ if (diagnostic == NULL) {
310
+ return false;
311
+ }
312
+
313
+ size_t length = (size_t) (result + 1);
314
+ char *message = (char *) malloc(length);
315
+ if (message == NULL) {
316
+ free(diagnostic);
317
+ return false;
318
+ }
319
+
320
+ va_start(arguments, diag_id);
321
+ vsnprintf(message, length, format, arguments);
322
+ va_end(arguments);
323
+
324
+ *diagnostic = (pm_diagnostic_t) {
325
+ .start = start,
326
+ .end = end,
327
+ .message = message,
328
+ .owned = true
329
+ };
330
+
274
331
  pm_list_append(list, (pm_list_node_t *) diagnostic);
275
332
  return true;
276
333
  }
@@ -284,8 +341,9 @@ pm_diagnostic_list_free(pm_list_t *list) {
284
341
 
285
342
  for (node = list->head; node != NULL; node = next) {
286
343
  next = node->next;
287
-
288
344
  pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) node;
345
+
346
+ if (diagnostic->owned) free((void *) diagnostic->message);
289
347
  free(diagnostic);
290
348
  }
291
349
  }