summaryrefslogtreecommitdiff
path: root/prism/templates/src/diagnostic.c.erb
blob: d9e195e08f3f0ed8a02e0bfb2b4656a11fe6343d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
#include "prism/diagnostic.h"

#define PM_DIAGNOSTIC_ID_MAX <%= errors.length + warnings.length %>

/** This struct holds the data for each diagnostic. */
typedef struct {
    /** The message associated with the diagnostic. */
    const char* message;

    /** The level associated with the diagnostic. */
    uint8_t level;
} pm_diagnostic_data_t;

/**
 * ## Message composition
 *
 * When composing an error message, use sentence fragments.
 *
 * Try describing the property of the code that caused the error, rather than
 * the rule that is being violated. It may help to use a fragment that completes
 * a sentence beginning, "the parser encountered (a) ...". If appropriate, add a
 * description of the rule violation (or other helpful context) after a
 * semicolon.
 *
 * For example:, instead of "control escape sequence cannot be doubled", prefer:
 *
 * > "invalid control escape sequence; control cannot be repeated"
 *
 * In some cases, where the failure is more general or syntax expectations are
 * violated, it may make more sense to use a fragment that completes a sentence
 * beginning, "the parser ...".
 *
 * For example:
 *
 * > "expected an expression after `(`"
 * > "cannot parse the expression"
 *
 * ## Message style guide
 *
 * - Use articles like "a", "an", and "the" when appropriate.
 *   - e.g., prefer "cannot parse the expression" to "cannot parse expression".
 * - Use the common name for tokens and nodes.
 *   - e.g., prefer "keyword splat" to "assoc splat"
 *   - e.g., prefer "embedded document" to "embdoc"
 * - Do not capitalize the initial word of the message.
 * - Use back ticks around token literals
 *   - e.g., "Expected a `=>` between the hash key and value"
 * - Do not use `.` or other punctuation at the end of the message.
 * - Do not use contractions like "can't". Prefer "cannot" to "can not".
 * - For tokens that can have multiple meanings, reference the token and its meaning.
 *   - e.g., "`*` splat argument" is clearer and more complete than "splat argument" or "`*` argument"
 *
 * ## Error names (PM_ERR_*)
 *
 * - When appropriate, prefer node name to token name.
 *   - e.g., prefer "SPLAT" to "STAR" in the context of argument parsing.
 * - Prefer token name to common name.
 *   - e.g., prefer "STAR" to "ASTERISK".
 * - Try to order the words in the name from more general to more specific,
 *   - e.g., "INVALID_NUMBER_DECIMAL" is better than "DECIMAL_INVALID_NUMBER".
 *   - When in doubt, look for similar patterns and name them so that they are grouped when lexically
 *     sorted. See PM_ERR_ARGUMENT_NO_FORWARDING_* for an example.
 *
 * ## Level
 *
 * For errors, they are:
 *
 * * `PM_ERROR_LEVEL_SYNTAX` - Errors that should raise SyntaxError.
 * * `PM_ERROR_LEVEL_ARGUMENT` - Errors that should raise ArgumentError.
 * * `PM_ERROR_LEVEL_LOAD` - Errors that should raise LoadError.
 *
 * For warnings, they are:
 *
 * * `PM_WARNING_LEVEL_DEFAULT` - Warnings that appear for `ruby -c -e 'code'`.
 * * `PM_WARNING_LEVEL_VERBOSE` - Warnings that appear with `-w`, as in `ruby -w -c -e 'code'`.
 */
static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
    // Special error that can be replaced
    [PM_ERR_CANNOT_PARSE_EXPRESSION]            = { "cannot parse the expression", PM_ERROR_LEVEL_SYNTAX },

    // Errors that should raise argument errors
    [PM_ERR_INVALID_ENCODING_MAGIC_COMMENT]     = { "unknown or invalid encoding in the magic comment", PM_ERROR_LEVEL_ARGUMENT },

    // Errors that should raise load errors
    [PM_ERR_SCRIPT_NOT_FOUND]                   = { "no Ruby script found in input", PM_ERROR_LEVEL_LOAD },

    // Errors that should raise syntax errors
    [PM_ERR_ALIAS_ARGUMENT]                     = { "invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE]  = { "invalid argument being passed to `alias`; can't make alias for the number variables", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_AMPAMPEQ_MULTI_ASSIGN]              = { "unexpected `&&=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_AFTER_BLOCK]               = { "unexpected argument after a block argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = { "unexpected argument after `...`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_BARE_HASH]                 = { "unexpected bare hash argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_BLOCK_MULTI]               = { "both block arg and actual block given; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_CONFLICT_AMPERSAND]        = { "unexpected `&`; anonymous block parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_CONFLICT_STAR]             = { "unexpected `*`; anonymous rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_CONFLICT_STAR_STAR]        = { "unexpected `**`; anonymous keyword rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_FORMAL_CLASS]              = { "invalid formal argument; formal argument cannot be a class variable", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_FORMAL_CONSTANT]           = { "invalid formal argument; formal argument cannot be a constant", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_FORMAL_GLOBAL]             = { "invalid formal argument; formal argument cannot be a global variable", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_FORMAL_IVAR]               = { "invalid formal argument; formal argument cannot be an instance variable", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_FORWARDING_UNBOUND]        = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_IN]                        = { "unexpected `in` keyword in arguments", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND]   = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES]    = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_NO_FORWARDING_STAR]        = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR]   = { "unexpected `**`; no anonymous keyword rest parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT]   = { "unexpected `*` splat argument after a `**` keyword splat argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_SPLAT_AFTER_SPLAT]         = { "unexpected `*` splat argument after a `*` splat argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_TERM_PAREN]                = { "unexpected %s; expected a `)` to close the arguments", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARGUMENT_UNEXPECTED_BLOCK]          = { "unexpected '{' after a method call without parenthesis", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARRAY_ELEMENT]                      = { "expected an element for the array", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARRAY_EXPRESSION]                   = { "expected an expression for the array element", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARRAY_EXPRESSION_AFTER_STAR]        = { "expected an expression after `*` in the array", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARRAY_SEPARATOR]                    = { "expected a `,` separator for the array elements", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ARRAY_TERM]                         = { "expected a `]` to close the array", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BEGIN_LONELY_ELSE]                  = { "unexpected `else` in `begin` block; else without rescue is useless", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BEGIN_TERM]                         = { "expected an `end` to close the `begin` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BEGIN_UPCASE_BRACE]                 = { "expected a `{` after `BEGIN`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BEGIN_UPCASE_TERM]                  = { "expected a `}` to close the `BEGIN` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BEGIN_UPCASE_TOPLEVEL]              = { "BEGIN is permitted only at toplevel", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE]         = { "expected a local variable name in the block parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BLOCK_PARAM_PIPE_TERM]              = { "expected the block parameters to end with `|`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BLOCK_TERM_BRACE]                   = { "expected a block beginning with `{` to end with `}`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_BLOCK_TERM_END]                     = { "expected a block beginning with `do` to end with `end`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CANNOT_PARSE_STRING_PART]           = { "cannot parse the string part", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CASE_EXPRESSION_AFTER_CASE]         = { "expected an expression after `case`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CASE_EXPRESSION_AFTER_WHEN]         = { "expected an expression after `when`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CASE_MATCH_MISSING_PREDICATE]       = { "expected a predicate for a case matching statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CASE_MISSING_CONDITIONS]            = { "expected a `when` or `in` clause after `case`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CASE_TERM]                          = { "expected an `end` to close the `case` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CLASS_IN_METHOD]                    = { "unexpected class definition in method body", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CLASS_NAME]                         = { "unexpected constant path after `class`; class/module name must be CONSTANT", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CLASS_SUPERCLASS]                   = { "expected a superclass after `<`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CLASS_TERM]                         = { "expected an `end` to close the `class` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CLASS_UNEXPECTED_END]               = { "unexpected `end`, expecting ';' or '\\n'", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CLASS_VARIABLE_BARE]                = { "'@@' without identifiers is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_ELSIF_PREDICATE]        = { "expected a predicate expression for the `elsif` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_IF_PREDICATE]           = { "expected a predicate expression for the `if` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_PREDICATE_TERM]         = { "expected `then` or `;` or '\\n'", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_TERM]                   = { "expected an `end` to close the conditional clause", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_TERM_ELSE]              = { "expected an `end` to close the `else` clause", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_UNLESS_PREDICATE]       = { "expected a predicate expression for the `unless` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_UNTIL_PREDICATE]        = { "expected a predicate expression for the `until` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONDITIONAL_WHILE_PREDICATE]        = { "expected a predicate expression for the `while` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = { "expected a constant after the `::` operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_ENDLESS]                        = { "could not parse the endless method body", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_ENDLESS_SETTER]                 = { "invalid method name; a setter method cannot be defined in an endless method definition", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_NAME]                           = { "unexpected %s; expected a method name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_PARAMS_TERM]                    = { "expected a delimiter to close the parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_PARAMS_TERM_PAREN]              = { "unexpected %s; expected a `)` to close the parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_RECEIVER]                       = { "expected a receiver for the method definition", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_RECEIVER_TERM]                  = { "expected a `.` or `::` after the receiver in a method definition", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEF_TERM]                           = { "expected an `end` to close the `def` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_DEFINED_EXPRESSION]                 = { "expected an expression after `defined?`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EMBDOC_TERM]                        = { "embedded document meets end of file", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EMBEXPR_END]                        = { "expected a `}` to close the embedded expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EMBVAR_INVALID]                     = { "invalid embedded variable", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_END_UPCASE_BRACE]                   = { "expected a `{` after `END`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_END_UPCASE_TERM]                    = { "expected a `}` to close the `END` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_CONTROL]             = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT]      = { "invalid control escape sequence; control cannot be repeated", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_HEXADECIMAL]         = { "invalid hex escape sequence", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_META]                = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_META_REPEAT]         = { "invalid meta escape sequence; meta cannot be repeated", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_UNICODE]             = { "invalid Unicode escape sequence", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS]    = { "invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL]     = { "invalid Unicode escape sequence; Multiple codepoints at single character literal are disallowed", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_UNICODE_LONG]        = { "invalid Unicode escape sequence; maximum length is 6 digits", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_ESCAPE_INVALID_UNICODE_TERM]        = { "unterminated Unicode escape", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_ARGUMENT]                    = { "expected an argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EOL_AFTER_STATEMENT]         = { "unexpected %s, expecting end-of-input", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ]   = { "expected an expression after `&&=`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = { "expected an expression after `||=`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA]      = { "expected an expression after `,`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL]      = { "expected an expression after `=`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS]  = { "expected an expression after `<<`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_LPAREN]     = { "expected an expression after `(`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR]   = { "unexpected %s; expected an expression after the operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT]      = { "expected an expression after `*` splat in an argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = { "expected an expression after `**` in a hash", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_EXPRESSION_AFTER_STAR]       = { "expected an expression after `*`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_IDENT_REQ_PARAMETER]         = { "expected an identifier for the required parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_IN_DELIMITER]                = { "expected a delimiter after the patterns of an `in` clause", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_LPAREN_REQ_PARAMETER]        = { "expected a `(` to start a required parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_MESSAGE]                     = { "unexpected %s; expecting a message to send to the receiver", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_RBRACKET]                    = { "expected a matching `]`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_RPAREN]                      = { "expected a matching `)`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_RPAREN_AFTER_MULTI]          = { "expected a `)` after multiple assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_RPAREN_REQ_PARAMETER]        = { "expected a `)` to end a required parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_STRING_CONTENT]              = { "expected string content after opening string delimiter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPECT_WHEN_DELIMITER]              = { "expected a delimiter after the predicates of a `when` clause", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_BARE_HASH]               = { "unexpected bare hash in expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE]            = { "unexpected '='; target cannot be written", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING]   = { "Can't assign to __ENCODING__", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE]      = { "Can't assign to false", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_FILE]       = { "Can't assign to __FILE__", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_LINE]       = { "Can't assign to __LINE__", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_NIL]        = { "Can't assign to nil", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_SELF]       = { "Can't change the value of self", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE]       = { "Can't assign to true", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_FLOAT_PARSE]                        = { "could not parse the float '%.*s'", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_FOR_COLLECTION]                     = { "expected a collection after the `in` in a `for` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_FOR_INDEX]                          = { "expected an index after `for`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_FOR_IN]                             = { "expected an `in` after the index in a `for` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_FOR_TERM]                           = { "expected an `end` to close the `for` loop", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_GLOBAL_VARIABLE_BARE]               = { "'$' without identifiers is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HASH_EXPRESSION_AFTER_LABEL]        = { "expected an expression after the label in a hash", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HASH_KEY]                           = { "unexpected %s, expecting '}' or a key in the hash literal", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HASH_ROCKET]                        = { "expected a `=>` between the hash key and value", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HASH_TERM]                          = { "expected a `}` to close the hash literal", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HASH_VALUE]                         = { "unexpected %s; expected a value in the hash literal", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HEREDOC_IDENTIFIER]                 = { "unterminated here document identifier", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_HEREDOC_TERM]                       = { "unterminated heredoc; can't find string \"%.*s\" anywhere before EOF", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INCOMPLETE_QUESTION_MARK]           = { "incomplete expression at `?`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3]      = { "`%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INCOMPLETE_VARIABLE_CLASS]          = { "'%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3]   = { "`%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE]       = { "'%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INSTANCE_VARIABLE_BARE]             = { "'@' without identifiers is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_BLOCK_EXIT]                 = { "Invalid %s", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_ESCAPE_CHARACTER]           = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_FLOAT_EXPONENT]             = { "invalid exponent", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_LOCAL_VARIABLE_READ]        = { "identifier %.*s is not valid to get", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_LOCAL_VARIABLE_WRITE]       = { "identifier %.*s is not valid to set", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_BINARY]              = { "invalid binary number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_DECIMAL]             = { "invalid decimal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_FRACTION]            = { "unexpected fraction part after numeric literal", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_HEXADECIMAL]         = { "invalid hexadecimal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_OCTAL]               = { "invalid octal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER]    = { "invalid underscore placement in number", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING] = { "trailing '_' in number", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_CHARACTER]                  = { "Invalid char '\\x%02X' in expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_MULTIBYTE_CHAR]             = { "invalid multibyte char (%s)", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_MULTIBYTE_CHARACTER]        = { "invalid multibyte character 0x%X", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_MULTIBYTE_ESCAPE]           = { "invalid multibyte escape: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_PRINTABLE_CHARACTER]        = { "invalid character `%c`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_PERCENT]                    = { "unknown type of %string", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_PERCENT_EOF]                = { "unterminated quoted string meets end of file", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_RETRY_AFTER_ELSE]           = { "Invalid retry after else", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_RETRY_AFTER_ENSURE]         = { "Invalid retry after ensure", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_RETRY_WITHOUT_RESCUE]       = { "Invalid retry without rescue", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_SYMBOL]                     = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_VARIABLE_GLOBAL_3_3]        = { "`%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_VARIABLE_GLOBAL]            = { "'%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_INVALID_YIELD]                      = { "Invalid yield", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_IT_NOT_ALLOWED_NUMBERED]            = { "`it` is not allowed when an numbered parameter is defined", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_IT_NOT_ALLOWED_ORDINARY]            = { "`it` is not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LAMBDA_OPEN]                        = { "expected a `do` keyword or a `{` to open the lambda block", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LAMBDA_TERM_BRACE]                  = { "expected a lambda block beginning with `{` to end with `}`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LAMBDA_TERM_END]                    = { "expected a lambda block beginning with `do` to end with `end`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_I_LOWER_ELEMENT]               = { "expected a symbol in a `%i` list", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_I_LOWER_TERM]                  = { "unterminated list; expected a closing delimiter for the `%i`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_I_UPPER_ELEMENT]               = { "expected a symbol in a `%I` list", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_I_UPPER_TERM]                  = { "unterminated list; expected a closing delimiter for the `%I`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_W_LOWER_ELEMENT]               = { "expected a string in a `%w` list", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_W_LOWER_TERM]                  = { "unterminated list; expected a closing delimiter for the `%w`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_W_UPPER_ELEMENT]               = { "expected a string in a `%W` list", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_LIST_W_UPPER_TERM]                  = { "unterminated list; expected a closing delimiter for the `%W`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MALLOC_FAILED]                      = { "failed to allocate memory", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MIXED_ENCODING]                     = { "UTF-8 mixed within %s source", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MODULE_IN_METHOD]                   = { "unexpected module definition in method body", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MODULE_NAME]                        = { "unexpected constant path after `module`; class/module name must be CONSTANT", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MODULE_TERM]                        = { "expected an `end` to close the `module` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MULTI_ASSIGN_MULTI_SPLATS]          = { "multiple splats in multiple assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST]       = { "unexpected '%.*s' resulting in multiple splats in multiple assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_NOT_EXPRESSION]                     = { "expected an expression after `not`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_NO_LOCAL_VARIABLE]                  = { "%.*s: no such local variable", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_NUMBER_LITERAL_UNDERSCORE]          = { "number literal ending with a `_`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_NUMBERED_PARAMETER_IT]              = { "numbered parameters are not allowed when an 'it' parameter is defined", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_NUMBERED_PARAMETER_ORDINARY]        = { "numbered parameters are not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE]     = { "numbered parameter is already used in outer scope", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_OPERATOR_MULTI_ASSIGN]              = { "unexpected operator for a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_OPERATOR_WRITE_ARGUMENTS]           = { "unexpected operator after a call with arguments", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_OPERATOR_WRITE_BLOCK]               = { "unexpected operator after a call with a block", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI]        = { "unexpected multiple `**` splat parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_BLOCK_MULTI]              = { "multiple block parameters; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_CIRCULAR]                 = { "circular argument reference - %.*s", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_FORWARDING_AFTER_REST]    = { "... after rest argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_METHOD_NAME]              = { "unexpected name for a parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_NAME_DUPLICATED]          = { "duplicated argument name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_NO_DEFAULT]               = { "expected a default value for the parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_NO_DEFAULT_KW]            = { "expected a default value for the keyword parameter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_NUMBERED_RESERVED]        = { "%.2s is reserved for numbered parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_ORDER]                    = { "unexpected parameter order", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_SPLAT_MULTI]              = { "unexpected multiple `*` splat parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_STAR]                     = { "unexpected parameter `*`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_UNEXPECTED_FWD]           = { "unexpected `...` in parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_WILD_LOOSE_COMMA]         = { "unexpected `,` in parameters", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PARAMETER_UNEXPECTED_NO_KW]         = { "unexpected **nil; no keywords marker disallowed after keywords", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_CAPTURE_DUPLICATE]          = { "duplicated variable name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET]   = { "expected a pattern expression after the `[` operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA]     = { "expected a pattern expression after `,`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET]   = { "expected a pattern expression after `=>`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_IN]        = { "expected a pattern expression after the `in` keyword", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_KEY]       = { "expected a pattern expression after the key", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN]     = { "expected a pattern expression after the `(` operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_PIN]       = { "expected a pattern expression after the `^` pin operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE]      = { "expected a pattern expression after the `|` operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE]     = { "expected a pattern expression after the range operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_EXPRESSION_AFTER_REST]      = { "unexpected pattern expression after the `**` expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_HASH_IMPLICIT]              = { "unexpected implicit hash in pattern; use '{' to delineate", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_HASH_KEY]                   = { "unexpected %s; expected a key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_HASH_KEY_DUPLICATE]         = { "duplicated key name", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_HASH_KEY_INTERPOLATED]      = { "symbol literal with interpolation is not allowed", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_HASH_KEY_LABEL]             = { "expected a label as the key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_HASH_KEY_LOCALS]            = { "key must be valid as local variables", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_IDENT_AFTER_HROCKET]        = { "expected an identifier after the `=>` operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_LABEL_AFTER_COMMA]          = { "expected a label after the `,` in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_REST]                       = { "unexpected rest pattern", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_TERM_BRACE]                 = { "expected a `}` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_TERM_BRACKET]               = { "expected a `]` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PATTERN_TERM_PAREN]                 = { "expected a `)` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN]            = { "unexpected `||=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH]    = { "regexp encoding option '%c' differs from source encoding '%s'", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING]      = { "incompatible character encoding: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_NON_ESCAPED_MBC]             = { "/.../n has a non escaped non ASCII character in non ASCII-8BIT script: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_INVALID_UNICODE_RANGE]       = { "invalid Unicode range: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_UNKNOWN_OPTIONS]             = { "unknown regexp %s: %.*s", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_TERM]                        = { "unterminated regexp meets end of file; expected a closing delimiter", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP]   = { "UTF-8 character in non UTF-8 regexp: /%s/", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_RESCUE_EXPRESSION]                  = { "expected a rescued expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_RESCUE_MODIFIER_VALUE]              = { "expected a value after the `rescue` modifier", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_RESCUE_TERM]                        = { "expected a closing delimiter for the `rescue` clause", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_RESCUE_VARIABLE]                    = { "expected an exception variable after `=>` in a rescue statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_RETURN_INVALID]                     = { "Invalid return in class/module body", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_SINGLETON_FOR_LITERALS]             = { "cannot define singleton method for literals", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STATEMENT_ALIAS]                    = { "unexpected an `alias` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STATEMENT_POSTEXE_END]              = { "unexpected an `END` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STATEMENT_PREEXE_BEGIN]             = { "unexpected a `BEGIN` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STATEMENT_UNDEF]                    = { "unexpected an `undef` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STRING_CONCATENATION]               = { "expected a string for concatenation", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STRING_INTERPOLATED_TERM]           = { "unterminated string; expected a closing delimiter for the interpolated string", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STRING_LITERAL_EOF]                 = { "unterminated string meets end of file", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_STRING_LITERAL_TERM]                = { "unexpected %s, expected a string literal terminator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_SYMBOL_INVALID]                     = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX }, // TODO expected symbol? prism.c ~9719
    [PM_ERR_SYMBOL_TERM_DYNAMIC]                = { "unterminated quoted string; expected a closing delimiter for the dynamic symbol", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_SYMBOL_TERM_INTERPOLATED]           = { "unterminated symbol; expected a closing delimiter for the interpolated symbol", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_TERNARY_COLON]                      = { "expected a `:` after the true expression of a ternary operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_TERNARY_EXPRESSION_FALSE]           = { "expected an expression after `:` in the ternary operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_TERNARY_EXPRESSION_TRUE]            = { "expected an expression after `?` in the ternary operator", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNDEF_ARGUMENT]                     = { "invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNARY_RECEIVER]                     = { "unexpected %s, expected a receiver for unary `%c`", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNEXPECTED_BLOCK_ARGUMENT]          = { "block argument should not be given", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNEXPECTED_INDEX_BLOCK]             = { "unexpected block arg given in index; blocks are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNEXPECTED_INDEX_KEYWORDS]          = { "unexpected keyword arg given in index; keywords are not allowed in index expressions", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNEXPECTED_SAFE_NAVIGATION]         = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT]     = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNEXPECTED_TOKEN_IGNORE]            = { "unexpected %s, ignoring it", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_UNTIL_TERM]                         = { "expected an `end` to close the `until` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_VOID_EXPRESSION]                    = { "unexpected void value expression", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_WHILE_TERM]                         = { "expected an `end` to close the `while` statement", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_WRITE_TARGET_IN_METHOD]             = { "dynamic constant assignment", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_WRITE_TARGET_READONLY]              = { "Can't set variable %.*s", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_WRITE_TARGET_UNEXPECTED]            = { "unexpected write target", PM_ERROR_LEVEL_SYNTAX },
    [PM_ERR_XSTRING_TERM]                       = { "expected a closing delimiter for the `%x` or backtick string", PM_ERROR_LEVEL_SYNTAX },

    // Warnings
    [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS]    = { "ambiguous first argument; put parentheses or a space even after `-` operator", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS]     = { "ambiguous first argument; put parentheses or a space even after `+` operator", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND]        = { "ambiguous `&` has been interpreted as an argument prefix", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_AMBIGUOUS_PREFIX_STAR]             = { "ambiguous `*` has been interpreted as an argument prefix", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR]        = { "ambiguous `**` has been interpreted as an argument prefix", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_AMBIGUOUS_SLASH]                   = { "ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_COMPARISON_AFTER_COMPARISON]       = { "comparison '%.*s' after comparison", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_DOT_DOT_DOT_EOL]                   = { "... at EOL, should be parenthesized?", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_DUPLICATED_HASH_KEY]               = { "key %.*s is duplicated and overwritten on line %" PRIi32, PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_DUPLICATED_WHEN_CLAUSE]            = { "duplicated 'when' clause with line %" PRIi32 " is ignored", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_EQUAL_IN_CONDITIONAL_3_3]          = { "found `= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_EQUAL_IN_CONDITIONAL]              = { "found '= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_END_IN_METHOD]                     = { "END in method; use at_exit", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_FLOAT_OUT_OF_RANGE]                = { "Float %.*s%s out of range", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_IGNORED_FROZEN_STRING_LITERAL]     = { "'frozen_string_literal' is ignored after any tokens", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_INTEGER_IN_FLIP_FLOP]              = { "integer literal in flip-flop", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_INVALID_CHARACTER]                 = { "invalid character syntax; use %s%s%s", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_INVALID_SHAREABLE_CONSTANT_VALUE]  = { "invalid value for shareable_constant_value: %.*s", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_INVALID_NUMBERED_REFERENCE]        = { "'%.*s' is too big for a number variable, always nil", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_KEYWORD_EOL]                       = { "`%.*s` at the end of line without an expression", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_LITERAL_IN_CONDITION_DEFAULT]      = { "%sliteral in %s", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_LITERAL_IN_CONDITION_VERBOSE]      = { "%sliteral in %s", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE]     = { "'shareable_constant_value' is ignored unless in comment-only line", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_SHEBANG_CARRIAGE_RETURN]           = { "shebang line ending with \\r may cause problems", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_UNEXPECTED_CARRIAGE_RETURN]        = { "encountered \\r in middle of line, treated as a mere space", PM_WARNING_LEVEL_DEFAULT },
    [PM_WARN_UNREACHABLE_STATEMENT]             = { "statement not reached", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_UNUSED_LOCAL_VARIABLE]             = { "assigned but unused variable - %.*s", PM_WARNING_LEVEL_VERBOSE },
    [PM_WARN_VOID_STATEMENT]                    = { "possibly useless use of %.*s in void context", PM_WARNING_LEVEL_VERBOSE }
};

/**
 * Get the human-readable name of the given diagnostic ID.
 */
const char *
pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) {
    switch (diag_id) {
        <%- errors.each do |error| -%>
        case PM_ERR_<%= error.name %>: return "<%= error.name.downcase %>";
        <%- end -%>
        <%- warnings.each do |warning| -%>
        case PM_WARN_<%= warning.name %>: return "<%= warning.name.downcase %>";
        <%- end -%>
    }

    assert(false && "unreachable");
    return "";
}

static inline const char *
pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
    assert(diag_id < PM_DIAGNOSTIC_ID_MAX);

    const char *message = diagnostic_messages[diag_id].message;
    assert(message);

    return message;
}

static inline uint8_t
pm_diagnostic_level(pm_diagnostic_id_t diag_id) {
    assert(diag_id < PM_DIAGNOSTIC_ID_MAX);

    return (uint8_t) diagnostic_messages[diag_id].level;
}

/**
 * Append an error to the given list of diagnostic.
 */
bool
pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
    pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) xcalloc(1, sizeof(pm_diagnostic_t));
    if (diagnostic == NULL) return false;

    *diagnostic = (pm_diagnostic_t) {
        .location = { start, end },
        .diag_id = diag_id,
        .message = pm_diagnostic_message(diag_id),
        .owned = false,
        .level = pm_diagnostic_level(diag_id)
    };

    pm_list_append(list, (pm_list_node_t *) diagnostic);
    return true;
}

/**
 * Append a diagnostic to the given list of diagnostics that is using a format
 * string for its message.
 */
bool
pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id, ...) {
    va_list arguments;
    va_start(arguments, diag_id);

    const char *format = pm_diagnostic_message(diag_id);
    int result = vsnprintf(NULL, 0, format, arguments);
    va_end(arguments);

    if (result < 0) {
        return false;
    }

    pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) xcalloc(1, sizeof(pm_diagnostic_t));
    if (diagnostic == NULL) {
        return false;
    }

    size_t length = (size_t) (result + 1);
    char *message = (char *) xmalloc(length);
    if (message == NULL) {
        xfree(diagnostic);
        return false;
    }

    va_start(arguments, diag_id);
    vsnprintf(message, length, format, arguments);
    va_end(arguments);

    *diagnostic = (pm_diagnostic_t) {
        .location = { start, end },
        .diag_id = diag_id,
        .message = message,
        .owned = true,
        .level = pm_diagnostic_level(diag_id)
    };

    pm_list_append(list, (pm_list_node_t *) diagnostic);
    return true;
}

/**
 * Deallocate the internal state of the given diagnostic list.
 */
void
pm_diagnostic_list_free(pm_list_t *list) {
    pm_diagnostic_t *node = (pm_diagnostic_t *) list->head;

    while (node != NULL) {
        pm_diagnostic_t *next = (pm_diagnostic_t *) node->node.next;

        if (node->owned) xfree((void *) node->message);
        xfree(node);

        node = next;
    }
}