Skip to content

Commit

Permalink
Parse error on identifiers that are too long.
Browse files Browse the repository at this point in the history
SnarkVM requires that identifiers fit in a field
element.
  • Loading branch information
mikebenfield committed Nov 4, 2024
1 parent 4afc757 commit 07d932a
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 1 deletion.
17 changes: 16 additions & 1 deletion compiler/parser/src/parser/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{Token, tokenizer::*};

use leo_ast::*;
use leo_errors::{ParserError, ParserWarning, Result, emitter::Handler};
use leo_span::{Span, Symbol};
use leo_span::{Span, Symbol, symbol::with_session_globals};

use snarkvm::prelude::Network;

Expand Down Expand Up @@ -155,6 +155,7 @@ impl<'a, N: Network> ParserContext<'a, N> {
pub(super) fn expect_identifier(&mut self) -> Result<Identifier> {
self.eat_identifier()
.ok_or_else(|| ParserError::unexpected_str(&self.token.token, "identifier", self.token.span).into())
.inspect(|id| self.check_identifier(id))
}

///
Expand Down Expand Up @@ -257,4 +258,18 @@ impl<'a, N: Network> ParserContext<'a, N> {
pub(super) fn peek_is_left_par(&self) -> bool {
matches!(self.token.token, Token::LeftParen)
}

pub(crate) fn check_identifier(&self, identifier: &Identifier) {
const FIELD_CAPACITY_BITS: usize = 250usize;
const FIELD_CAPACITY_BYTES: usize = FIELD_CAPACITY_BITS / 8;
let len = with_session_globals(|sg| identifier.name.as_str(sg, |s| s.len()));
if len > FIELD_CAPACITY_BYTES {
self.emit_err(ParserError::identifier_too_long(
identifier.name,
len,
FIELD_CAPACITY_BYTES,
identifier.span,
));
}
}
}
3 changes: 3 additions & 0 deletions compiler/parser/src/parser/type_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ impl<N: Network> ParserContext<'_, N> {
/// Also returns the span of the parsed token.
pub fn parse_type(&mut self) -> Result<(Type, Span)> {
if let Some(ident) = self.eat_identifier() {
self.check_identifier(&ident);

// Check if using external type
let file_type = self.look_ahead(1, |t| &t.token);
if self.token.token == Token::Dot && (file_type == &Token::Aleo) {
Expand All @@ -98,6 +100,7 @@ impl<N: Network> ParserContext<'_, N> {

// Parse the record name
if let Some(record_name) = self.eat_identifier() {
self.check_identifier(&record_name);
// Return the external type
return Ok((
Type::Composite(CompositeType { id: record_name, program: Some(ident.name) }),
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 @@ -365,4 +365,11 @@ create_messages!(
msg: format!("Digit {digit} invalid in radix {radix} (token {token})."),
help: None,
}

@formatted
identifier_too_long {
args: (ident: impl Display, length: usize, max_length: usize),
msg: format!("Identifier {ident} too long ({length} bytes; maximum is {max_length})"),
help: None,
}
);
23 changes: 23 additions & 0 deletions tests/expectations/parser/identifiers/long_identifier_fail.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace = "Parse"
expectation = "Fail"
outputs = ["""
Error [EPAR0370044]: Identifier S012345678901234567890123456789q too long (32 bytes; maximum is 31)
--> test:19:12
|
19 | struct S012345678901234567890123456789q {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error [EPAR0370044]: Identifier m012345678901234567890123456789q too long (32 bytes; maximum is 31)
--> test:20:9
|
20 | m012345678901234567890123456789q: u8,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error [EPAR0370044]: Identifier x012345678901234567890123456789q too long (32 bytes; maximum is 31)
--> test:23:14
|
23 | function x012345678901234567890123456789q(y012345678901234567890123456789q: u8) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error [EPAR0370044]: Identifier y012345678901234567890123456789q too long (32 bytes; maximum is 31)
--> test:23:47
|
23 | function x012345678901234567890123456789q(y012345678901234567890123456789q: u8) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"""]
30 changes: 30 additions & 0 deletions tests/tests/parser/identifiers/long_identifier_fail.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
namespace = "Parse"
expectation = "Fail"
*/

program test.aleo {
transition main() -> bool {
return true;
}

// These identifiers are 31 characters long and should be fine.
struct S012345678901234567890123456789 {
m012345678901234567890123456789: u8,
}

function x012345678901234567890123456789(y012345678901234567890123456789: u8) -> u8 {
let z012345678901234567890123456789: u8 = 1u8;
return z012345678901234567890123456789 + y012345678901234567890123456789;
}

// These identifiers are 32 characters long and should fail.
struct S012345678901234567890123456789q {
m012345678901234567890123456789q: u8,
}

function x012345678901234567890123456789q(y012345678901234567890123456789q: u8) -> u8 {
let z012345678901234567890123456789q: u8 = 1u8;
return z012345678901234567890123456789q + y012345678901234567890123456789q;
}
}

0 comments on commit 07d932a

Please sign in to comment.