Skip to main content

leo_errors/errors/parser/
parser_errors.rs

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