leo_errors/errors/parser/
parser_errors.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use crate::create_messages;
18
19use std::fmt::{Debug, Display};
20
21create_messages!(
22    /// ParserError enum that represents all the errors for the `leo-parser` crate.
23    ParserError,
24    code_mask: 0000i32,
25    code_prefix: "PAR",
26
27    /// For when the parser encountered an unexpected token.
28    @formatted
29    unexpected_token {
30        args: (message: impl Display),
31        msg: message,
32        help: None,
33    }
34
35    /// For when the parser encountered an invalid address literal.
36    @formatted
37    invalid_address_lit {
38        args: (token: impl Display),
39        msg: format!("invalid address literal: '{token}'"),
40        help: None,
41    }
42
43    /// For when the parser encountered an empty import list.
44    @formatted
45    invalid_import_list {
46        args: (),
47        msg: "Cannot import empty list",
48        help: None,
49    }
50
51    /// For when the parser encountered an unexpected End of File.
52    @formatted
53    unexpected_eof {
54        args: (),
55        msg: "unexpected EOF",
56        help: None,
57    }
58
59    /// For when the parser encountered an unexpected whitespace.
60    // TODO This error is unused. Remove it in a future version.
61    @formatted
62    unexpected_whitespace {
63        args: (left: impl Display, right: impl Display),
64        msg: format!("Unexpected white space between terms {left} and {right}"),
65        help: None,
66    }
67
68    /// For when the parser encountered an unexpected list of tokens.
69    @formatted
70    unexpected {
71        args: (found: impl Display, expected: impl Display),
72        msg: format!("expected {expected} -- found '{found}'"),
73        help: None,
74    }
75
76    /// For when the parser encountered a mix of commas and semi-colons in struct member variables.
77    // TODO This error is unused. Remove it in a future version.
78    @formatted
79    mixed_commas_and_semicolons {
80        args: (),
81        msg: "Cannot mix use of commas and semi-colons for struct member variable declarations.",
82        help: None,
83    }
84
85    /// For when the parser encountered an unexpected identifier.
86    // TODO This error is unused. Remove it in a future version.
87    @formatted
88    unexpected_ident {
89        args: (found: impl Display, expected: &[impl Display]),
90        msg: format!(
91            "unexpected identifier: expected {} -- found '{found}'",
92            expected
93                .iter()
94                .map(|x| format!("'{x}'"))
95                .collect::<Vec<_>>()
96                .join(", "),
97        ),
98        help: None,
99    }
100
101    /// For when the parser encountered an unexpected statement.
102    // TODO This error is unused. Remove it in a future version.
103    @formatted
104    unexpected_statement {
105        args: (found: impl Display, expected: impl Display),
106        msg: format!("unexpected statement: expected '{expected}', found '{found}'"),
107        help: None,
108    }
109
110    /// For when the parser encountered an unexpected string.
111    // TODO This error is unused. Remove it in a future version.
112    @formatted
113    unexpected_str {
114        args: (found: impl Display, expected: impl Display),
115        msg: format!("unexpected string: expected '{expected}', found '{found}'"),
116        help: None,
117    }
118
119    /// For when the parser encountered an unexpected spread in an array init expression.
120    @formatted
121    spread_in_array_init {
122        args: (),
123        msg: "illegal spread in array initializer",
124        help: None,
125    }
126
127    /// When more input was expected but not found.
128    // TODO This error is unused. Remove it in a future version.
129    @backtraced
130    lexer_empty_input {
131        args: (),
132        msg: "Expected more characters to lex but found none.",
133        help: None,
134    }
135
136    /// When an integer is started with a leading zero.
137    // TODO This error is unused. Remove it in a future version.
138    @backtraced
139    lexer_expected_valid_escaped_char {
140    args: (input: impl Display),
141    msg: format!("Expected a valid escape character but found `{input}`."),
142    help: None,
143    }
144
145    /// When a string is not properly closed.
146    // TODO This error is unused. Remove it in a future version.
147    @backtraced
148    lexer_string_not_closed {
149    args: (input: impl Display),
150    msg: format!("Expected a closed string but found `{input}`."),
151    help: None,
152    }
153
154    /// When a block comment is empty.
155    // TODO This error is unused. Remove it in a future version.
156    @backtraced
157    lexer_empty_block_comment {
158    args: (),
159    msg: "Empty block comment.",
160    help: None,
161    }
162
163    /// When a block comment is not closed before end of file.
164    // TODO This error is unused. Remove it in a future version.
165    @backtraced
166    lexer_block_comment_does_not_close_before_eof {
167    args: (input: impl Display),
168    msg: format!("Block comment does not close with content: `{input}`."),
169    help: None,
170    }
171
172    /// When the lexer could not lex some text.
173    @backtraced
174    could_not_lex {
175    args: (input: impl Display),
176    msg: format!("Could not lex the following content: `{input}`.\n"),
177    help: None,
178    }
179
180    /// When the user tries to pass an implicit value.
181    // TODO This error is unused. Remove it in a future version.
182    @formatted
183    implicit_values_not_allowed {
184        args: (input: impl Display),
185        msg: format!("Could not parse the implicit value: {input}."),
186        help: None,
187    }
188
189    /// When a hex number is provided.
190    // TODO This error is unused. Remove it in a future version.
191    @backtraced
192    lexer_hex_number_provided {
193        args: (input: impl Display),
194        msg: format!("A hex number `{input}..` was provided but hex is not allowed."),
195        help: None,
196    }
197
198    /// For when a user specified more than one mode on a parameter.
199    // TODO This error is unused. Remove it in a future version.
200    @formatted
201    inputs_multiple_variable_modes_specified {
202        args: (),
203        msg: "A parameter cannot have multiple modes.",
204        help: Some("Consider using either `constant`, `public`, `private`, or none at all.".to_string()),
205    }
206
207    /// For when the lexer encountered a bidi override character
208    @backtraced
209    lexer_bidi_override {
210        args: (),
211        msg: "Unicode bidi override code point encountered.",
212        help: None,
213    }
214
215    /// Parsed an unknown method call on the type of an expression.
216    @formatted
217    invalid_method_call {
218        args: (expr: impl Display, func: impl Display, num_args: impl Display),
219        msg: format!("The type of `{expr}` has no associated function `{func}` that takes {num_args} argument(s)."),
220        help: None,
221    }
222
223    // TODO This error is unused. Remove it in a future version.
224    @formatted
225    invalid_associated_access {
226        args: (name: impl Display),
227        msg: format!("Invalid associated access call to struct {name}."),
228        help: Some("Double colon `::` syntax is only supported for core functions in Leo for mainnet.".to_string()),
229    }
230
231    // TODO This error is unused. Remove it in a future version.
232    @formatted
233    leo_and_aleo_imports_only {
234        args: (),
235        msg: "Invalid import call to non-leo non-aleo file.",
236        help: Some("Only imports of Leo `.leo` and Aleo `.aleo` files are currently supported.".to_string()),
237    }
238
239    // TODO This error is unused. Remove it in a future version.
240    @formatted
241    space_in_annotation {
242        args: (),
243        msg: "Illegal spacing in the annotation declaration.",
244        help: Some("Remove whitespace between the `@` symbol and the identifier.".to_string()),
245    }
246
247    // TODO This error is unused. Remove it in a future version.
248    @formatted
249    circuit_is_deprecated {
250        args: (),
251        msg: "The keyword `circuit` is deprecated.",
252        help: Some("Use `struct` instead.".to_string()),
253    }
254
255    // TODO This error is unused. Remove it in a future version.
256    @formatted
257    only_one_program_scope_is_allowed {
258        args: (),
259        msg: "Only one program scope is allowed in a Leo file.",
260        help: None,
261    }
262
263    // TODO This error is unused. Remove it in a future version.
264    @formatted
265    missing_program_scope {
266        args: (),
267        msg: "Missing a program scope in a Leo file.",
268        help: Some("Add a program scope of the form: `program <name>.aleo { ... }` to the Leo file.".to_string()),
269    }
270
271    @formatted
272    invalid_network {
273        args: (),
274        msg: "Invalid network identifier. The only supported identifier is `.aleo`.",
275        help: None,
276    }
277
278    @formatted
279    tuple_must_have_at_least_two_elements {
280        args: (kind: impl Display),
281        msg: format!("A tuple {kind} must have at least two elements."),
282        help: None,
283    }
284
285    // TODO This error is unused. Remove it in a future version.
286    @formatted
287    async_finalize_is_deprecated {
288        args: (),
289        msg: format!("`async finalize` is deprecated."),
290        help: Some("Use `return <expr> then finalize(<args>)` instead.".to_string()),
291    }
292
293    // TODO This error is unused. Remove it in a future version.
294    @formatted
295    finalize_statements_are_deprecated {
296        args: (),
297        msg: format!("`finalize` statements are deprecated."),
298        help: Some("Use `return <expr> then finalize(<args>)` instead.".to_string()),
299    }
300
301    // TODO This error is unused. Remove it in a future version.
302    @formatted
303    console_statements_are_not_yet_supported {
304        args: (),
305        msg: format!("`console` statements are not yet supported."),
306        help: Some("Consider using `assert`, `assert_eq`, or `assert_neq` instead.".to_string()),
307    }
308
309    /// Enforce that tuple index must not have leading 0, or underscore in between digits
310    // TODO This error is unused. Remove it in a future version.
311    @formatted
312    tuple_index_must_be_whole_number {
313        args: (found: impl Display),
314        msg: format!("expected no underscores or leading zeros -- found '{found}'"),
315        help: None,
316    }
317
318    @formatted
319    array_must_have_at_least_one_element {
320        args: (kind: impl Display),
321        msg: format!("An array {kind} must have at least one element."),
322        help: None,
323    }
324
325    // TODO This error is unused. Remove it in a future version.
326    @formatted
327    invalid_external_type {
328        args: (),
329        msg: format!("Invalid external type."),
330        help: Some("External type should have the form `<program>.aleo/<record>`. For example `bank.aleo/loan`".to_string()),
331    }
332
333    // TODO This error is unused. Remove it in a future version.
334    @formatted
335    cannot_declare_external_struct {
336        args: (),
337        msg: format!("Cannot declare external struct."),
338        help: None,
339    }
340
341    // TODO This error is unused. Remove it in a future version.
342    @formatted
343    external_type_cannot_be_used_inside_function {
344        args: (program: impl Display, file_type: impl Display),
345        msg: format!("External types cannot be used inside function (only as input/output types) -- found exported type from '{program}.{file_type}'."),
346        help: None,
347    }
348
349    /// Enforce that cannot use import in program scope
350    // TODO This error is unused. Remove it in a future version.
351    @formatted
352    cannot_import_inside_program_body {
353        args: (),
354        msg: format!("Cannot use import inside program body."),
355        help: None,
356    }
357
358    // TODO This error is unused. Remove it in a future version.
359    @formatted
360    only_aleo_external_calls {
361        args: (),
362        msg: format!("Only external calls to `.aleo` programs are supported."),
363        help: None,
364    }
365
366    @formatted
367    cannot_define_external_record {
368        args: (),
369        msg: format!("Cannot create an external record. Records can only be created in the program that they are defined in."),
370        help: None,
371    }
372
373    /// For when the parser encountered a member declaration not followed by a comma.
374    // TODO This error is unused. Remove it in a future version.
375    @formatted
376    comma_expected_after_member {
377        args: (),
378        msg: "Each member declaration in a struct or record must be followed by a comma (except the last).",
379        help: None,
380    }
381
382    @formatted
383    hexbin_literal_nonintegers {
384        args: (),
385        msg: format!("Hex, octal, and binary literals may only be used for integer types."),
386        help: None,
387    }
388
389    @backtraced
390    wrong_digit_for_radix {
391        args: (digit: char, radix: u32, token: String),
392        msg: format!("Digit {digit} invalid in radix {radix} (token {token})."),
393        help: None,
394    }
395
396    @formatted
397    identifier_too_long {
398        args: (ident: impl Display, length: usize, max_length: usize),
399        msg: format!("Identifier {ident} is too long ({length} bytes; maximum is {max_length})"),
400        help: None,
401    }
402
403    // TODO This error is unused. Remove it in a future version.
404    @formatted
405    expected_identifier {
406        args: (),
407        msg: format!("Expected an identifier."),
408        help: None,
409    }
410
411    @formatted
412    identifier_cannot_contain_double_underscore {
413        args : (ident: impl Display),
414        msg: format!("Identifier {ident} cannot contain a double underscore `__`"),
415        help: None,
416    }
417
418    @formatted
419    custom {
420        args: (msg: impl Display),
421        msg: format!("{msg}"),
422        help: None,
423    }
424
425    // TODO This error is unused. Remove it in a future version.
426    @backtraced
427    conflicting_module_definitions {
428        args: (module_name: impl Display, file_a: impl Display, file_b: impl Display),
429        msg: format!(
430            "Module `{module_name}` is defined in both `{file_a}` and `{file_b}`"
431        ),
432        help: Some({
433            let module_path_fs = format!("{module_name}").replace("::", "/");
434            format!(
435                "Use `{module_path_fs}.leo` for a simple module with no submodules, or place a `mod.leo` file in a `{module_path_fs}/` directory if it contains submodules — not both."
436            )
437        }),
438    }
439
440    @backtraced
441    keyword_used_as_module_name {
442        args: (module_name: impl Display, keyword: impl Display),
443        msg: format!(
444            "Module `{module_name}` uses the reserved keyword `{keyword}` as a name"
445        ),
446        help: {
447            Some(format!(
448                "Rename the module so it does not conflict with the language keyword `{keyword}`."
449            ))
450        },
451    }
452
453    @formatted
454    could_not_lex_span {
455    args: (input: impl Display),
456    msg: format!("Could not lex the following content: `{input}`.\n"),
457    help: None,
458    }
459
460    /// For when the lexer encountered a bidi override character
461    @formatted
462    lexer_bidi_override_span {
463        args: (),
464        msg: "Unicode bidi override code point encountered.",
465        help: None,
466    }
467
468    @formatted
469    wrong_digit_for_radix_span {
470        args: (digit: char, radix: u32, token: impl Display),
471        msg: format!("Digit {digit} invalid in radix {radix} (token {token})."),
472        help: None,
473    }
474);