yarp 0.10.0 → 0.12.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.
data/lib/yarp.rb CHANGED
@@ -20,6 +20,10 @@ module YARP
20
20
  offsets.bsearch_index { |offset| offset > value } || offsets.length
21
21
  end
22
22
 
23
+ def line_offset(value)
24
+ offsets[line(value) - 1]
25
+ end
26
+
23
27
  def column(value)
24
28
  value - offsets[line(value) - 1]
25
29
  end
@@ -46,10 +50,14 @@ module YARP
46
50
  # The length of this location in bytes.
47
51
  attr_reader :length
48
52
 
53
+ # The list of comments attached to this location
54
+ attr_reader :comments
55
+
49
56
  def initialize(source, start_offset, length)
50
57
  @source = source
51
58
  @start_offset = start_offset
52
59
  @length = length
60
+ @comments = []
53
61
  end
54
62
 
55
63
  # Create a new location object with the given options.
@@ -81,6 +89,12 @@ module YARP
81
89
  source.line(start_offset)
82
90
  end
83
91
 
92
+ # The content of the line where this location starts before this location.
93
+ def start_line_slice
94
+ offset = source.line_offset(start_offset)
95
+ source.slice(offset, start_offset - offset)
96
+ end
97
+
84
98
  # The line number where this location ends.
85
99
  def end_line
86
100
  source.line(end_offset - 1)
@@ -95,7 +109,7 @@ module YARP
95
109
  # The column number in bytes where this location ends from the start of the
96
110
  # line.
97
111
  def end_column
98
- source.column(end_offset - 1)
112
+ source.column(end_offset)
99
113
  end
100
114
 
101
115
  def deconstruct_keys(keys)
@@ -141,6 +155,15 @@ module YARP
141
155
  def deconstruct_keys(keys)
142
156
  { type: type, location: location }
143
157
  end
158
+
159
+ # Returns true if the comment happens on the same line as other code and false if the comment is by itself
160
+ def trailing?
161
+ type == :inline && !location.start_line_slice.strip.empty?
162
+ end
163
+
164
+ def inspect
165
+ "#<YARP::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"
166
+ end
144
167
  end
145
168
 
146
169
  # This represents an error that was encountered during parsing.
@@ -155,6 +178,10 @@ module YARP
155
178
  def deconstruct_keys(keys)
156
179
  { message: message, location: location }
157
180
  end
181
+
182
+ def inspect
183
+ "#<YARP::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
184
+ end
158
185
  end
159
186
 
160
187
  # This represents a warning that was encountered during parsing.
@@ -169,6 +196,10 @@ module YARP
169
196
  def deconstruct_keys(keys)
170
197
  { message: message, location: location }
171
198
  end
199
+
200
+ def inspect
201
+ "#<YARP::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
202
+ end
172
203
  end
173
204
 
174
205
  # A class that knows how to walk down the tree. None of the individual visit
@@ -217,45 +248,6 @@ module YARP
217
248
  def failure?
218
249
  !success?
219
250
  end
220
-
221
- # Keep in sync with Java MarkNewlinesVisitor
222
- class MarkNewlinesVisitor < YARP::Visitor
223
- def initialize(newline_marked)
224
- @newline_marked = newline_marked
225
- end
226
-
227
- def visit_block_node(node)
228
- old_newline_marked = @newline_marked
229
- @newline_marked = Array.new(old_newline_marked.size, false)
230
- begin
231
- super(node)
232
- ensure
233
- @newline_marked = old_newline_marked
234
- end
235
- end
236
- alias_method :visit_lambda_node, :visit_block_node
237
-
238
- def visit_if_node(node)
239
- node.set_newline_flag(@newline_marked)
240
- super(node)
241
- end
242
- alias_method :visit_unless_node, :visit_if_node
243
-
244
- def visit_statements_node(node)
245
- node.body.each do |child|
246
- child.set_newline_flag(@newline_marked)
247
- end
248
- super(node)
249
- end
250
- end
251
- private_constant :MarkNewlinesVisitor
252
-
253
- def mark_newlines
254
- newline_marked = Array.new(1 + @source.offsets.size, false)
255
- visitor = MarkNewlinesVisitor.new(newline_marked)
256
- value.accept(visitor)
257
- value
258
- end
259
251
  end
260
252
 
261
253
  # This represents a token from the Ruby source.
@@ -315,45 +307,72 @@ module YARP
315
307
  end
316
308
 
317
309
  def pretty_print(q)
318
- q.group do
319
- q.text(self.class.name.split("::").last)
320
- location.pretty_print(q)
321
- q.text("[Li:#{location.start_line}]") if newline?
322
- q.text("(")
323
- q.nest(2) do
324
- deconstructed = deconstruct_keys([])
325
- deconstructed.delete(:location)
310
+ q.text(inspect.chomp)
311
+ end
312
+ end
326
313
 
327
- q.breakable("")
328
- q.seplist(deconstructed, lambda { q.comma_breakable }, :each_value) { |value| q.pp(value) }
329
- end
330
- q.breakable("")
331
- q.text(")")
314
+ # This object is responsible for generating the output for the inspect method
315
+ # implementations of child nodes.
316
+ class NodeInspector
317
+ attr_reader :prefix, :output
318
+
319
+ def initialize(prefix = "")
320
+ @prefix = prefix
321
+ @output = +""
322
+ end
323
+
324
+ # Appends a line to the output with the current prefix.
325
+ def <<(line)
326
+ output << "#{prefix}#{line}"
327
+ end
328
+
329
+ # This generates a string that is used as the header of the inspect output
330
+ # for any given node.
331
+ def header(node)
332
+ output = +"@ #{node.class.name.split("::").last} ("
333
+ output << "location: (#{node.location.start_offset}...#{node.location.end_offset})"
334
+ output << ", newline: true" if node.newline?
335
+ output << ")\n"
336
+ output
337
+ end
338
+
339
+ # Generates a string that represents a list of nodes. It handles properly
340
+ # using the box drawing characters to make the output look nice.
341
+ def list(prefix, nodes)
342
+ output = +"(length: #{nodes.length})\n"
343
+ last_index = nodes.length - 1
344
+
345
+ nodes.each_with_index do |node, index|
346
+ pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "]
347
+ node_prefix = "#{prefix}#{preadd}"
348
+ output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}")
332
349
  end
350
+
351
+ output
333
352
  end
334
- end
335
353
 
336
- class FloatNode < Node
337
- def value
338
- Float(slice)
354
+ # Generates a string that represents a location field on a node.
355
+ def location(value)
356
+ if value
357
+ "(#{value.start_offset}...#{value.end_offset}) = #{value.slice.inspect}"
358
+ else
359
+ "∅"
360
+ end
339
361
  end
340
- end
341
362
 
342
- class ImaginaryNode < Node
343
- def value
344
- Complex(0, numeric.value)
363
+ # Generates a string that represents a child node.
364
+ def child_node(node, append)
365
+ node.inspect(child_inspector(append)).delete_prefix(prefix)
345
366
  end
346
- end
347
367
 
348
- class IntegerNode < Node
349
- def value
350
- Integer(slice)
368
+ # Returns a new inspector that can be used to inspect a child node.
369
+ def child_inspector(append)
370
+ NodeInspector.new("#{prefix}#{append}")
351
371
  end
352
- end
353
372
 
354
- class RationalNode < Node
355
- def value
356
- Rational(slice.chomp("r"))
373
+ # Returns the output as a string.
374
+ def to_str
375
+ output
357
376
  end
358
377
  end
359
378
 
@@ -421,10 +440,6 @@ module YARP
421
440
  # arguments. We get rid of that here.
422
441
  names = names.grep_v(Integer)
423
442
 
424
- # TODO: We don't support numbered local variables yet, so we get rid
425
- # of those here.
426
- names = names.grep_v(/^_\d$/)
427
-
428
443
  # For some reason, CRuby occasionally pushes this special local
429
444
  # variable when there are splat arguments. We get rid of that here.
430
445
  names = names.grep_v(:"#arg_rest")
@@ -464,10 +479,10 @@ module YARP
464
479
  sorted = [
465
480
  *params.requireds.grep(RequiredParameterNode).map(&:name),
466
481
  *params.optionals.map(&:name),
467
- *((params.rest.name ? params.rest.name.to_sym : :*) if params.rest && params.rest.operator != ","),
482
+ *((params.rest.name || :*) if params.rest && params.rest.operator != ","),
468
483
  *params.posts.grep(RequiredParameterNode).map(&:name),
469
- *params.keywords.reject(&:value).map { |param| param.name.chomp(":").to_sym },
470
- *params.keywords.select(&:value).map { |param| param.name.chomp(":").to_sym }
484
+ *params.keywords.reject(&:value).map(&:name),
485
+ *params.keywords.select(&:value).map(&:name)
471
486
  ]
472
487
 
473
488
  # TODO: When we get a ... parameter, we should be pushing * and &
@@ -533,9 +548,69 @@ require_relative "yarp/node"
533
548
  require_relative "yarp/ripper_compat"
534
549
  require_relative "yarp/serialize"
535
550
  require_relative "yarp/pack"
551
+ require_relative "yarp/pattern"
552
+
553
+ require_relative "yarp/parse_result/comments"
554
+ require_relative "yarp/parse_result/newlines"
536
555
 
537
556
  if RUBY_ENGINE == "ruby" and !ENV["YARP_FFI_BACKEND"]
538
557
  require "yarp/yarp"
539
558
  else
540
559
  require_relative "yarp/ffi"
541
560
  end
561
+
562
+ # Reopening the YARP module after yarp/node is required so that constant
563
+ # reflection APIs will find the constants defined in the node file before these.
564
+ # This block is meant to contain extra APIs we define on YARP nodes that aren't
565
+ # templated and are meant as convenience methods.
566
+ module YARP
567
+ class FloatNode < Node
568
+ # Returns the value of the node as a Ruby Float.
569
+ def value
570
+ Float(slice)
571
+ end
572
+ end
573
+
574
+ class ImaginaryNode < Node
575
+ # Returns the value of the node as a Ruby Complex.
576
+ def value
577
+ Complex(0, numeric.value)
578
+ end
579
+ end
580
+
581
+ class IntegerNode < Node
582
+ # Returns the value of the node as a Ruby Integer.
583
+ def value
584
+ Integer(slice)
585
+ end
586
+ end
587
+
588
+ class InterpolatedRegularExpressionNode < Node
589
+ # Returns a numeric value that represents the flags that were used to create
590
+ # the regular expression.
591
+ def options
592
+ o = flags & 0b111
593
+ o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
594
+ o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
595
+ o
596
+ end
597
+ end
598
+
599
+ class RationalNode < Node
600
+ # Returns the value of the node as a Ruby Rational.
601
+ def value
602
+ Rational(slice.chomp("r"))
603
+ end
604
+ end
605
+
606
+ class RegularExpressionNode < Node
607
+ # Returns a numeric value that represents the flags that were used to create
608
+ # the regular expression.
609
+ def options
610
+ o = flags & 0b111
611
+ o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
612
+ o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
613
+ o
614
+ end
615
+ end
616
+ end
data/src/diagnostic.c CHANGED
@@ -1,12 +1,269 @@
1
1
  #include "yarp/diagnostic.h"
2
2
 
3
+ /*
4
+ ## Message composition
5
+
6
+ When composing an error message, use sentence fragments.
7
+
8
+ Try describing the property of the code that caused the error, rather than the rule that is being
9
+ violated. It may help to use a fragment that completes a sentence beginning, "The parser
10
+ encountered (a) ...". If appropriate, add a description of the rule violation (or other helpful
11
+ context) after a semicolon.
12
+
13
+ For example:, instead of "Control escape sequence cannot be doubled", prefer:
14
+
15
+ > "Invalid control escape sequence; control cannot be repeated"
16
+
17
+ In some cases, where the failure is more general or syntax expectations are violated, it may make
18
+ more sense to use a fragment that completes a sentence beginning, "The parser ...".
19
+
20
+ For example:
21
+
22
+ > "Expected an expression after `(`"
23
+ > "Cannot parse the expression"
24
+
25
+
26
+ ## Message style guide
27
+
28
+ - Use articles like "a", "an", and "the" when appropriate.
29
+ - e.g., prefer "Cannot parse the expression" to "Cannot parse expression".
30
+ - Use the common name for tokens and nodes.
31
+ - e.g., prefer "keyword splat" to "assoc splat"
32
+ - e.g., prefer "embedded document" to "embdoc"
33
+ - Capitalize the initial word of the message.
34
+ - Use back ticks around token literals
35
+ - e.g., "Expected a `=>` between the hash key and value"
36
+ - Do not use `.` or other punctuation at the end of the message.
37
+ - Do not use contractions like "can't". Prefer "cannot" to "can not".
38
+ - For tokens that can have multiple meanings, reference the token and its meaning.
39
+ - e.g., "`*` splat argument" is clearer and more complete than "splat argument" or "`*` argument"
40
+
41
+
42
+ ## Error names (YP_ERR_*)
43
+
44
+ - When appropriate, prefer node name to token name.
45
+ - e.g., prefer "SPLAT" to "STAR" in the context of argument parsing.
46
+ - Prefer token name to common name.
47
+ - e.g., prefer "STAR" to "ASTERISK".
48
+ - Try to order the words in the name from more general to more specific,
49
+ - e.g., "INVALID_NUMBER_DECIMAL" is better than "DECIMAL_INVALID_NUMBER".
50
+ - When in doubt, look for similar patterns and name them so that they are grouped when lexically
51
+ sorted. See YP_ERR_ARGUMENT_NO_FORWARDING_* for an example.
52
+ */
53
+
54
+ static const char* const diagnostic_messages[YP_DIAGNOSTIC_ID_LEN] = {
55
+ [YP_ERR_ALIAS_ARGUMENT] = "Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable",
56
+ [YP_ERR_AMPAMPEQ_MULTI_ASSIGN] = "Unexpected `&&=` in a multiple assignment",
57
+ [YP_ERR_ARGUMENT_AFTER_BLOCK] = "Unexpected argument after a block argument",
58
+ [YP_ERR_ARGUMENT_BARE_HASH] = "Unexpected bare hash argument",
59
+ [YP_ERR_ARGUMENT_BLOCK_MULTI] = "Multiple block arguments; only one block is allowed",
60
+ [YP_ERR_ARGUMENT_FORMAL_CLASS] = "Invalid formal argument; formal argument cannot be a class variable",
61
+ [YP_ERR_ARGUMENT_FORMAL_CONSTANT] = "Invalid formal argument; formal argument cannot be a constant",
62
+ [YP_ERR_ARGUMENT_FORMAL_GLOBAL] = "Invalid formal argument; formal argument cannot be a global variable",
63
+ [YP_ERR_ARGUMENT_FORMAL_IVAR] = "Invalid formal argument; formal argument cannot be an instance variable",
64
+ [YP_ERR_ARGUMENT_NO_FORWARDING_AMP] = "Unexpected `&` when the parent method is not forwarding",
65
+ [YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "Unexpected `...` when the parent method is not forwarding",
66
+ [YP_ERR_ARGUMENT_NO_FORWARDING_STAR] = "Unexpected `*` when the parent method is not forwarding",
67
+ [YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = "Unexpected `*` splat argument after a `**` keyword splat argument",
68
+ [YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT] = "Unexpected `*` splat argument after a `*` splat argument",
69
+ [YP_ERR_ARGUMENT_TERM_PAREN] = "Expected a `)` to close the arguments",
70
+ [YP_ERR_ARGUMENT_UNEXPECTED_BLOCK] = "Unexpected `{` after a method call without parenthesis",
71
+ [YP_ERR_ARRAY_ELEMENT] = "Expected an element for the array",
72
+ [YP_ERR_ARRAY_EXPRESSION] = "Expected an expression for the array element",
73
+ [YP_ERR_ARRAY_EXPRESSION_AFTER_STAR] = "Expected an expression after `*` in the array",
74
+ [YP_ERR_ARRAY_SEPARATOR] = "Expected a `,` separator for the array elements",
75
+ [YP_ERR_ARRAY_TERM] = "Expected a `]` to close the array",
76
+ [YP_ERR_BEGIN_LONELY_ELSE] = "Unexpected `else` in `begin` block; a `rescue` clause must precede `else`",
77
+ [YP_ERR_BEGIN_TERM] = "Expected an `end` to close the `begin` statement",
78
+ [YP_ERR_BEGIN_UPCASE_BRACE] = "Expected a `{` after `BEGIN`",
79
+ [YP_ERR_BEGIN_UPCASE_TERM] = "Expected a `}` to close the `BEGIN` statement",
80
+ [YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE] = "Expected a local variable name in the block parameters",
81
+ [YP_ERR_BLOCK_PARAM_PIPE_TERM] = "Expected the block parameters to end with `|`",
82
+ [YP_ERR_BLOCK_TERM_BRACE] = "Expected a block beginning with `{` to end with `}`",
83
+ [YP_ERR_BLOCK_TERM_END] = "Expected a block beginning with `do` to end with `end`",
84
+ [YP_ERR_CANNOT_PARSE_EXPRESSION] = "Cannot parse the expression",
85
+ [YP_ERR_CANNOT_PARSE_STRING_PART] = "Cannot parse the string part",
86
+ [YP_ERR_CASE_EXPRESSION_AFTER_CASE] = "Expected an expression after `case`",
87
+ [YP_ERR_CASE_EXPRESSION_AFTER_WHEN] = "Expected an expression after `when`",
88
+ [YP_ERR_CASE_MISSING_CONDITIONS] = "Expected a `when` or `in` clause after `case`",
89
+ [YP_ERR_CASE_TERM] = "Expected an `end` to close the `case` statement",
90
+ [YP_ERR_CLASS_IN_METHOD] = "Unexpected class definition in a method body",
91
+ [YP_ERR_CLASS_NAME] = "Expected a constant name after `class`",
92
+ [YP_ERR_CLASS_SUPERCLASS] = "Expected a superclass after `<`",
93
+ [YP_ERR_CLASS_TERM] = "Expected an `end` to close the `class` statement",
94
+ [YP_ERR_CONDITIONAL_ELSIF_PREDICATE] = "Expected a predicate expression for the `elsif` statement",
95
+ [YP_ERR_CONDITIONAL_IF_PREDICATE] = "Expected a predicate expression for the `if` statement",
96
+ [YP_ERR_CONDITIONAL_TERM] = "Expected an `end` to close the conditional clause",
97
+ [YP_ERR_CONDITIONAL_TERM_ELSE] = "Expected an `end` to close the `else` clause",
98
+ [YP_ERR_CONDITIONAL_UNLESS_PREDICATE] = "Expected a predicate expression for the `unless` statement",
99
+ [YP_ERR_CONDITIONAL_UNTIL_PREDICATE] = "Expected a predicate expression for the `until` statement",
100
+ [YP_ERR_CONDITIONAL_WHILE_PREDICATE] = "Expected a predicate expression for the `while` statement",
101
+ [YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = "Expected a constant after the `::` operator",
102
+ [YP_ERR_DEF_ENDLESS] = "Could not parse the endless method body",
103
+ [YP_ERR_DEF_ENDLESS_SETTER] = "Invalid method name; a setter method cannot be defined in an endless method definition",
104
+ [YP_ERR_DEF_NAME] = "Expected a method name",
105
+ [YP_ERR_DEF_NAME_AFTER_RECEIVER] = "Expected a method name after the receiver",
106
+ [YP_ERR_DEF_PARAMS_TERM] = "Expected a delimiter to close the parameters",
107
+ [YP_ERR_DEF_PARAMS_TERM_PAREN] = "Expected a `)` to close the parameters",
108
+ [YP_ERR_DEF_RECEIVER] = "Expected a receiver for the method definition",
109
+ [YP_ERR_DEF_RECEIVER_TERM] = "Expected a `.` or `::` after the receiver in a method definition",
110
+ [YP_ERR_DEF_TERM] = "Expected an `end` to close the `def` statement",
111
+ [YP_ERR_DEFINED_EXPRESSION] = "Expected an expression after `defined?`",
112
+ [YP_ERR_EMBDOC_TERM] = "Could not find a terminator for the embedded document",
113
+ [YP_ERR_EMBEXPR_END] = "Expected a `}` to close the embedded expression",
114
+ [YP_ERR_EMBVAR_INVALID] = "Invalid embedded variable",
115
+ [YP_ERR_END_UPCASE_BRACE] = "Expected a `{` after `END`",
116
+ [YP_ERR_END_UPCASE_TERM] = "Expected a `}` to close the `END` statement",
117
+ [YP_ERR_ESCAPE_INVALID_CONTROL] = "Invalid control escape sequence",
118
+ [YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT] = "Invalid control escape sequence; control cannot be repeated",
119
+ [YP_ERR_ESCAPE_INVALID_HEXADECIMAL] = "Invalid hexadecimal escape sequence",
120
+ [YP_ERR_ESCAPE_INVALID_META] = "Invalid meta escape sequence",
121
+ [YP_ERR_ESCAPE_INVALID_META_REPEAT] = "Invalid meta escape sequence; meta cannot be repeated",
122
+ [YP_ERR_ESCAPE_INVALID_UNICODE] = "Invalid Unicode escape sequence",
123
+ [YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS] = "Invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags",
124
+ [YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = "Invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal",
125
+ [YP_ERR_ESCAPE_INVALID_UNICODE_LONG] = "Invalid Unicode escape sequence; maximum length is 6 digits",
126
+ [YP_ERR_ESCAPE_INVALID_UNICODE_TERM] = "Invalid Unicode escape sequence; needs closing `}`",
127
+ [YP_ERR_EXPECT_ARGUMENT] = "Expected an argument",
128
+ [YP_ERR_EXPECT_EOL_AFTER_STATEMENT] = "Expected a newline or semicolon after the statement",
129
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = "Expected an expression after `&&=`",
130
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = "Expected an expression after `||=`",
131
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA] = "Expected an expression after `,`",
132
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL] = "Expected an expression after `=`",
133
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS] = "Expected an expression after `<<`",
134
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_LPAREN] = "Expected an expression after `(`",
135
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = "Expected an expression after the operator",
136
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = "Expected an expression after `*` splat in an argument",
137
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = "Expected an expression after `**` in a hash",
138
+ [YP_ERR_EXPECT_EXPRESSION_AFTER_STAR] = "Expected an expression after `*`",
139
+ [YP_ERR_EXPECT_IDENT_REQ_PARAMETER] = "Expected an identifier for the required parameter",
140
+ [YP_ERR_EXPECT_LPAREN_REQ_PARAMETER] = "Expected a `(` to start a required parameter",
141
+ [YP_ERR_EXPECT_RBRACKET] = "Expected a matching `]`",
142
+ [YP_ERR_EXPECT_RPAREN] = "Expected a matching `)`",
143
+ [YP_ERR_EXPECT_RPAREN_AFTER_MULTI] = "Expected a `)` after multiple assignment",
144
+ [YP_ERR_EXPECT_RPAREN_REQ_PARAMETER] = "Expected a `)` to end a required parameter",
145
+ [YP_ERR_EXPECT_STRING_CONTENT] = "Expected string content after opening string delimiter",
146
+ [YP_ERR_EXPECT_WHEN_DELIMITER] = "Expected a delimiter after the predicates of a `when` clause",
147
+ [YP_ERR_EXPRESSION_BARE_HASH] = "Unexpected bare hash in expression",
148
+ [YP_ERR_FOR_COLLECTION] = "Expected a collection after the `in` in a `for` statement",
149
+ [YP_ERR_FOR_INDEX] = "Expected an index after `for`",
150
+ [YP_ERR_FOR_IN] = "Expected an `in` after the index in a `for` statement",
151
+ [YP_ERR_FOR_TERM] = "Expected an `end` to close the `for` loop",
152
+ [YP_ERR_HASH_EXPRESSION_AFTER_LABEL] = "Expected an expression after the label in a hash",
153
+ [YP_ERR_HASH_KEY] = "Expected a key in the hash literal",
154
+ [YP_ERR_HASH_ROCKET] = "Expected a `=>` between the hash key and value",
155
+ [YP_ERR_HASH_TERM] = "Expected a `}` to close the hash literal",
156
+ [YP_ERR_HASH_VALUE] = "Expected a value in the hash literal",
157
+ [YP_ERR_HEREDOC_TERM] = "Could not find a terminator for the heredoc",
158
+ [YP_ERR_INCOMPLETE_QUESTION_MARK] = "Incomplete expression at `?`",
159
+ [YP_ERR_INCOMPLETE_VARIABLE_CLASS] = "Incomplete class variable",
160
+ [YP_ERR_INCOMPLETE_VARIABLE_INSTANCE] = "Incomplete instance variable",
161
+ [YP_ERR_INVALID_ENCODING_MAGIC_COMMENT] = "Unknown or invalid encoding in the magic comment",
162
+ [YP_ERR_INVALID_FLOAT_EXPONENT] = "Invalid exponent",
163
+ [YP_ERR_INVALID_NUMBER_BINARY] = "Invalid binary number",
164
+ [YP_ERR_INVALID_NUMBER_DECIMAL] = "Invalid decimal number",
165
+ [YP_ERR_INVALID_NUMBER_HEXADECIMAL] = "Invalid hexadecimal number",
166
+ [YP_ERR_INVALID_NUMBER_OCTAL] = "Invalid octal number",
167
+ [YP_ERR_INVALID_NUMBER_UNDERSCORE] = "Invalid underscore placement in number",
168
+ [YP_ERR_INVALID_PERCENT] = "Invalid `%` token", // TODO WHAT?
169
+ [YP_ERR_INVALID_TOKEN] = "Invalid token", // TODO WHAT?
170
+ [YP_ERR_INVALID_VARIABLE_GLOBAL] = "Invalid global variable",
171
+ [YP_ERR_LAMBDA_OPEN] = "Expected a `do` keyword or a `{` to open the lambda block",
172
+ [YP_ERR_LAMBDA_TERM_BRACE] = "Expected a lambda block beginning with `{` to end with `}`",
173
+ [YP_ERR_LAMBDA_TERM_END] = "Expected a lambda block beginning with `do` to end with `end`",
174
+ [YP_ERR_LIST_I_LOWER_ELEMENT] = "Expected a symbol in a `%i` list",
175
+ [YP_ERR_LIST_I_LOWER_TERM] = "Expected a closing delimiter for the `%i` list",
176
+ [YP_ERR_LIST_I_UPPER_ELEMENT] = "Expected a symbol in a `%I` list",
177
+ [YP_ERR_LIST_I_UPPER_TERM] = "Expected a closing delimiter for the `%I` list",
178
+ [YP_ERR_LIST_W_LOWER_ELEMENT] = "Expected a string in a `%w` list",
179
+ [YP_ERR_LIST_W_LOWER_TERM] = "Expected a closing delimiter for the `%w` list",
180
+ [YP_ERR_LIST_W_UPPER_ELEMENT] = "Expected a string in a `%W` list",
181
+ [YP_ERR_LIST_W_UPPER_TERM] = "Expected a closing delimiter for the `%W` list",
182
+ [YP_ERR_MALLOC_FAILED] = "Failed to allocate memory",
183
+ [YP_ERR_MODULE_IN_METHOD] = "Unexpected module definition in a method body",
184
+ [YP_ERR_MODULE_NAME] = "Expected a constant name after `module`",
185
+ [YP_ERR_MODULE_TERM] = "Expected an `end` to close the `module` statement",
186
+ [YP_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "Multiple splats in multiple assignment",
187
+ [YP_ERR_NOT_EXPRESSION] = "Expected an expression after `not`",
188
+ [YP_ERR_NUMBER_LITERAL_UNDERSCORE] = "Number literal ending with a `_`",
189
+ [YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "Numbered parameters are not allowed alongside explicit parameters",
190
+ [YP_ERR_NUMBERED_PARAMETER_OUTER_SCOPE] = "Numbered parameter is already used in outer scope",
191
+ [YP_ERR_OPERATOR_MULTI_ASSIGN] = "Unexpected operator for a multiple assignment",
192
+ [YP_ERR_OPERATOR_WRITE_BLOCK] = "Unexpected operator after a call with a block",
193
+ [YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = "Unexpected multiple `**` splat parameters",
194
+ [YP_ERR_PARAMETER_BLOCK_MULTI] = "Multiple block parameters; only one block is allowed",
195
+ [YP_ERR_PARAMETER_NAME_REPEAT] = "Repeated parameter name",
196
+ [YP_ERR_PARAMETER_NO_DEFAULT] = "Expected a default value for the parameter",
197
+ [YP_ERR_PARAMETER_NO_DEFAULT_KW] = "Expected a default value for the keyword parameter",
198
+ [YP_ERR_PARAMETER_NUMBERED_RESERVED] = "Token reserved for a numbered parameter",
199
+ [YP_ERR_PARAMETER_ORDER] = "Unexpected parameter order",
200
+ [YP_ERR_PARAMETER_SPLAT_MULTI] = "Unexpected multiple `*` splat parameters",
201
+ [YP_ERR_PARAMETER_STAR] = "Unexpected parameter `*`",
202
+ [YP_ERR_PARAMETER_WILD_LOOSE_COMMA] = "Unexpected `,` in parameters",
203
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = "Expected a pattern expression after the `[` operator",
204
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = "Expected a pattern expression after `,`",
205
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = "Expected a pattern expression after `=>`",
206
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_IN] = "Expected a pattern expression after the `in` keyword",
207
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_KEY] = "Expected a pattern expression after the key",
208
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN] = "Expected a pattern expression after the `(` operator",
209
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_PIN] = "Expected a pattern expression after the `^` pin operator",
210
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = "Expected a pattern expression after the `|` operator",
211
+ [YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = "Expected a pattern expression after the range operator",
212
+ [YP_ERR_PATTERN_HASH_KEY] = "Expected a key in the hash pattern",
213
+ [YP_ERR_PATTERN_HASH_KEY_LABEL] = "Expected a label as the key in the hash pattern", // TODO // THIS // AND // ABOVE // IS WEIRD
214
+ [YP_ERR_PATTERN_IDENT_AFTER_HROCKET] = "Expected an identifier after the `=>` operator",
215
+ [YP_ERR_PATTERN_LABEL_AFTER_COMMA] = "Expected a label after the `,` in the hash pattern",
216
+ [YP_ERR_PATTERN_REST] = "Unexpected rest pattern",
217
+ [YP_ERR_PATTERN_TERM_BRACE] = "Expected a `}` to close the pattern expression",
218
+ [YP_ERR_PATTERN_TERM_BRACKET] = "Expected a `]` to close the pattern expression",
219
+ [YP_ERR_PATTERN_TERM_PAREN] = "Expected a `)` to close the pattern expression",
220
+ [YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN] = "Unexpected `||=` in a multiple assignment",
221
+ [YP_ERR_REGEXP_TERM] = "Expected a closing delimiter for the regular expression",
222
+ [YP_ERR_RESCUE_EXPRESSION] = "Expected a rescued expression",
223
+ [YP_ERR_RESCUE_MODIFIER_VALUE] = "Expected a value after the `rescue` modifier",
224
+ [YP_ERR_RESCUE_TERM] = "Expected a closing delimiter for the `rescue` clause",
225
+ [YP_ERR_RESCUE_VARIABLE] = "Expected an exception variable after `=>` in a rescue statement",
226
+ [YP_ERR_RETURN_INVALID] = "Invalid `return` in a class or module body",
227
+ [YP_ERR_STRING_CONCATENATION] = "Expected a string for concatenation",
228
+ [YP_ERR_STRING_INTERPOLATED_TERM] = "Expected a closing delimiter for the interpolated string",
229
+ [YP_ERR_STRING_LITERAL_TERM] = "Expected a closing delimiter for the string literal",
230
+ [YP_ERR_SYMBOL_INVALID] = "Invalid symbol", // TODO expected symbol? yarp.c ~9719
231
+ [YP_ERR_SYMBOL_TERM_DYNAMIC] = "Expected a closing delimiter for the dynamic symbol",
232
+ [YP_ERR_SYMBOL_TERM_INTERPOLATED] = "Expected a closing delimiter for the interpolated symbol",
233
+ [YP_ERR_TERNARY_COLON] = "Expected a `:` after the true expression of a ternary operator",
234
+ [YP_ERR_TERNARY_EXPRESSION_FALSE] = "Expected an expression after `:` in the ternary operator",
235
+ [YP_ERR_TERNARY_EXPRESSION_TRUE] = "Expected an expression after `?` in the ternary operator",
236
+ [YP_ERR_UNDEF_ARGUMENT] = "Invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument",
237
+ [YP_ERR_UNARY_RECEIVER_BANG] = "Expected a receiver for unary `!`",
238
+ [YP_ERR_UNARY_RECEIVER_MINUS] = "Expected a receiver for unary `-`",
239
+ [YP_ERR_UNARY_RECEIVER_PLUS] = "Expected a receiver for unary `+`",
240
+ [YP_ERR_UNARY_RECEIVER_TILDE] = "Expected a receiver for unary `~`",
241
+ [YP_ERR_UNTIL_TERM] = "Expected an `end` to close the `until` statement",
242
+ [YP_ERR_WHILE_TERM] = "Expected an `end` to close the `while` statement",
243
+ [YP_ERR_WRITE_TARGET_READONLY] = "Immutable variable as a write target",
244
+ [YP_ERR_WRITE_TARGET_UNEXPECTED] = "Unexpected write target",
245
+ [YP_ERR_XSTRING_TERM] = "Expected a closing delimiter for the `%x` or backtick string",
246
+ [YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = "Ambiguous first argument; put parentheses or a space even after `-` operator",
247
+ [YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = "Ambiguous first argument; put parentheses or a space even after `+` operator",
248
+ [YP_WARN_AMBIGUOUS_PREFIX_STAR] = "Ambiguous `*` has been interpreted as an argument prefix",
249
+ [YP_WARN_AMBIGUOUS_SLASH] = "Ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator",
250
+ };
251
+
252
+ static const char*
253
+ yp_diagnostic_message(yp_diagnostic_id_t diag_id) {
254
+ assert(diag_id < YP_DIAGNOSTIC_ID_LEN);
255
+ const char *message = diagnostic_messages[diag_id];
256
+ assert(message);
257
+ return message;
258
+ }
259
+
3
260
  // Append an error to the given list of diagnostic.
4
261
  bool
5
- yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, const char *message) {
262
+ yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, yp_diagnostic_id_t diag_id) {
6
263
  yp_diagnostic_t *diagnostic = (yp_diagnostic_t *) malloc(sizeof(yp_diagnostic_t));
7
264
  if (diagnostic == NULL) return false;
8
265
 
9
- *diagnostic = (yp_diagnostic_t) { .start = start, .end = end, .message = message };
266
+ *diagnostic = (yp_diagnostic_t) { .start = start, .end = end, .message = yp_diagnostic_message(diag_id) };
10
267
  yp_list_append(list, (yp_list_node_t *) diagnostic);
11
268
  return true;
12
269
  }
data/src/enc/yp_unicode.c CHANGED
@@ -10,7 +10,7 @@ typedef uint32_t yp_unicode_codepoint_t;
10
10
  // this table is different from other encodings where we used a lookup table
11
11
  // because the indices of those tables are the byte representations, not the
12
12
  // codepoints themselves.
13
- uint8_t yp_encoding_unicode_table[256] = {
13
+ const uint8_t yp_encoding_unicode_table[256] = {
14
14
  // 0 1 2 3 4 5 6 7 8 9 A B C D E F
15
15
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
16
16
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
@@ -31,7 +31,7 @@ uint8_t yp_encoding_unicode_table[256] = {
31
31
  };
32
32
 
33
33
  #define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450
34
- static yp_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = {
34
+ static const yp_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = {
35
35
  0x100, 0x2C1,
36
36
  0x2C6, 0x2D1,
37
37
  0x2E0, 0x2E4,
@@ -760,7 +760,7 @@ static yp_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_
760
760
  };
761
761
 
762
762
  #define UNICODE_ALNUM_CODEPOINTS_LENGTH 1528
763
- static yp_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = {
763
+ static const yp_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = {
764
764
  0x100, 0x2C1,
765
765
  0x2C6, 0x2D1,
766
766
  0x2E0, 0x2E4,
@@ -1528,7 +1528,7 @@ static yp_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_
1528
1528
  };
1529
1529
 
1530
1530
  #define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1296
1531
- static yp_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = {
1531
+ static const yp_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = {
1532
1532
  0x100, 0x100,
1533
1533
  0x102, 0x102,
1534
1534
  0x104, 0x104,
@@ -2180,7 +2180,7 @@ static yp_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOI
2180
2180
  };
2181
2181
 
2182
2182
  static bool
2183
- yp_unicode_codepoint_match(yp_unicode_codepoint_t codepoint, yp_unicode_codepoint_t *codepoints, size_t size) {
2183
+ yp_unicode_codepoint_match(yp_unicode_codepoint_t codepoint, const yp_unicode_codepoint_t *codepoints, size_t size) {
2184
2184
  size_t start = 0;
2185
2185
  size_t end = size;
2186
2186