diff --git a/Cargo.toml b/Cargo.toml index 3836644..0ebe9e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ copy_iterator = "warn" default_trait_access = "warn" doc_link_with_quotes = "warn" doc_markdown = "warn" -empty_enum = "warn" +empty_enums = "warn" enum_glob_use = "allow" expl_impl_clone_on_copy = "warn" explicit_deref_methods = "warn" @@ -152,7 +152,7 @@ struct_field_names = "warn" too_many_lines = "allow" transmute_ptr_to_ptr = "warn" trivially_copy_pass_by_ref = "warn" -unchecked_duration_subtraction = "warn" +unchecked_time_subtraction = "warn" unicode_not_nfc = "warn" unnecessary_box_returns = "warn" unnecessary_join = "warn" diff --git a/src/lexer.rs b/src/lexer.rs index fef1892..9fe6560 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -20,6 +20,9 @@ pub enum Token<'src> { // Control symbols Arrow, + /// Represents a contiguous `::` token. + /// This prevents the lexer from allowing spaces between colons (e.g., `use a: :b`), + DoubleColon, Colon, Semi, Comma, @@ -71,6 +74,7 @@ impl<'src> fmt::Display for Token<'src> { Token::Match => write!(f, "match"), Token::Arrow => write!(f, "->"), + Token::DoubleColon => write!(f, "::"), Token::Colon => write!(f, ":"), Token::Semi => write!(f, ";"), Token::Comma => write!(f, ","), @@ -145,16 +149,22 @@ pub fn lexer<'src>( _ => Token::Ident(s), }); - let jet = just("jet::") - .labelled("jet") + let jet = just("jet") + .padded() + .ignore_then(just("::")) + .padded() .ignore_then(text::ident()) .map(Token::Jet); - let witness = just("witness::") - .labelled("witness") + let witness = just("witness") + .padded() + .ignore_then(just("::")) + .padded() .ignore_then(text::ident()) .map(Token::Witness); - let param = just("param::") - .labelled("param") + let param = just("param") + .padded() + .ignore_then(just("::")) + .padded() .ignore_then(text::ident()) .map(Token::Param); @@ -162,6 +172,7 @@ pub fn lexer<'src>( just("->").to(Token::Arrow), just("=>").to(Token::FatArrow), just("=").to(Token::Eq), + just("::").to(Token::DoubleColon), just(":").to(Token::Colon), just(";").to(Token::Semi), just(",").to(Token::Comma), diff --git a/src/parse.rs b/src/parse.rs index c42c6f3..909de38 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1347,16 +1347,14 @@ impl ChumskyParse for CallName { where I: ValueInput<'tokens, Token = Token<'src>, Span = Span>, { - let double_colon = just(Token::Colon).then(just(Token::Colon)).labelled("::"); - - let turbofish_start = double_colon.clone().then(just(Token::LAngle)).ignored(); + let turbofish_start = just(Token::DoubleColon).then(just(Token::LAngle)).ignored(); let generics_close = just(Token::RAngle); let type_cast = just(Token::LAngle) .ignore_then(AliasedType::parser()) .then_ignore(generics_close.clone()) - .then_ignore(just(Token::Colon).then(just(Token::Colon))) + .then_ignore(just(Token::DoubleColon)) .then_ignore(just(Token::Ident("into"))) .map(CallName::TypeCast); @@ -2163,3 +2161,28 @@ impl crate::ArbitraryRec for Match { }) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_double_colon() { + let input = "fn main() { let ab: u8 = <(u4, u4)> : :into((0b1011, 0b1101)); }"; + let mut error_handler = ErrorCollector::new(Arc::from(input)); + let parse_program = Program::parse_from_str_with_errors(input, &mut error_handler); + + assert!(parse_program.is_none()); + assert!(ErrorCollector::to_string(&error_handler).contains("Expected '::', found ':'")); + } + + #[test] + fn test_double_double_colon() { + let input = "fn main() { let pk: Pubkey = witnes::::PK; }"; + let mut error_handler = ErrorCollector::new(Arc::from(input)); + let parse_program = Program::parse_from_str_with_errors(input, &mut error_handler); + + assert!(parse_program.is_none()); + assert!(ErrorCollector::to_string(&error_handler).contains("Expected ';', found '::'")); + } +}