Support declaring bytearray literals as base16 strings.

This commit is contained in:
KtorZ 2022-12-29 13:08:58 +01:00
parent 6f8d1698fe
commit 3139c85fe8
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
5 changed files with 94 additions and 2 deletions

1
Cargo.lock generated
View File

@ -75,6 +75,7 @@ name = "aiken-lang"
version = "0.0.26"
dependencies = [
"chumsky",
"hex",
"indexmap",
"indoc",
"itertools",

View File

@ -12,6 +12,7 @@ authors = ["Lucas Rosa <x@rvcas.dev>", "Kasey White <kwhitemsg@gmail.com>"]
[dependencies]
chumsky = "0.8.0"
hex = "0.4.3"
indexmap = "1.9.1"
indoc = "1.0.7"
itertools = "0.10.5"

View File

@ -344,7 +344,7 @@ fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = P
elements,
});
let constant_bytearray_parser = just(Token::Hash)
let constant_bytearray_list_parser = just(Token::Hash)
.ignore_then(
select! {Token::Int {value} => value}
.validate(|value, span, emit| {
@ -372,6 +372,27 @@ fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = P
bytes,
});
let constant_bytearray_hexstring_parser =
just(Token::Hash)
.ignore_then(select! {Token::String {value} => value}.validate(
|value, span, emit| match hex::decode(&value) {
Ok(bytes) => bytes,
Err(_) => {
emit(ParseError::malformed_base16_string_literal(span));
vec![]
}
},
))
.map_with_span(|bytes, span| ast::UntypedConstant::ByteArray {
location: span,
bytes,
});
let constant_bytearray_parser = choice((
constant_bytearray_list_parser,
constant_bytearray_hexstring_parser,
));
let constant_list_parser = r
.clone()
.separated_by(just(Token::Comma))

View File

@ -3,6 +3,7 @@ use std::collections::HashSet;
use miette::Diagnostic;
use crate::{ast::Span, parser::token::Token};
use indoc::formatdoc;
#[derive(Debug, Diagnostic, thiserror::Error)]
#[error("{kind}\n")]
@ -35,6 +36,16 @@ impl ParseError {
label: None,
}
}
pub fn malformed_base16_string_literal(span: Span) -> Self {
Self {
kind: ErrorKind::MalformedBase16StringLiteral,
span,
while_parsing: None,
expected: HashSet::new(),
label: None,
}
}
}
impl PartialEq for ParseError {
@ -91,6 +102,18 @@ pub enum ErrorKind {
#[help]
hint: Option<String>,
},
#[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.
For example:
pub const my_policy_id =
#"f4c9f9c4252d86702c2f4c2e49e6648c7cffe3c8f2b6b7d779788f50"
"#
}))]
MalformedBase16StringLiteral,
}
#[derive(Debug, PartialEq, Eq, Hash, Diagnostic, thiserror::Error)]

View File

@ -3,7 +3,7 @@ use indoc::indoc;
use pretty_assertions::assert_eq;
use crate::{
ast::{self, DataType, Function, Span, TypeAlias, Use},
ast::{self, Constant, DataType, Function, ModuleConstant, Span, TypeAlias, Use},
expr, parser,
};
@ -1542,3 +1542,49 @@ fn parse_tuple() {
}),
)
}
#[test]
fn plain_bytearray_literals() {
let code = indoc! {r#"
pub const my_policy_id = #[0, 170, 255]
"#};
assert_definition(
code,
ast::UntypedDefinition::ModuleConstant(ModuleConstant {
doc: None,
location: Span::new((), 0..39),
public: true,
name: "my_policy_id".to_string(),
annotation: None,
value: Box::new(Constant::ByteArray {
location: Span::new((), 25..39),
bytes: vec![0, 170, 255],
}),
tipo: (),
}),
)
}
#[test]
fn base16_bytearray_literals() {
let code = indoc! {r#"
pub const my_policy_id = #"00aaff"
"#};
assert_definition(
code,
ast::UntypedDefinition::ModuleConstant(ModuleConstant {
doc: None,
location: Span::new((), 0..34),
public: true,
name: "my_policy_id".to_string(),
annotation: None,
value: Box::new(Constant::ByteArray {
location: Span::new((), 25..34),
bytes: vec![0, 170, 255],
}),
tipo: (),
}),
)
}