diff --git a/compiler/parser/src/parser/context.rs b/compiler/parser/src/parser/context.rs index 8656aa17ee..b5f37deb16 100644 --- a/compiler/parser/src/parser/context.rs +++ b/compiler/parser/src/parser/context.rs @@ -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; @@ -155,6 +155,7 @@ impl<'a, N: Network> ParserContext<'a, N> { pub(super) fn expect_identifier(&mut self) -> Result { self.eat_identifier() .ok_or_else(|| ParserError::unexpected_str(&self.token.token, "identifier", self.token.span).into()) + .inspect(|id| self.check_identifier(id)) } /// @@ -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, + )); + } + } } diff --git a/compiler/parser/src/parser/type_.rs b/compiler/parser/src/parser/type_.rs index d090a3082b..07b6b79924 100644 --- a/compiler/parser/src/parser/type_.rs +++ b/compiler/parser/src/parser/type_.rs @@ -83,6 +83,8 @@ impl 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) { @@ -98,6 +100,7 @@ impl 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) }), diff --git a/errors/src/errors/parser/parser_errors.rs b/errors/src/errors/parser/parser_errors.rs index bd8be8cd80..675788342e 100644 --- a/errors/src/errors/parser/parser_errors.rs +++ b/errors/src/errors/parser/parser_errors.rs @@ -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, + } ); diff --git a/tests/expectations/parser/identifiers/long_identifier_fail.out b/tests/expectations/parser/identifiers/long_identifier_fail.out new file mode 100644 index 0000000000..a9dec531a2 --- /dev/null +++ b/tests/expectations/parser/identifiers/long_identifier_fail.out @@ -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 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"""] diff --git a/tests/tests/parser/identifiers/long_identifier_fail.leo b/tests/tests/parser/identifiers/long_identifier_fail.leo new file mode 100644 index 0000000000..526c789180 --- /dev/null +++ b/tests/tests/parser/identifiers/long_identifier_fail.leo @@ -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; + } +}