Support declaring bytearray literals as base16 strings.
This commit is contained in:
		
							parent
							
								
									6f8d1698fe
								
							
						
					
					
						commit
						3139c85fe8
					
				| 
						 | 
					@ -75,6 +75,7 @@ name = "aiken-lang"
 | 
				
			||||||
version = "0.0.26"
 | 
					version = "0.0.26"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "chumsky",
 | 
					 "chumsky",
 | 
				
			||||||
 | 
					 "hex",
 | 
				
			||||||
 "indexmap",
 | 
					 "indexmap",
 | 
				
			||||||
 "indoc",
 | 
					 "indoc",
 | 
				
			||||||
 "itertools",
 | 
					 "itertools",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@ authors = ["Lucas Rosa <x@rvcas.dev>", "Kasey White <kwhitemsg@gmail.com>"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
chumsky = "0.8.0"
 | 
					chumsky = "0.8.0"
 | 
				
			||||||
 | 
					hex = "0.4.3"
 | 
				
			||||||
indexmap = "1.9.1"
 | 
					indexmap = "1.9.1"
 | 
				
			||||||
indoc = "1.0.7"
 | 
					indoc = "1.0.7"
 | 
				
			||||||
itertools = "0.10.5"
 | 
					itertools = "0.10.5"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -344,7 +344,7 @@ fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = P
 | 
				
			||||||
                elements,
 | 
					                elements,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let constant_bytearray_parser = just(Token::Hash)
 | 
					        let constant_bytearray_list_parser = just(Token::Hash)
 | 
				
			||||||
            .ignore_then(
 | 
					            .ignore_then(
 | 
				
			||||||
                select! {Token::Int {value} => value}
 | 
					                select! {Token::Int {value} => value}
 | 
				
			||||||
                    .validate(|value, span, emit| {
 | 
					                    .validate(|value, span, emit| {
 | 
				
			||||||
| 
						 | 
					@ -372,6 +372,27 @@ fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = P
 | 
				
			||||||
                bytes,
 | 
					                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
 | 
					        let constant_list_parser = r
 | 
				
			||||||
            .clone()
 | 
					            .clone()
 | 
				
			||||||
            .separated_by(just(Token::Comma))
 | 
					            .separated_by(just(Token::Comma))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ use std::collections::HashSet;
 | 
				
			||||||
use miette::Diagnostic;
 | 
					use miette::Diagnostic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{ast::Span, parser::token::Token};
 | 
					use crate::{ast::Span, parser::token::Token};
 | 
				
			||||||
 | 
					use indoc::formatdoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Diagnostic, thiserror::Error)]
 | 
					#[derive(Debug, Diagnostic, thiserror::Error)]
 | 
				
			||||||
#[error("{kind}\n")]
 | 
					#[error("{kind}\n")]
 | 
				
			||||||
| 
						 | 
					@ -35,6 +36,16 @@ impl ParseError {
 | 
				
			||||||
            label: None,
 | 
					            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 {
 | 
					impl PartialEq for ParseError {
 | 
				
			||||||
| 
						 | 
					@ -91,6 +102,18 @@ pub enum ErrorKind {
 | 
				
			||||||
        #[help]
 | 
					        #[help]
 | 
				
			||||||
        hint: Option<String>,
 | 
					        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)]
 | 
					#[derive(Debug, PartialEq, Eq, Hash, Diagnostic, thiserror::Error)]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ use indoc::indoc;
 | 
				
			||||||
use pretty_assertions::assert_eq;
 | 
					use pretty_assertions::assert_eq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    ast::{self, DataType, Function, Span, TypeAlias, Use},
 | 
					    ast::{self, Constant, DataType, Function, ModuleConstant, Span, TypeAlias, Use},
 | 
				
			||||||
    expr, parser,
 | 
					    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: (),
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue