Emit parse error when finding a ByteArray literal instead of String literal.
This commit is contained in:
		
							parent
							
								
									5132110d4b
								
							
						
					
					
						commit
						d72e13c7c8
					
				| 
						 | 
					@ -533,12 +533,70 @@ pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = Par
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn unexpected_bytearray_literal(
 | 
				
			||||||
 | 
					    token: Token,
 | 
				
			||||||
 | 
					    expr: &expr::UntypedExpr,
 | 
				
			||||||
 | 
					) -> 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<expr::UntypedExpr>,
 | 
				
			||||||
 | 
					    emit: &mut dyn FnMut(ParseError),
 | 
				
			||||||
 | 
					) -> Option<expr::UntypedExpr> {
 | 
				
			||||||
 | 
					    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<Token, expr::UntypedExpr, Error = ParseError> {
 | 
					pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> {
 | 
				
			||||||
    recursive(|r| {
 | 
					    recursive(|r| {
 | 
				
			||||||
        choice((
 | 
					        choice((
 | 
				
			||||||
            just(Token::Trace)
 | 
					            just(Token::Trace)
 | 
				
			||||||
                .ignore_then(expr_parser(r.clone()))
 | 
					                .ignore_then(expr_parser(r.clone()))
 | 
				
			||||||
                .then(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 {
 | 
					                .map_with_span(|(text, then_), span| expr::UntypedExpr::Trace {
 | 
				
			||||||
                    kind: TraceKind::Trace,
 | 
					                    kind: TraceKind::Trace,
 | 
				
			||||||
                    location: span,
 | 
					                    location: span,
 | 
				
			||||||
| 
						 | 
					@ -547,9 +605,11 @@ pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseE
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
            just(Token::ErrorTerm)
 | 
					            just(Token::ErrorTerm)
 | 
				
			||||||
                .ignore_then(expr_parser(r.clone()).or_not())
 | 
					                .ignore_then(expr_parser(r.clone()).or_not())
 | 
				
			||||||
 | 
					                .validate(|reason, _span, emit| validate_error_todo(Token::ErrorTerm, reason, emit))
 | 
				
			||||||
                .map_with_span(|reason, span| expr::UntypedExpr::error(span, reason)),
 | 
					                .map_with_span(|reason, span| expr::UntypedExpr::error(span, reason)),
 | 
				
			||||||
            just(Token::Todo)
 | 
					            just(Token::Todo)
 | 
				
			||||||
                .ignore_then(expr_parser(r.clone()).or_not())
 | 
					                .ignore_then(expr_parser(r.clone()).or_not())
 | 
				
			||||||
 | 
					                .validate(|reason, _span, emit| validate_error_todo(Token::Todo, reason, emit))
 | 
				
			||||||
                .map_with_span(|reason, span| expr::UntypedExpr::todo(span, reason)),
 | 
					                .map_with_span(|reason, span| expr::UntypedExpr::todo(span, reason)),
 | 
				
			||||||
            expr_parser(r.clone())
 | 
					            expr_parser(r.clone())
 | 
				
			||||||
                .then(r.repeated())
 | 
					                .then(r.repeated())
 | 
				
			||||||
| 
						 | 
					@ -924,6 +984,7 @@ pub fn expr_parser(
 | 
				
			||||||
                            .then_ignore(one_of(Token::RArrow).not().rewind())
 | 
					                            .then_ignore(one_of(Token::RArrow).not().rewind())
 | 
				
			||||||
                            .or_not(),
 | 
					                            .or_not(),
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					                    .validate(|reason, _span, emit| validate_error_todo(Token::Todo, reason, emit))
 | 
				
			||||||
                    .map_with_span(|reason, span| expr::UntypedExpr::todo(span, reason)),
 | 
					                    .map_with_span(|reason, span| expr::UntypedExpr::todo(span, reason)),
 | 
				
			||||||
                just(Token::ErrorTerm)
 | 
					                just(Token::ErrorTerm)
 | 
				
			||||||
                    .ignore_then(
 | 
					                    .ignore_then(
 | 
				
			||||||
| 
						 | 
					@ -931,6 +992,9 @@ pub fn expr_parser(
 | 
				
			||||||
                            .then_ignore(just(Token::RArrow).not().rewind())
 | 
					                            .then_ignore(just(Token::RArrow).not().rewind())
 | 
				
			||||||
                            .or_not(),
 | 
					                            .or_not(),
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					                    .validate(|reason, _span, emit| {
 | 
				
			||||||
 | 
					                        validate_error_todo(Token::ErrorTerm, reason, emit)
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
                    .map_with_span(|reason, span| expr::UntypedExpr::error(span, reason)),
 | 
					                    .map_with_span(|reason, span| expr::UntypedExpr::error(span, reason)),
 | 
				
			||||||
            )))
 | 
					            )))
 | 
				
			||||||
            .map_with_span(
 | 
					            .map_with_span(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,16 @@ impl ParseError {
 | 
				
			||||||
            label: None,
 | 
					            label: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn unexpected_bytearray_literal(span: Span, keyword: Token, literal: String) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            kind: ErrorKind::UnexpectedByteArrayLiteral(keyword, literal),
 | 
				
			||||||
 | 
					            span,
 | 
				
			||||||
 | 
					            while_parsing: None,
 | 
				
			||||||
 | 
					            expected: HashSet::new(),
 | 
				
			||||||
 | 
					            label: Some("use @"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PartialEq for ParseError {
 | 
					impl PartialEq for ParseError {
 | 
				
			||||||
| 
						 | 
					@ -102,15 +112,18 @@ impl<T: Into<Pattern>> chumsky::Error<T> for ParseError {
 | 
				
			||||||
pub enum ErrorKind {
 | 
					pub enum ErrorKind {
 | 
				
			||||||
    #[error("I arrived at the end of the file unexpectedly.")]
 | 
					    #[error("I arrived at the end of the file unexpectedly.")]
 | 
				
			||||||
    UnexpectedEnd,
 | 
					    UnexpectedEnd,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[error("{0}")]
 | 
					    #[error("{0}")]
 | 
				
			||||||
    #[diagnostic(help("{}", .0.help().unwrap_or_else(|| Box::new(""))))]
 | 
					    #[diagnostic(help("{}", .0.help().unwrap_or_else(|| Box::new(""))))]
 | 
				
			||||||
    Unexpected(Pattern),
 | 
					    Unexpected(Pattern),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[error("I discovered an invalid tuple index.")]
 | 
					    #[error("I discovered an invalid tuple index.")]
 | 
				
			||||||
    #[diagnostic()]
 | 
					    #[diagnostic()]
 | 
				
			||||||
    InvalidTupleIndex {
 | 
					    InvalidTupleIndex {
 | 
				
			||||||
        #[help]
 | 
					        #[help]
 | 
				
			||||||
        hint: Option<String>,
 | 
					        hint: Option<String>,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[error("I tripped over a malformed base16-encoded string literal.")]
 | 
					    #[error("I tripped over a malformed base16-encoded string literal.")]
 | 
				
			||||||
    #[diagnostic(help("{}", formatdoc! {
 | 
					    #[diagnostic(help("{}", formatdoc! {
 | 
				
			||||||
        r#"You can declare literal bytearrays from base16-encoded (a.k.a. hexadecimal) string literals.
 | 
					        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()}))]
 | 
					    , "pub const".bright_blue(), "=".yellow(), "\"f4c9f9c4252d86702c2f4c2e49e6648c7cffe3c8f2b6b7d779788f50\"".bright_purple()}))]
 | 
				
			||||||
    MalformedBase16StringLiteral,
 | 
					    MalformedBase16StringLiteral,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[error("I failed to understand a when clause guard.")]
 | 
					    #[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(url("https://aiken-lang.org/language-tour/control-flow#checking-equality-and-ordering-in-patterns"))]
 | 
				
			||||||
    #[diagnostic(help("{}", formatdoc! {
 | 
					    #[diagnostic(help("{}", formatdoc! {
 | 
				
			||||||
| 
						 | 
					@ -145,6 +159,29 @@ pub enum ErrorKind {
 | 
				
			||||||
        , bad = "✖️".red()
 | 
					        , bad = "✖️".red()
 | 
				
			||||||
    }))]
 | 
					    }))]
 | 
				
			||||||
    InvalidWhenClause,
 | 
					    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)]
 | 
					#[derive(Debug, PartialEq, Eq, Hash, Diagnostic, thiserror::Error)]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue