prism 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }