From d72e13c7c8535ddd9406af70f189bb62313deeff Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 18 Feb 2023 10:55:39 +0100 Subject: [PATCH] Emit parse error when finding a ByteArray literal instead of String literal. --- crates/aiken-lang/src/parser.rs | 64 +++++++++++++++++++++++++++ crates/aiken-lang/src/parser/error.rs | 37 ++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/crates/aiken-lang/src/parser.rs b/crates/aiken-lang/src/parser.rs index df6a143c..1e14b1e0 100644 --- a/crates/aiken-lang/src/parser.rs +++ b/crates/aiken-lang/src/parser.rs @@ -533,12 +533,70 @@ pub fn anon_fn_param_parser() -> impl Parser Option<(ParseError, String)> { + match expr { + expr::UntypedExpr::ByteArray { + bytes, + preferred_format: ByteArrayFormatPreference::Utf8String, + location, + .. + } => { + let literal = String::from_utf8(bytes.clone()).unwrap(); + + Some(( + ParseError::unexpected_bytearray_literal(*location, token, literal.clone()), + literal, + )) + } + _ => None, + } +} + +fn validate_error_todo( + token: Token, + reason: Option, + emit: &mut dyn FnMut(ParseError), +) -> Option { + if let Some(reason) = reason { + match unexpected_bytearray_literal(token, &reason) { + None => Some(reason), + Some((err, value)) => { + emit(err); + Some(expr::UntypedExpr::String { + location: reason.location(), + value, + }) + } + } + } else { + reason + } +} + pub fn expr_seq_parser() -> impl Parser { recursive(|r| { choice(( just(Token::Trace) .ignore_then(expr_parser(r.clone())) .then(r.clone()) + .validate(|(text, then), _span, emit| { + match unexpected_bytearray_literal(Token::Trace, &text) { + None => (text, then), + Some((err, value)) => { + emit(err); + ( + expr::UntypedExpr::String { + location: text.location(), + value, + }, + then, + ) + } + } + }) .map_with_span(|(text, then_), span| expr::UntypedExpr::Trace { kind: TraceKind::Trace, location: span, @@ -547,9 +605,11 @@ pub fn expr_seq_parser() -> impl Parser Self { + Self { + kind: ErrorKind::UnexpectedByteArrayLiteral(keyword, literal), + span, + while_parsing: None, + expected: HashSet::new(), + label: Some("use @"), + } + } } impl PartialEq for ParseError { @@ -102,15 +112,18 @@ impl> chumsky::Error for ParseError { pub enum ErrorKind { #[error("I arrived at the end of the file unexpectedly.")] UnexpectedEnd, + #[error("{0}")] #[diagnostic(help("{}", .0.help().unwrap_or_else(|| Box::new(""))))] Unexpected(Pattern), + #[error("I discovered an invalid tuple index.")] #[diagnostic()] InvalidTupleIndex { #[help] hint: Option, }, + #[error("I tripped over a malformed base16-encoded string literal.")] #[diagnostic(help("{}", formatdoc! { r#"You can declare literal bytearrays from base16-encoded (a.k.a. hexadecimal) string literals. @@ -123,6 +136,7 @@ pub enum ErrorKind { "# , "pub const".bright_blue(), "=".yellow(), "\"f4c9f9c4252d86702c2f4c2e49e6648c7cffe3c8f2b6b7d779788f50\"".bright_purple()}))] MalformedBase16StringLiteral, + #[error("I failed to understand a when clause guard.")] #[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#checking-equality-and-ordering-in-patterns"))] #[diagnostic(help("{}", formatdoc! { @@ -145,6 +159,29 @@ pub enum ErrorKind { , bad = "✖️".red() }))] InvalidWhenClause, + + #[error( + "I noticed a {} literal where I would expect a {}.", + "ByteArray".bold().bright_blue(), + "String".bold().bright_blue(), + )] + #[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#string"))] + #[diagnostic(help("{}", formatdoc! { + r#"The keyword {keyword} accepts a {type_String} as argument. A {type_String} literal is denoted by {syntax}. Simple double-quotes are interpreted as {type_ByteArray} of UTF-8 encoded bytes. Juggling between {type_ByteArray} and {type_String} can be a little confusing. + + In this instance, you probably meant to write the following: + + ╰─▶ {keyword} {symbol_at}{symbol_doublequotes}{literal}{symbol_doublequotes} + "#, + type_String = "String".bold().bright_blue(), + type_ByteArray = "ByteArray".bold().bright_blue(), + symbol_at = "@".purple(), + symbol_doublequotes = "\"".purple(), + syntax = format!("{}{}", "@".purple(), "\"...\"".purple()), + keyword = format!("{}", .0).replace('"', "").bold(), + literal = .1.purple(), + }))] + UnexpectedByteArrayLiteral(Token, String), } #[derive(Debug, PartialEq, Eq, Hash, Diagnostic, thiserror::Error)]