Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/parser-lossless/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ extern {
Arrow => LalrToken{ token: Token::Arrow, .. },
BigArrow => LalrToken{ token: Token::BigArrow, .. },
At => LalrToken{ token: Token::At, .. },
// Underscore => tokens::Token::Underscore,
Underscore => LalrToken { token: Token::Underscore, .. },

// Keywords
True => LalrToken { token: Token::True, .. },
Expand Down
8 changes: 8 additions & 0 deletions compiler/parser-lossless/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ pub enum Token {
// with an LR(1) parser - we potentially get shift-reduce conflicts and other ambiguities between
// member accesses, program ids, tuple accesses, etc. We could make it work but let's just cut to the
// chase here.

// Catch identifiers starting with underscore
#[regex(r"_[a-zA-Z][a-zA-Z0-9_]*", priority = 10)]
InvalidLeadingUnderscoreIdent,

#[regex(r"[a-zA-Z][a-zA-Z0-9_]*", id_variant)]
// We need to special case `group::abc` and `signature::abc` as otherwise these are keywords.
#[token(r"group::[a-zA-Z][a-zA-Z0-9_]*", |_| IdVariants::Path)]
Expand Down Expand Up @@ -514,6 +519,9 @@ impl<'a> Iterator for Lexer<'a> {
if matches!(token, Token::Bidi) {
self.handler.emit_err(ParserError::lexer_bidi_override_span(span));
return None;
} else if matches!(token, Token::InvalidLeadingUnderscoreIdent) {
self.handler.emit_err(ParserError::identifier_cannot_start_with_underscore(span));
return None;
} else if matches!(token, Token::Integer) {
let (s, radix) = if let Some(s) = text.strip_prefix("0x") {
(s, 16)
Expand Down
7 changes: 7 additions & 0 deletions errors/src/errors/parser/parser_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,11 @@ create_messages!(
msg: format!("Digit {digit} invalid in radix {radix} (token {token})."),
help: None,
}

@formatted
identifier_cannot_start_with_underscore {
args: (),
msg: "Identifiers cannot start with an underscore.",
help: Some("Identifiers must start with a letter.".to_string()),
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Error [EPAR0370053]: Identifiers cannot start with an underscore.
--> test:5:16
|
5 | return _value;
| ^^^^^^
|
= Identifiers must start with a letter.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Error [EPAR0370053]: Identifiers cannot start with an underscore.
--> test:4:13
|
4 | let _c: u32 = a + b;
| ^^
|
= Identifiers must start with a letter.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
program test.aleo {
// Tests underscore in expression context
transition main() -> u32 {
// this should error when lexer sees _value
return _value;
}

function foo(_param: u32) -> u32 {
return _param;
}
}

13 changes: 13 additions & 0 deletions tests/tests/parser/identifiers/leading_underscore_fail.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
program test.aleo {
transition main(a: u32, b: u32) -> u32 {
// single leading underscore, typed
let _c: u32 = a + b;

// single leading underscore, untyped
let _temp = 10u32;

// using underscore-prefixed variable in expression
return _c + _temp;
}
}