Merge pull request #391 from aiken-lang/string-and-bytearray-literals-iteration
String and bytearray literals iteration
This commit is contained in:
commit
95fce14b75
|
@ -326,11 +326,21 @@ pub struct DefinitionLocation<'module> {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Constant {
|
pub enum Constant {
|
||||||
Int { location: Span, value: String },
|
Int {
|
||||||
|
location: Span,
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
|
||||||
String { location: Span, value: String },
|
String {
|
||||||
|
location: Span,
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
|
||||||
ByteArray { location: Span, bytes: Vec<u8> },
|
ByteArray {
|
||||||
|
location: Span,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
preferred_format: ByteArrayFormatPreference,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Constant {
|
impl Constant {
|
||||||
|
@ -748,6 +758,13 @@ impl<A, B> Pattern<A, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||||
|
pub enum ByteArrayFormatPreference {
|
||||||
|
HexadecimalString,
|
||||||
|
ArrayOfBytes,
|
||||||
|
Utf8String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||||
pub enum AssignmentKind {
|
pub enum AssignmentKind {
|
||||||
Let,
|
Let,
|
||||||
|
|
|
@ -4,9 +4,9 @@ use vec1::Vec1;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, DefinitionLocation, IfBranch,
|
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, Clause,
|
||||||
Pattern, RecordUpdateSpread, Span, TraceKind, TypedRecordUpdateArg, UnOp,
|
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind,
|
||||||
UntypedRecordUpdateArg,
|
TypedRecordUpdateArg, UnOp, UntypedRecordUpdateArg,
|
||||||
},
|
},
|
||||||
builtins::void,
|
builtins::void,
|
||||||
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
|
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
|
||||||
|
@ -361,6 +361,7 @@ pub enum UntypedExpr {
|
||||||
ByteArray {
|
ByteArray {
|
||||||
location: Span,
|
location: Span,
|
||||||
bytes: Vec<u8>,
|
bytes: Vec<u8>,
|
||||||
|
preferred_format: ByteArrayFormatPreference,
|
||||||
},
|
},
|
||||||
|
|
||||||
PipeLine {
|
PipeLine {
|
||||||
|
|
|
@ -5,12 +5,12 @@ use vec1::Vec1;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, ClauseGuard, Constant, DataType,
|
Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
|
||||||
Definition, Function, IfBranch, ModuleConstant, Pattern, RecordConstructor,
|
ClauseGuard, Constant, DataType, Definition, Function, IfBranch, ModuleConstant, Pattern,
|
||||||
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp,
|
RecordConstructor, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias,
|
||||||
UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedDefinition,
|
TypedArg, UnOp, UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard,
|
||||||
UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, Use, Validator,
|
UntypedDefinition, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg,
|
||||||
CAPTURE_VARIABLE,
|
Use, Validator, CAPTURE_VARIABLE,
|
||||||
},
|
},
|
||||||
docvec,
|
docvec,
|
||||||
expr::{UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR},
|
expr::{UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR},
|
||||||
|
@ -326,7 +326,11 @@ impl<'comments> Formatter<'comments> {
|
||||||
|
|
||||||
fn const_expr<'a>(&mut self, value: &'a Constant) -> Document<'a> {
|
fn const_expr<'a>(&mut self, value: &'a Constant) -> Document<'a> {
|
||||||
match value {
|
match value {
|
||||||
Constant::ByteArray { bytes, .. } => self.bytearray(bytes),
|
Constant::ByteArray {
|
||||||
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
..
|
||||||
|
} => self.bytearray(bytes, preferred_format),
|
||||||
Constant::Int { value, .. } => value.to_doc(),
|
Constant::Int { value, .. } => value.to_doc(),
|
||||||
Constant::String { value, .. } => self.string(value),
|
Constant::String { value, .. } => self.string(value),
|
||||||
}
|
}
|
||||||
|
@ -635,18 +639,43 @@ impl<'comments> Formatter<'comments> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytearray<'a>(&mut self, bytes: &'a [u8]) -> Document<'a> {
|
pub fn bytearray<'a>(
|
||||||
"#".to_doc()
|
&mut self,
|
||||||
|
bytes: &'a [u8],
|
||||||
|
preferred_format: &ByteArrayFormatPreference,
|
||||||
|
) -> Document<'a> {
|
||||||
|
match preferred_format {
|
||||||
|
ByteArrayFormatPreference::HexadecimalString => "#"
|
||||||
|
.to_doc()
|
||||||
.append("\"")
|
.append("\"")
|
||||||
.append(Document::String(hex::encode(bytes)))
|
.append(Document::String(hex::encode(bytes)))
|
||||||
|
.append("\""),
|
||||||
|
ByteArrayFormatPreference::ArrayOfBytes => "#"
|
||||||
|
.to_doc()
|
||||||
|
.append(
|
||||||
|
flex_break("[", "[")
|
||||||
|
.append(join(bytes.iter().map(|b| b.to_doc()), break_(",", ", ")))
|
||||||
|
.nest(INDENT)
|
||||||
|
.append(break_(",", ""))
|
||||||
|
.append("]"),
|
||||||
|
)
|
||||||
|
.group(),
|
||||||
|
ByteArrayFormatPreference::Utf8String => nil()
|
||||||
.append("\"")
|
.append("\"")
|
||||||
|
.append(Document::String(String::from_utf8(bytes.to_vec()).unwrap()))
|
||||||
|
.append("\""),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
|
pub fn expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
|
||||||
let comments = self.pop_comments(expr.start_byte_index());
|
let comments = self.pop_comments(expr.start_byte_index());
|
||||||
|
|
||||||
let document = match expr {
|
let document = match expr {
|
||||||
UntypedExpr::ByteArray { bytes, .. } => self.bytearray(bytes),
|
UntypedExpr::ByteArray {
|
||||||
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
..
|
||||||
|
} => self.bytearray(bytes, preferred_format),
|
||||||
|
|
||||||
UntypedExpr::If {
|
UntypedExpr::If {
|
||||||
branches,
|
branches,
|
||||||
|
@ -741,7 +770,7 @@ impl<'comments> Formatter<'comments> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string<'a>(&self, string: &'a String) -> Document<'a> {
|
fn string<'a>(&self, string: &'a String) -> Document<'a> {
|
||||||
let doc = string.to_doc().surround("\"", "\"");
|
let doc = "@".to_doc().append(string.to_doc().surround("\"", "\""));
|
||||||
if string.contains('\n') {
|
if string.contains('\n') {
|
||||||
doc.force_break()
|
doc.force_break()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,7 +7,10 @@ pub mod lexer;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, BinOp, Span, TraceKind, UnOp, UntypedDefinition, CAPTURE_VARIABLE},
|
ast::{
|
||||||
|
self, BinOp, ByteArrayFormatPreference, Span, TraceKind, UnOp, UntypedDefinition,
|
||||||
|
CAPTURE_VARIABLE,
|
||||||
|
},
|
||||||
expr,
|
expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -402,9 +405,12 @@ fn constant_value_parser() -> impl Parser<Token, ast::Constant, Error = ParseErr
|
||||||
});
|
});
|
||||||
|
|
||||||
let constant_bytearray_parser =
|
let constant_bytearray_parser =
|
||||||
bytearray_parser().map_with_span(|bytes, span| ast::Constant::ByteArray {
|
bytearray_parser().map_with_span(|(preferred_format, bytes), span| {
|
||||||
|
ast::Constant::ByteArray {
|
||||||
location: span,
|
location: span,
|
||||||
bytes,
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
choice((
|
choice((
|
||||||
|
@ -414,8 +420,10 @@ fn constant_value_parser() -> impl Parser<Token, ast::Constant, Error = ParseErr
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytearray_parser() -> impl Parser<Token, Vec<u8>, Error = ParseError> {
|
pub fn bytearray_parser(
|
||||||
let bytearray_list_parser = just(Token::Hash).ignore_then(
|
) -> impl Parser<Token, (ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
|
||||||
|
let bytearray_list_parser = just(Token::Hash)
|
||||||
|
.ignore_then(
|
||||||
select! {Token::Int {value} => value}
|
select! {Token::Int {value} => value}
|
||||||
.validate(|value, span, emit| {
|
.validate(|value, span, emit| {
|
||||||
let byte: u8 = match value.parse() {
|
let byte: u8 = match value.parse() {
|
||||||
|
@ -436,10 +444,12 @@ pub fn bytearray_parser() -> impl Parser<Token, Vec<u8>, Error = ParseError> {
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
|
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
|
||||||
);
|
)
|
||||||
|
.map(|token| (ByteArrayFormatPreference::ArrayOfBytes, token));
|
||||||
|
|
||||||
let bytearray_hexstring_parser =
|
let bytearray_hexstring_parser =
|
||||||
just(Token::Hash).ignore_then(select! {Token::String {value} => value}.validate(
|
just(Token::Hash)
|
||||||
|
.ignore_then(select! {Token::ByteString {value} => value}.validate(
|
||||||
|value, span, emit| match hex::decode(value) {
|
|value, span, emit| match hex::decode(value) {
|
||||||
Ok(bytes) => bytes,
|
Ok(bytes) => bytes,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
@ -447,9 +457,17 @@ pub fn bytearray_parser() -> impl Parser<Token, Vec<u8>, Error = ParseError> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
));
|
))
|
||||||
|
.map(|token| (ByteArrayFormatPreference::HexadecimalString, token));
|
||||||
|
|
||||||
choice((bytearray_list_parser, bytearray_hexstring_parser))
|
let bytearray_utf8_parser = select! {Token::ByteString {value} => value.into_bytes() }
|
||||||
|
.map(|token| (ByteArrayFormatPreference::Utf8String, token));
|
||||||
|
|
||||||
|
choice((
|
||||||
|
bytearray_list_parser,
|
||||||
|
bytearray_hexstring_parser,
|
||||||
|
bytearray_utf8_parser,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
pub fn fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
||||||
|
@ -515,6 +533,25 @@ pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = Par
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interpret bytearray string literals written as utf-8 strings, as strings.
|
||||||
|
//
|
||||||
|
// This is mostly convenient so that todo & error works with either @"..." or plain "...".
|
||||||
|
// In this particular context, there's actually no ambiguity about the right-hand-side, so
|
||||||
|
// we can provide this syntactic sugar.
|
||||||
|
fn flexible_string_literal(expr: expr::UntypedExpr) -> expr::UntypedExpr {
|
||||||
|
match expr {
|
||||||
|
expr::UntypedExpr::ByteArray {
|
||||||
|
preferred_format: ByteArrayFormatPreference::Utf8String,
|
||||||
|
bytes,
|
||||||
|
location,
|
||||||
|
} => expr::UntypedExpr::String {
|
||||||
|
location,
|
||||||
|
value: String::from_utf8(bytes).unwrap(),
|
||||||
|
},
|
||||||
|
_ => expr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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((
|
||||||
|
@ -525,14 +562,18 @@ pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseE
|
||||||
kind: TraceKind::Trace,
|
kind: TraceKind::Trace,
|
||||||
location: span,
|
location: span,
|
||||||
then: Box::new(then_),
|
then: Box::new(then_),
|
||||||
text: Box::new(text),
|
text: Box::new(flexible_string_literal(text)),
|
||||||
}),
|
}),
|
||||||
just(Token::ErrorTerm)
|
just(Token::ErrorTerm)
|
||||||
.ignore_then(expr_parser(r.clone()).or_not())
|
.ignore_then(expr_parser(r.clone()).or_not())
|
||||||
.map_with_span(|reason, span| expr::UntypedExpr::error(span, reason)),
|
.map_with_span(|reason, span| {
|
||||||
|
expr::UntypedExpr::error(span, reason.map(flexible_string_literal))
|
||||||
|
}),
|
||||||
just(Token::Todo)
|
just(Token::Todo)
|
||||||
.ignore_then(expr_parser(r.clone()).or_not())
|
.ignore_then(expr_parser(r.clone()).or_not())
|
||||||
.map_with_span(|reason, span| expr::UntypedExpr::todo(span, reason)),
|
.map_with_span(|reason, span| {
|
||||||
|
expr::UntypedExpr::todo(span, reason.map(flexible_string_literal))
|
||||||
|
}),
|
||||||
expr_parser(r.clone())
|
expr_parser(r.clone())
|
||||||
.then(r.repeated())
|
.then(r.repeated())
|
||||||
.foldl(|current, next| current.append_in_sequence(next)),
|
.foldl(|current, next| current.append_in_sequence(next)),
|
||||||
|
@ -816,10 +857,12 @@ pub fn expr_parser(
|
||||||
elems,
|
elems,
|
||||||
});
|
});
|
||||||
|
|
||||||
let bytearray =
|
let bytearray = bytearray_parser().map_with_span(|(preferred_format, bytes), span| {
|
||||||
bytearray_parser().map_with_span(|bytes, span| expr::UntypedExpr::ByteArray {
|
expr::UntypedExpr::ByteArray {
|
||||||
location: span,
|
location: span,
|
||||||
bytes,
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let list_parser = just(Token::LeftSquare)
|
let list_parser = just(Token::LeftSquare)
|
||||||
|
@ -904,14 +947,18 @@ pub fn expr_parser(
|
||||||
.then_ignore(one_of(Token::RArrow).not().rewind())
|
.then_ignore(one_of(Token::RArrow).not().rewind())
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.map_with_span(|reason, span| expr::UntypedExpr::todo(span, reason)),
|
.map_with_span(|reason, span| {
|
||||||
|
expr::UntypedExpr::todo(span, reason.map(flexible_string_literal))
|
||||||
|
}),
|
||||||
just(Token::ErrorTerm)
|
just(Token::ErrorTerm)
|
||||||
.ignore_then(
|
.ignore_then(
|
||||||
r.clone()
|
r.clone()
|
||||||
.then_ignore(just(Token::RArrow).not().rewind())
|
.then_ignore(just(Token::RArrow).not().rewind())
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
.map_with_span(|reason, span| expr::UntypedExpr::error(span, reason)),
|
.map_with_span(|reason, span| {
|
||||||
|
expr::UntypedExpr::error(span, reason.map(flexible_string_literal))
|
||||||
|
}),
|
||||||
)))
|
)))
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|(((patterns, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
|(((patterns, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
||||||
|
|
|
@ -102,15 +102,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 +126,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! {
|
||||||
|
|
|
@ -77,13 +77,21 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
||||||
.or(just('t').to('\t')),
|
.or(just('t').to('\t')),
|
||||||
);
|
);
|
||||||
|
|
||||||
let string = just('"')
|
let string = just('@')
|
||||||
|
.ignore_then(just('"'))
|
||||||
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
|
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
|
||||||
.then_ignore(just('"'))
|
.then_ignore(just('"'))
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
.map(|value| Token::String { value })
|
.map(|value| Token::String { value })
|
||||||
.labelled("string");
|
.labelled("string");
|
||||||
|
|
||||||
|
let bytestring = just('"')
|
||||||
|
.ignore_then(filter(|c| *c != '\\' && *c != '"').or(escape).repeated())
|
||||||
|
.then_ignore(just('"'))
|
||||||
|
.collect::<String>()
|
||||||
|
.map(|value| Token::ByteString { value })
|
||||||
|
.labelled("bytestring");
|
||||||
|
|
||||||
let keyword = text::ident().map(|s: String| match s.as_str() {
|
let keyword = text::ident().map(|s: String| match s.as_str() {
|
||||||
"trace" => Token::Trace,
|
"trace" => Token::Trace,
|
||||||
"error" => Token::ErrorTerm,
|
"error" => Token::ErrorTerm,
|
||||||
|
@ -158,7 +166,9 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
||||||
comment_parser(Token::ModuleComment),
|
comment_parser(Token::ModuleComment),
|
||||||
comment_parser(Token::DocComment),
|
comment_parser(Token::DocComment),
|
||||||
comment_parser(Token::Comment),
|
comment_parser(Token::Comment),
|
||||||
choice((ordinal, keyword, int, op, newlines, grouping, string))
|
choice((
|
||||||
|
ordinal, keyword, int, op, newlines, grouping, bytestring, string,
|
||||||
|
))
|
||||||
.or(any().map(Token::Error).validate(|t, span, emit| {
|
.or(any().map(Token::Error).validate(|t, span, emit| {
|
||||||
emit(ParseError::expected_input_found(
|
emit(ParseError::expected_input_found(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub enum Token {
|
||||||
UpName { name: String },
|
UpName { name: String },
|
||||||
DiscardName { name: String },
|
DiscardName { name: String },
|
||||||
Int { value: String },
|
Int { value: String },
|
||||||
|
ByteString { value: String },
|
||||||
String { value: String },
|
String { value: String },
|
||||||
// Groupings
|
// Groupings
|
||||||
NewLineLeftParen, // ↳(
|
NewLineLeftParen, // ↳(
|
||||||
|
@ -97,6 +98,7 @@ impl fmt::Display for Token {
|
||||||
Token::DiscardName { name } => name,
|
Token::DiscardName { name } => name,
|
||||||
Token::Int { value } => value,
|
Token::Int { value } => value,
|
||||||
Token::String { value } => value,
|
Token::String { value } => value,
|
||||||
|
Token::ByteString { value } => value,
|
||||||
Token::NewLineLeftParen => "↳(",
|
Token::NewLineLeftParen => "↳(",
|
||||||
Token::LeftParen => "(",
|
Token::LeftParen => "(",
|
||||||
Token::RightParen => ")",
|
Token::RightParen => ")",
|
||||||
|
|
|
@ -235,12 +235,12 @@ fn list_pattern_6() {
|
||||||
fn trace_strings() {
|
fn trace_strings() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
fn bar() {
|
fn bar() {
|
||||||
"BAR"
|
@"BAR"
|
||||||
}
|
}
|
||||||
|
|
||||||
test foo() {
|
test foo() {
|
||||||
let msg1 = "FOO"
|
let msg1 = @"FOO"
|
||||||
trace("INLINE")
|
trace(@"INLINE")
|
||||||
trace(msg1)
|
trace(msg1)
|
||||||
trace(bar())
|
trace(bar())
|
||||||
True
|
True
|
||||||
|
@ -305,3 +305,17 @@ fn trace_if_false_ko() {
|
||||||
Err((_, Error::CouldNotUnify { .. }))
|
Err((_, Error::CouldNotUnify { .. }))
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn utf8_hex_literal_warning() {
|
||||||
|
let source_code = r#"
|
||||||
|
pub const policy_id = "f43a62fdc3965df486de8a0d32fe800963589c41b38946602a0dc535"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let (warnings, _) = check(parse(source_code)).unwrap();
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
warnings[0],
|
||||||
|
Warning::Utf8ByteArrayIsValidHexString { .. }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
@ -311,22 +311,6 @@ fn test_block_logical_expr() {
|
||||||
assert_fmt(src, expected);
|
assert_fmt(src, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_format_bytearray_literals() {
|
|
||||||
let src = indoc! {r#"
|
|
||||||
const foo = #"ff00"
|
|
||||||
const bar = #[0, 255]
|
|
||||||
"#};
|
|
||||||
|
|
||||||
let expected = indoc! { r#"
|
|
||||||
const foo = #"ff00"
|
|
||||||
|
|
||||||
const bar = #"00ff"
|
|
||||||
"#};
|
|
||||||
|
|
||||||
assert_fmt(src, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nested_function_calls() {
|
fn test_nested_function_calls() {
|
||||||
let src = indoc! {r#"
|
let src = indoc! {r#"
|
||||||
|
@ -360,7 +344,7 @@ fn test_nested_function_calls() {
|
||||||
),
|
),
|
||||||
when output.datum is {
|
when output.datum is {
|
||||||
InlineDatum(_) -> True
|
InlineDatum(_) -> True
|
||||||
_ -> error "expected inline datum"
|
_ -> error @"expected inline datum"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|> list.and
|
|> list.and
|
||||||
|
@ -398,7 +382,33 @@ fn format_trace_todo_error() {
|
||||||
}
|
}
|
||||||
"#};
|
"#};
|
||||||
|
|
||||||
assert_fmt(src, src);
|
let out = indoc! {r#"
|
||||||
|
fn foo_1() {
|
||||||
|
todo
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_2() {
|
||||||
|
todo @"my custom message"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_3() {
|
||||||
|
when x is {
|
||||||
|
Foo -> True
|
||||||
|
_ -> error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_4() {
|
||||||
|
if 14 == 42 {
|
||||||
|
error @"I don't think so"
|
||||||
|
} else {
|
||||||
|
trace @"been there"
|
||||||
|
True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#};
|
||||||
|
|
||||||
|
assert_fmt(src, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -503,3 +513,37 @@ fn test_newline_module_comments() {
|
||||||
|
|
||||||
assert_fmt(src, out);
|
assert_fmt(src, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bytearray_literals() {
|
||||||
|
let src = indoc! {r#"
|
||||||
|
const foo_const_array = #[102, 111, 111]
|
||||||
|
|
||||||
|
const foo_const_hex = #"666f6f"
|
||||||
|
|
||||||
|
const foo_const_utf8 = "foo"
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let foo_const_array = #[102, 111, 111]
|
||||||
|
|
||||||
|
let foo_const_hex = #"666f6f"
|
||||||
|
|
||||||
|
let foo_const_utf8 = "foo"
|
||||||
|
}
|
||||||
|
"#};
|
||||||
|
|
||||||
|
assert_fmt(src, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string_literal() {
|
||||||
|
let src = indoc! {r#"
|
||||||
|
const foo_const: String = @"foo"
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let foo_var: String = @"foo"
|
||||||
|
}
|
||||||
|
"#};
|
||||||
|
|
||||||
|
assert_fmt(src, src);
|
||||||
|
}
|
||||||
|
|
|
@ -1343,7 +1343,7 @@ fn call() {
|
||||||
#[test]
|
#[test]
|
||||||
fn record_update() {
|
fn record_update() {
|
||||||
let code = indoc! {r#"
|
let code = indoc! {r#"
|
||||||
fn update_name(user: User, name: String) -> User {
|
fn update_name(user: User, name: ByteArray) -> User {
|
||||||
User { ..user, name: "Aiken", age }
|
User { ..user, name: "Aiken", age }
|
||||||
}
|
}
|
||||||
"#};
|
"#};
|
||||||
|
@ -1373,60 +1373,61 @@ fn record_update() {
|
||||||
name: "name".to_string(),
|
name: "name".to_string(),
|
||||||
location: Span::new((), 27..31),
|
location: Span::new((), 27..31),
|
||||||
},
|
},
|
||||||
location: Span::new((), 27..39),
|
location: Span::new((), 27..42),
|
||||||
annotation: Some(ast::Annotation::Constructor {
|
annotation: Some(ast::Annotation::Constructor {
|
||||||
location: Span::new((), 33..39),
|
location: Span::new((), 33..42),
|
||||||
module: None,
|
module: None,
|
||||||
name: "String".to_string(),
|
name: "ByteArray".to_string(),
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
}),
|
}),
|
||||||
tipo: (),
|
tipo: (),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
body: expr::UntypedExpr::RecordUpdate {
|
body: expr::UntypedExpr::RecordUpdate {
|
||||||
location: Span::new((), 53..88),
|
location: Span::new((), 56..91),
|
||||||
constructor: Box::new(expr::UntypedExpr::Var {
|
constructor: Box::new(expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 53..57),
|
location: Span::new((), 56..60),
|
||||||
name: "User".to_string(),
|
name: "User".to_string(),
|
||||||
}),
|
}),
|
||||||
spread: ast::RecordUpdateSpread {
|
spread: ast::RecordUpdateSpread {
|
||||||
base: Box::new(expr::UntypedExpr::Var {
|
base: Box::new(expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 62..66),
|
location: Span::new((), 65..69),
|
||||||
name: "user".to_string(),
|
name: "user".to_string(),
|
||||||
}),
|
}),
|
||||||
location: Span::new((), 60..66),
|
location: Span::new((), 63..69),
|
||||||
},
|
},
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
ast::UntypedRecordUpdateArg {
|
ast::UntypedRecordUpdateArg {
|
||||||
label: "name".to_string(),
|
label: "name".to_string(),
|
||||||
location: Span::new((), 68..81),
|
location: Span::new((), 71..84),
|
||||||
value: expr::UntypedExpr::String {
|
value: expr::UntypedExpr::ByteArray {
|
||||||
location: Span::new((), 74..81),
|
location: Span::new((), 77..84),
|
||||||
value: "Aiken".to_string(),
|
bytes: String::from("Aiken").into_bytes(),
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::UntypedRecordUpdateArg {
|
ast::UntypedRecordUpdateArg {
|
||||||
label: "age".to_string(),
|
label: "age".to_string(),
|
||||||
location: Span::new((), 83..86),
|
location: Span::new((), 86..89),
|
||||||
value: expr::UntypedExpr::Var {
|
value: expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 83..86),
|
location: Span::new((), 86..89),
|
||||||
name: "age".to_string(),
|
name: "age".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
doc: None,
|
doc: None,
|
||||||
location: Span::new((), 0..48),
|
location: Span::new((), 0..51),
|
||||||
name: "update_name".to_string(),
|
name: "update_name".to_string(),
|
||||||
public: false,
|
public: false,
|
||||||
return_annotation: Some(ast::Annotation::Constructor {
|
return_annotation: Some(ast::Annotation::Constructor {
|
||||||
location: Span::new((), 44..48),
|
location: Span::new((), 47..51),
|
||||||
module: None,
|
module: None,
|
||||||
name: "User".to_string(),
|
name: "User".to_string(),
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
}),
|
}),
|
||||||
return_type: (),
|
return_type: (),
|
||||||
end_position: 89,
|
end_position: 92,
|
||||||
})],
|
})],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1448,9 +1449,10 @@ fn record_create_labeled() {
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
label: Some("name".to_string()),
|
label: Some("name".to_string()),
|
||||||
location: Span::new((), 23..36),
|
location: Span::new((), 23..36),
|
||||||
value: expr::UntypedExpr::String {
|
value: expr::UntypedExpr::ByteArray {
|
||||||
location: Span::new((), 29..36),
|
location: Span::new((), 29..36),
|
||||||
value: "Aiken".to_string(),
|
bytes: String::from("Aiken").into_bytes(),
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
|
@ -1504,9 +1506,10 @@ fn record_create_labeled_with_field_access() {
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
label: Some("name".to_string()),
|
label: Some("name".to_string()),
|
||||||
location: Span::new((), 35..48),
|
location: Span::new((), 35..48),
|
||||||
value: expr::UntypedExpr::String {
|
value: expr::UntypedExpr::ByteArray {
|
||||||
location: Span::new((), 41..48),
|
location: Span::new((), 41..48),
|
||||||
value: "Aiken".to_string(),
|
bytes: String::from("Aiken").into_bytes(),
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
|
@ -1785,6 +1788,7 @@ fn plain_bytearray_literals() {
|
||||||
value: Box::new(Constant::ByteArray {
|
value: Box::new(Constant::ByteArray {
|
||||||
location: Span::new((), 25..39),
|
location: Span::new((), 25..39),
|
||||||
bytes: vec![0, 170, 255],
|
bytes: vec![0, 170, 255],
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::ArrayOfBytes,
|
||||||
}),
|
}),
|
||||||
tipo: (),
|
tipo: (),
|
||||||
})],
|
})],
|
||||||
|
@ -1813,6 +1817,7 @@ fn base16_bytearray_literals() {
|
||||||
value: Box::new(Constant::ByteArray {
|
value: Box::new(Constant::ByteArray {
|
||||||
location: Span::new((), 25..34),
|
location: Span::new((), 25..34),
|
||||||
bytes: vec![0, 170, 255],
|
bytes: vec![0, 170, 255],
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::HexadecimalString,
|
||||||
}),
|
}),
|
||||||
tipo: (),
|
tipo: (),
|
||||||
}),
|
}),
|
||||||
|
@ -1828,6 +1833,7 @@ fn base16_bytearray_literals() {
|
||||||
right: Box::new(expr::UntypedExpr::ByteArray {
|
right: Box::new(expr::UntypedExpr::ByteArray {
|
||||||
location: Span::new((), 71..80),
|
location: Span::new((), 71..80),
|
||||||
bytes: vec![0, 170, 255],
|
bytes: vec![0, 170, 255],
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::HexadecimalString,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
doc: None,
|
doc: None,
|
||||||
|
@ -2489,9 +2495,10 @@ fn clause_guards() {
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::String {
|
right: Box::new(ast::ClauseGuard::Constant(ast::Constant::ByteArray {
|
||||||
location: Span::new((), 178..183),
|
location: Span::new((), 178..183),
|
||||||
value: "str".to_string(),
|
bytes: String::from("str").into_bytes(),
|
||||||
|
preferred_format: ast::ByteArrayFormatPreference::Utf8String,
|
||||||
})),
|
})),
|
||||||
}),
|
}),
|
||||||
then: expr::UntypedExpr::Var {
|
then: expr::UntypedExpr::Var {
|
||||||
|
@ -2669,10 +2676,10 @@ fn scope_logical_expression() {
|
||||||
fn trace_expressions() {
|
fn trace_expressions() {
|
||||||
let code = indoc! {r#"
|
let code = indoc! {r#"
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let msg1 = "FOO"
|
let msg1 = @"FOO"
|
||||||
trace "INLINE"
|
trace @"INLINE"
|
||||||
trace msg1
|
trace msg1
|
||||||
trace string.concat(msg1, "BAR")
|
trace string.concat(msg1, @"BAR")
|
||||||
trace ( 14 + 42 * 1337 )
|
trace ( 14 + 42 * 1337 )
|
||||||
Void
|
Void
|
||||||
}
|
}
|
||||||
|
@ -2682,12 +2689,12 @@ fn trace_expressions() {
|
||||||
vec![ast::Definition::Fn(Function {
|
vec![ast::Definition::Fn(Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
body: expr::UntypedExpr::Sequence {
|
body: expr::UntypedExpr::Sequence {
|
||||||
location: Span::new((), 13..128),
|
location: Span::new((), 13..131),
|
||||||
expressions: vec![
|
expressions: vec![
|
||||||
expr::UntypedExpr::Assignment {
|
expr::UntypedExpr::Assignment {
|
||||||
location: Span::new((), 13..29),
|
location: Span::new((), 13..30),
|
||||||
value: Box::new(expr::UntypedExpr::String {
|
value: Box::new(expr::UntypedExpr::String {
|
||||||
location: Span::new((), 24..29),
|
location: Span::new((), 24..30),
|
||||||
value: "FOO".to_string(),
|
value: "FOO".to_string(),
|
||||||
}),
|
}),
|
||||||
pattern: ast::Pattern::Var {
|
pattern: ast::Pattern::Var {
|
||||||
|
@ -2699,36 +2706,36 @@ fn trace_expressions() {
|
||||||
},
|
},
|
||||||
expr::UntypedExpr::Trace {
|
expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Trace,
|
kind: ast::TraceKind::Trace,
|
||||||
location: Span::new((), 32..128),
|
location: Span::new((), 33..131),
|
||||||
then: Box::new(expr::UntypedExpr::Trace {
|
then: Box::new(expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Trace,
|
kind: ast::TraceKind::Trace,
|
||||||
location: Span::new((), 49..128),
|
location: Span::new((), 51..131),
|
||||||
then: Box::new(expr::UntypedExpr::Trace {
|
then: Box::new(expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Trace,
|
kind: ast::TraceKind::Trace,
|
||||||
location: Span::new((), 62..128),
|
location: Span::new((), 64..131),
|
||||||
then: Box::new(expr::UntypedExpr::Trace {
|
then: Box::new(expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Trace,
|
kind: ast::TraceKind::Trace,
|
||||||
location: Span::new((), 97..128),
|
location: Span::new((), 100..131),
|
||||||
then: Box::new(expr::UntypedExpr::Var {
|
then: Box::new(expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 124..128),
|
location: Span::new((), 127..131),
|
||||||
name: "Void".to_string(),
|
name: "Void".to_string(),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::BinOp {
|
text: Box::new(expr::UntypedExpr::BinOp {
|
||||||
location: Span::new((), 105..119),
|
location: Span::new((), 108..122),
|
||||||
name: ast::BinOp::AddInt,
|
name: ast::BinOp::AddInt,
|
||||||
left: Box::new(expr::UntypedExpr::Int {
|
left: Box::new(expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 105..107),
|
location: Span::new((), 108..110),
|
||||||
value: "14".to_string(),
|
value: "14".to_string(),
|
||||||
}),
|
}),
|
||||||
right: Box::new(expr::UntypedExpr::BinOp {
|
right: Box::new(expr::UntypedExpr::BinOp {
|
||||||
location: Span::new((), 110..119),
|
location: Span::new((), 113..122),
|
||||||
name: ast::BinOp::MultInt,
|
name: ast::BinOp::MultInt,
|
||||||
left: Box::new(expr::UntypedExpr::Int {
|
left: Box::new(expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 110..112),
|
location: Span::new((), 113..115),
|
||||||
value: "42".to_string(),
|
value: "42".to_string(),
|
||||||
}),
|
}),
|
||||||
right: Box::new(expr::UntypedExpr::Int {
|
right: Box::new(expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 115..119),
|
location: Span::new((), 118..122),
|
||||||
value: "1337".to_string(),
|
value: "1337".to_string(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -2738,39 +2745,39 @@ fn trace_expressions() {
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
label: None,
|
label: None,
|
||||||
location: Span::new((), 82..86),
|
location: Span::new((), 84..88),
|
||||||
value: expr::UntypedExpr::Var {
|
value: expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 82..86),
|
location: Span::new((), 84..88),
|
||||||
name: "msg1".to_string(),
|
name: "msg1".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::CallArg {
|
ast::CallArg {
|
||||||
label: None,
|
label: None,
|
||||||
location: Span::new((), 88..93),
|
location: Span::new((), 90..96),
|
||||||
value: expr::UntypedExpr::String {
|
value: expr::UntypedExpr::String {
|
||||||
location: Span::new((), 88..93),
|
location: Span::new((), 90..96),
|
||||||
value: "BAR".to_string(),
|
value: "BAR".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
fun: Box::new(expr::UntypedExpr::FieldAccess {
|
fun: Box::new(expr::UntypedExpr::FieldAccess {
|
||||||
location: Span::new((), 68..81),
|
location: Span::new((), 70..83),
|
||||||
label: "concat".to_string(),
|
label: "concat".to_string(),
|
||||||
container: Box::new(expr::UntypedExpr::Var {
|
container: Box::new(expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 68..74),
|
location: Span::new((), 70..76),
|
||||||
name: "string".to_string(),
|
name: "string".to_string(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
location: Span::new((), 68..94),
|
location: Span::new((), 70..97),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::Var {
|
text: Box::new(expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 55..59),
|
location: Span::new((), 57..61),
|
||||||
name: "msg1".to_string(),
|
name: "msg1".to_string(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::String {
|
text: Box::new(expr::UntypedExpr::String {
|
||||||
location: Span::new((), 38..46),
|
location: Span::new((), 39..48),
|
||||||
value: "INLINE".to_string(),
|
value: "INLINE".to_string(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -2782,7 +2789,7 @@ fn trace_expressions() {
|
||||||
public: false,
|
public: false,
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
return_type: (),
|
return_type: (),
|
||||||
end_position: 129,
|
end_position: 132,
|
||||||
})],
|
})],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2791,7 +2798,7 @@ fn trace_expressions() {
|
||||||
fn parse_keyword_error() {
|
fn parse_keyword_error() {
|
||||||
let code = indoc! {r#"
|
let code = indoc! {r#"
|
||||||
fn foo() {
|
fn foo() {
|
||||||
error "not implemented"
|
error @"not implemented"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar() {
|
fn bar() {
|
||||||
|
@ -2808,12 +2815,12 @@ fn parse_keyword_error() {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
body: expr::UntypedExpr::Trace {
|
body: expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Error,
|
kind: ast::TraceKind::Error,
|
||||||
location: Span::new((), 13..36),
|
location: Span::new((), 13..37),
|
||||||
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
||||||
location: Span::new((), 13..36),
|
location: Span::new((), 13..37),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::String {
|
text: Box::new(expr::UntypedExpr::String {
|
||||||
location: Span::new((), 19..36),
|
location: Span::new((), 19..37),
|
||||||
value: "not implemented".to_string(),
|
value: "not implemented".to_string(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -2823,22 +2830,22 @@ fn parse_keyword_error() {
|
||||||
public: false,
|
public: false,
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
return_type: (),
|
return_type: (),
|
||||||
end_position: 37,
|
end_position: 38,
|
||||||
}),
|
}),
|
||||||
ast::Definition::Fn(Function {
|
ast::Definition::Fn(Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
body: expr::UntypedExpr::When {
|
body: expr::UntypedExpr::When {
|
||||||
location: Span::new((), 53..109),
|
location: Span::new((), 54..110),
|
||||||
subjects: vec![expr::UntypedExpr::Var {
|
subjects: vec![expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 58..59),
|
location: Span::new((), 59..60),
|
||||||
name: "x".to_string(),
|
name: "x".to_string(),
|
||||||
}],
|
}],
|
||||||
clauses: vec![
|
clauses: vec![
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 71..88),
|
location: Span::new((), 72..89),
|
||||||
pattern: vec![ast::Pattern::Constructor {
|
pattern: vec![ast::Pattern::Constructor {
|
||||||
is_record: false,
|
is_record: false,
|
||||||
location: Span::new((), 71..80),
|
location: Span::new((), 72..81),
|
||||||
name: "Something".to_string(),
|
name: "Something".to_string(),
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
module: None,
|
module: None,
|
||||||
|
@ -2849,26 +2856,26 @@ fn parse_keyword_error() {
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Var {
|
then: expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 84..88),
|
location: Span::new((), 85..89),
|
||||||
name: "Void".to_string(),
|
name: "Void".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 95..105),
|
location: Span::new((), 96..106),
|
||||||
pattern: vec![ast::Pattern::Discard {
|
pattern: vec![ast::Pattern::Discard {
|
||||||
name: "_".to_string(),
|
name: "_".to_string(),
|
||||||
location: Span::new((), 95..96),
|
location: Span::new((), 96..97),
|
||||||
}],
|
}],
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Trace {
|
then: expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Error,
|
kind: ast::TraceKind::Error,
|
||||||
location: Span::new((), 100..105),
|
location: Span::new((), 101..106),
|
||||||
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
||||||
location: Span::new((), 100..105),
|
location: Span::new((), 101..106),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::String {
|
text: Box::new(expr::UntypedExpr::String {
|
||||||
location: Span::new((), 100..105),
|
location: Span::new((), 101..106),
|
||||||
value: "aiken::error".to_string(),
|
value: "aiken::error".to_string(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -2876,12 +2883,12 @@ fn parse_keyword_error() {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
doc: None,
|
doc: None,
|
||||||
location: Span::new((), 40..48),
|
location: Span::new((), 41..49),
|
||||||
name: "bar".to_string(),
|
name: "bar".to_string(),
|
||||||
public: false,
|
public: false,
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
return_type: (),
|
return_type: (),
|
||||||
end_position: 110,
|
end_position: 111,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -2891,7 +2898,7 @@ fn parse_keyword_error() {
|
||||||
fn parse_keyword_todo() {
|
fn parse_keyword_todo() {
|
||||||
let code = indoc! {r#"
|
let code = indoc! {r#"
|
||||||
fn foo() {
|
fn foo() {
|
||||||
todo "not implemented"
|
todo @"not implemented"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar() {
|
fn bar() {
|
||||||
|
@ -2909,12 +2916,12 @@ fn parse_keyword_todo() {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
body: expr::UntypedExpr::Trace {
|
body: expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Todo,
|
kind: ast::TraceKind::Todo,
|
||||||
location: Span::new((), 13..35),
|
location: Span::new((), 13..36),
|
||||||
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
||||||
location: Span::new((), 13..35),
|
location: Span::new((), 13..36),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::String {
|
text: Box::new(expr::UntypedExpr::String {
|
||||||
location: Span::new((), 18..35),
|
location: Span::new((), 18..36),
|
||||||
value: "not implemented".to_string(),
|
value: "not implemented".to_string(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
@ -2924,22 +2931,22 @@ fn parse_keyword_todo() {
|
||||||
public: false,
|
public: false,
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
return_type: (),
|
return_type: (),
|
||||||
end_position: 36,
|
end_position: 37,
|
||||||
}),
|
}),
|
||||||
ast::Definition::Fn(Function {
|
ast::Definition::Fn(Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
body: expr::UntypedExpr::When {
|
body: expr::UntypedExpr::When {
|
||||||
location: Span::new((), 52..120),
|
location: Span::new((), 53..121),
|
||||||
subjects: vec![expr::UntypedExpr::Var {
|
subjects: vec![expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 57..58),
|
location: Span::new((), 58..59),
|
||||||
name: "x".to_string(),
|
name: "x".to_string(),
|
||||||
}],
|
}],
|
||||||
clauses: vec![
|
clauses: vec![
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 70..81),
|
location: Span::new((), 71..82),
|
||||||
pattern: vec![ast::Pattern::Constructor {
|
pattern: vec![ast::Pattern::Constructor {
|
||||||
is_record: false,
|
is_record: false,
|
||||||
location: Span::new((), 70..73),
|
location: Span::new((), 71..74),
|
||||||
name: "Foo".to_string(),
|
name: "Foo".to_string(),
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
module: None,
|
module: None,
|
||||||
|
@ -2951,21 +2958,21 @@ fn parse_keyword_todo() {
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Trace {
|
then: expr::UntypedExpr::Trace {
|
||||||
kind: ast::TraceKind::Todo,
|
kind: ast::TraceKind::Todo,
|
||||||
location: Span::new((), 77..81),
|
location: Span::new((), 78..82),
|
||||||
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
then: Box::new(expr::UntypedExpr::ErrorTerm {
|
||||||
location: Span::new((), 77..81),
|
location: Span::new((), 78..82),
|
||||||
}),
|
}),
|
||||||
text: Box::new(expr::UntypedExpr::String {
|
text: Box::new(expr::UntypedExpr::String {
|
||||||
location: Span::new((), 77..81),
|
location: Span::new((), 78..82),
|
||||||
value: "aiken::todo".to_string(),
|
value: "aiken::todo".to_string(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 88..99),
|
location: Span::new((), 89..100),
|
||||||
pattern: vec![ast::Pattern::Constructor {
|
pattern: vec![ast::Pattern::Constructor {
|
||||||
is_record: false,
|
is_record: false,
|
||||||
location: Span::new((), 88..91),
|
location: Span::new((), 89..92),
|
||||||
name: "Bar".to_string(),
|
name: "Bar".to_string(),
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
module: None,
|
module: None,
|
||||||
|
@ -2976,32 +2983,32 @@ fn parse_keyword_todo() {
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Var {
|
then: expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 95..99),
|
location: Span::new((), 96..100),
|
||||||
name: "True".to_string(),
|
name: "True".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 106..116),
|
location: Span::new((), 107..117),
|
||||||
pattern: vec![ast::Pattern::Discard {
|
pattern: vec![ast::Pattern::Discard {
|
||||||
name: "_".to_string(),
|
name: "_".to_string(),
|
||||||
location: Span::new((), 106..107),
|
location: Span::new((), 107..108),
|
||||||
}],
|
}],
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Var {
|
then: expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 111..116),
|
location: Span::new((), 112..117),
|
||||||
name: "False".to_string(),
|
name: "False".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
doc: None,
|
doc: None,
|
||||||
location: Span::new((), 39..47),
|
location: Span::new((), 40..48),
|
||||||
name: "bar".to_string(),
|
name: "bar".to_string(),
|
||||||
public: false,
|
public: false,
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
return_type: (),
|
return_type: (),
|
||||||
end_position: 121,
|
end_position: 122,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1244,6 +1244,31 @@ pub enum Warning {
|
||||||
#[label("unused")]
|
#[label("unused")]
|
||||||
location: Span,
|
location: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
"I noticed a suspicious {type_ByteArray} UTF-8 literal which resembles a hash digest.",
|
||||||
|
type_ByteArray = "ByteArray".bold().bright_blue()
|
||||||
|
)]
|
||||||
|
#[diagnostic(help("{}", formatdoc! {
|
||||||
|
r#"When you specify a {type_ByteArray} literal using plain double-quotes, it's interpreted as an array of UTF-8 bytes. For example, the literal {literal_foo} is interpreted as the byte sequence {foo_bytes}.
|
||||||
|
|
||||||
|
However here, you have specified a literal that resembles a hash digest encoded as an hexadecimal string. This is a common case, but you probably want to capture the raw bytes represented by this sequence, and not the hexadecimal sequence. Fear not! Aiken provides a convenient syntax for that: just prefix the literal with {symbol_hash}. This will decode the hexadecimal string for you and capture the non-encoded bytes as a {type_ByteArray}.
|
||||||
|
|
||||||
|
╰─▶ {symbol_hash}{value}
|
||||||
|
"#,
|
||||||
|
type_ByteArray = "ByteArray".bold().bright_blue(),
|
||||||
|
literal_foo = "\"foo\"".purple(),
|
||||||
|
foo_bytes = "#[102, 111, 111]".purple(),
|
||||||
|
value = "\"{value}\"".purple(),
|
||||||
|
symbol_hash = "#".purple(),
|
||||||
|
}))]
|
||||||
|
#[diagnostic(code("syntax::bytearray_literal_is_hex_string"))]
|
||||||
|
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#bytearray"))]
|
||||||
|
Utf8ByteArrayIsValidHexString {
|
||||||
|
#[label("missing '#' to decode hex string")]
|
||||||
|
location: Span,
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
|
@ -4,11 +4,11 @@ use vec1::Vec1;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, Clause, ClauseGuard, Constant,
|
Annotation, Arg, ArgName, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
|
||||||
IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg, TypedCallArg,
|
Clause, ClauseGuard, Constant, IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing,
|
||||||
TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern, TypedRecordUpdateArg,
|
TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern,
|
||||||
UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedMultiPattern,
|
TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch,
|
||||||
UntypedPattern, UntypedRecordUpdateArg,
|
UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg,
|
||||||
},
|
},
|
||||||
builtins::{bool, byte_array, function, int, list, string, tuple},
|
builtins::{bool, byte_array, function, int, list, string, tuple},
|
||||||
expr::{TypedExpr, UntypedExpr},
|
expr::{TypedExpr, UntypedExpr},
|
||||||
|
@ -350,9 +350,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
..
|
..
|
||||||
} => self.infer_tuple_index(*tuple, index, location),
|
} => self.infer_tuple_index(*tuple, index, location),
|
||||||
|
|
||||||
UntypedExpr::ByteArray { location, bytes } => {
|
UntypedExpr::ByteArray {
|
||||||
Ok(self.infer_byte_array(bytes, location))
|
bytes,
|
||||||
}
|
preferred_format,
|
||||||
|
location,
|
||||||
|
} => self.infer_bytearray(bytes, preferred_format, location),
|
||||||
|
|
||||||
UntypedExpr::RecordUpdate {
|
UntypedExpr::RecordUpdate {
|
||||||
location,
|
location,
|
||||||
|
@ -373,12 +375,27 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_byte_array(&mut self, bytes: Vec<u8>, location: Span) -> TypedExpr {
|
fn infer_bytearray(
|
||||||
TypedExpr::ByteArray {
|
&mut self,
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
preferred_format: ByteArrayFormatPreference,
|
||||||
|
location: Span,
|
||||||
|
) -> Result<TypedExpr, Error> {
|
||||||
|
if let ByteArrayFormatPreference::Utf8String = preferred_format {
|
||||||
|
let value = String::from_utf8(bytes.clone()).unwrap();
|
||||||
|
let is_hex_string = hex::decode(&value).is_ok();
|
||||||
|
if bytes.len() >= 56 && is_hex_string {
|
||||||
|
self.environment
|
||||||
|
.warnings
|
||||||
|
.push(Warning::Utf8ByteArrayIsValidHexString { location, value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(TypedExpr::ByteArray {
|
||||||
location,
|
location,
|
||||||
bytes,
|
bytes,
|
||||||
tipo: byte_array(),
|
tipo: byte_array(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_trace_if_false(
|
fn infer_trace_if_false(
|
||||||
|
@ -1353,7 +1370,18 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
location, value, ..
|
location, value, ..
|
||||||
} => Ok(Constant::String { location, value }),
|
} => Ok(Constant::String { location, value }),
|
||||||
|
|
||||||
Constant::ByteArray { location, bytes } => Ok(Constant::ByteArray { location, bytes }),
|
Constant::ByteArray {
|
||||||
|
location,
|
||||||
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
} => {
|
||||||
|
let _ = self.infer_bytearray(bytes.clone(), preferred_format, location)?;
|
||||||
|
Ok(Constant::ByteArray {
|
||||||
|
location,
|
||||||
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
})
|
||||||
|
}
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
// Check type annotation is accurate.
|
// Check type annotation is accurate.
|
||||||
|
|
|
@ -10,10 +10,10 @@ fn concat(left: String, right: String) -> String {
|
||||||
|
|
||||||
fn is_negative(i: Int) -> Bool {
|
fn is_negative(i: Int) -> Bool {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
trace "is negative"
|
trace @"is negative"
|
||||||
True
|
True
|
||||||
} else {
|
} else {
|
||||||
trace concat("is", concat(" ", "non-negative"))
|
trace concat(@"is", concat(@" ", @"non-negative"))
|
||||||
False
|
False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
[[requirements]]
|
[[requirements]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "3b47c89006e7580c2213370d7426ed2a38d2836e"
|
version = "main"
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
||||||
[[packages]]
|
[[packages]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "3b47c89006e7580c2213370d7426ed2a38d2836e"
|
version = "main"
|
||||||
requirements = []
|
requirements = []
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
name = "aiken-lang/acceptance_test_036"
|
name = "aiken-lang/acceptance_test_036"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
||||||
dependencies = [
|
[[dependencies]]
|
||||||
{ name = "aiken-lang/stdlib", version = "3b47c89006e7580c2213370d7426ed2a38d2836e", source = "github" },
|
name = 'aiken-lang/stdlib'
|
||||||
]
|
version = 'main'
|
||||||
|
source = 'github'
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
[[requirements]]
|
[[requirements]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "1cedbe85b7c7e9c4036d63d45cad4ced27b0d50b"
|
version = "main"
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
||||||
[[packages]]
|
[[packages]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "1cedbe85b7c7e9c4036d63d45cad4ced27b0d50b"
|
version = "main"
|
||||||
requirements = []
|
requirements = []
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
name = "aiken-lang/acceptance_test_054"
|
name = "aiken-lang/acceptance_test_054"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
||||||
dependencies = [
|
[[dependencies]]
|
||||||
{ name = "aiken-lang/stdlib", version = "1cedbe85b7c7e9c4036d63d45cad4ced27b0d50b", source = "github" },
|
name = 'aiken-lang/stdlib'
|
||||||
]
|
version = 'main'
|
||||||
|
source = 'github'
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
[[requirements]]
|
[[requirements]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "3b47c89006e7580c2213370d7426ed2a38d2836e"
|
version = "main"
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
||||||
[[packages]]
|
[[packages]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "3b47c89006e7580c2213370d7426ed2a38d2836e"
|
version = "main"
|
||||||
requirements = []
|
requirements = []
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
name = "aiken-lang/acceptance_test_055"
|
name = "aiken-lang/acceptance_test_055"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
||||||
dependencies = [
|
[[dependencies]]
|
||||||
{ name = "aiken-lang/stdlib", version="3b47c89006e7580c2213370d7426ed2a38d2836e", source = "github" },
|
name = 'aiken-lang/stdlib'
|
||||||
]
|
version = 'main'
|
||||||
|
source = 'github'
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
let foo = Module { name: "tests", docs: [], type_info: (), definitions: [Fn(Function { arguments: [Arg { arg_name: Named { name: "signatories", label: "signatories", location: 18..29 }, location: 18..29, annotation: None, tipo: () }], body: When { location: 35..154, subjects: [Var { location: 40..51, name: "signatories" }], clauses: [Clause { location: 61..115, pattern: [List { location: 61..63, elements: [], tail: None }], alternative_patterns: [], guard: None, then: Trace { kind: Trace, location: 75..109, then: Var { location: 104..109, name: "False" }, text: String { location: 81..97, value: "no signatories" } } }, Clause { location: 120..150, pattern: [List { location: 120..129, elements: [Var { location: 121..124, name: "sig" }], tail: Some(Discard { name: "_", location: 128..129 }) }], alternative_patterns: [], guard: None, then: TraceIfFalse { location: 133..150, value: BinOp { location: 134..148, name: Eq, left: Var { location: 134..137, name: "sig" }, right: String { location: 141..148, value: "#ffff" } } } }] }, doc: None, location: 0..30, name: "must_be_signed", public: false, return_annotation: None, return_type: (), end_position: 155 }), Fn(Function { arguments: [], body: Var { location: 182..186, name: "True" }, doc: None, location: 158..177, name: "must_say_hello", public: false, return_annotation: None, return_type: (), end_position: 187 }), Test(Function { arguments: [], body: BinOp { location: 205..260, name: Or, left: BinOp { location: 205..252, name: And, left: TraceIfFalse { location: 205..231, value: Call { arguments: [CallArg { label: None, location: 220..229, value: List { location: 220..229, elements: [String { location: 221..228, value: "#f000" }], tail: None } }], fun: Var { location: 205..219, name: "must_be_signed" }, location: 205..230 } }, right: TraceIfFalse { location: 235..252, value: Call { arguments: [], fun: Var { location: 235..249, name: "must_say_hello" }, location: 235..251 } } }, right: Var { location: 256..260, name: "True" } }, doc: None, location: 190..200, name: "foo", public: false, return_annotation: None, return_type: (), end_position: 261 })], kind: Lib };
|
|
|
@ -1,4 +1,4 @@
|
||||||
name = 'aiken-lang/acceptance_test_061'
|
name = 'aiken-lang/acceptance_test_063'
|
||||||
version = '0.0.0'
|
version = '0.0.0'
|
||||||
description = ''
|
description = ''
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
fn must_be_signed(signatories) {
|
fn must_be_signed(signatories) {
|
||||||
when signatories is {
|
when signatories is {
|
||||||
[] -> {
|
[] -> {
|
||||||
trace "no signatories"
|
trace @"no signatories"
|
||||||
False
|
False
|
||||||
}
|
}
|
||||||
[sig, ..] -> (sig == "#ffff")?
|
[sig, ..] -> (sig == "#ffff")?
|
||||||
|
|
|
@ -28,7 +28,7 @@ fn assert_purpose(purpose) {
|
||||||
ref.transaction_id == TransactionId(
|
ref.transaction_id == TransactionId(
|
||||||
#"0000000000000000000000000000000000000000000000000000000000000000",
|
#"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
) && ref.output_index == 0
|
) && ref.output_index == 0
|
||||||
_ -> error "script purpose isn't 'Spend'"
|
_ -> error @"script purpose isn't 'Spend'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,6 @@ fn assert_outputs(transaction) {
|
||||||
output.reference_script == None,
|
output.reference_script == None,
|
||||||
]
|
]
|
||||||
|> list.and
|
|> list.and
|
||||||
_ -> error "unexpected number of outputs"
|
_ -> error @"unexpected number of outputs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn assert_outputs(outputs) {
|
||||||
when outputs is {
|
when outputs is {
|
||||||
[output_1, output_2, ..] ->
|
[output_1, output_2, ..] ->
|
||||||
assert_first_output(output_1) && assert_second_output(output_2)
|
assert_first_output(output_1) && assert_second_output(output_2)
|
||||||
_ -> error "expected transaction to have (at least) 2 outputs"
|
_ -> error @"expected transaction to have (at least) 2 outputs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ fn assert_second_output(output) {
|
||||||
),
|
),
|
||||||
when output.datum is {
|
when output.datum is {
|
||||||
InlineDatum(_) -> True
|
InlineDatum(_) -> True
|
||||||
_ -> error "expected inline datum"
|
_ -> error @"expected inline datum"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|> list.and
|
|> list.and
|
||||||
|
|
|
@ -29,7 +29,7 @@ fn assert_mint(purpose, transaction) {
|
||||||
let tokens = value.tokens(transaction.mint, policy_id)
|
let tokens = value.tokens(transaction.mint, policy_id)
|
||||||
|
|
||||||
when dict.get(tokens, #"666f6f") is {
|
when dict.get(tokens, #"666f6f") is {
|
||||||
None -> error "token not found"
|
None -> error @"token not found"
|
||||||
Some(quantity) -> quantity == 1337
|
Some(quantity) -> quantity == 1337
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,11 @@ validator spend {
|
||||||
|
|
||||||
[
|
[
|
||||||
when dict.get(ctx.transaction.withdrawals, alice) is {
|
when dict.get(ctx.transaction.withdrawals, alice) is {
|
||||||
None -> error "alice's withdrawal not found"
|
None -> error @"alice's withdrawal not found"
|
||||||
Some(value) -> value == 42
|
Some(value) -> value == 42
|
||||||
},
|
},
|
||||||
when dict.get(ctx.transaction.withdrawals, bob) is {
|
when dict.get(ctx.transaction.withdrawals, bob) is {
|
||||||
None -> error "bob's withdrawal not found"
|
None -> error @"bob's withdrawal not found"
|
||||||
Some(value) -> value == 14
|
Some(value) -> value == 14
|
||||||
},
|
},
|
||||||
dict.keys(ctx.transaction.withdrawals) == [alice, bob],
|
dict.keys(ctx.transaction.withdrawals) == [alice, bob],
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
[[requirements]]
|
[[requirements]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "43d8e740ffdf5febc59e51b7f0d5f8506115340c"
|
version = "main"
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
||||||
[[packages]]
|
[[packages]]
|
||||||
name = "aiken-lang/stdlib"
|
name = "aiken-lang/stdlib"
|
||||||
version = "43d8e740ffdf5febc59e51b7f0d5f8506115340c"
|
version = "main"
|
||||||
requirements = []
|
requirements = []
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
|
@ -2,6 +2,8 @@ name = "aiken-lang/hello_world"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
licences = ["Apache-2.0"]
|
licences = ["Apache-2.0"]
|
||||||
description = "Aiken contracts for project 'aiken-lang/hello_world'"
|
description = "Aiken contracts for project 'aiken-lang/hello_world'"
|
||||||
dependencies = [
|
|
||||||
{ name = "aiken-lang/stdlib", version = "43d8e740ffdf5febc59e51b7f0d5f8506115340c", source = "github" },
|
[[dependencies]]
|
||||||
]
|
name = "aiken-lang/stdlib"
|
||||||
|
version = "main"
|
||||||
|
source = "github"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use aiken/hash.{Blake2b_224, Hash}
|
use aiken/hash.{Blake2b_224, Hash}
|
||||||
use aiken/list
|
use aiken/list
|
||||||
use aiken/string
|
|
||||||
use aiken/transaction.{ScriptContext}
|
use aiken/transaction.{ScriptContext}
|
||||||
use aiken/transaction/credential.{VerificationKey}
|
use aiken/transaction/credential.{VerificationKey}
|
||||||
|
|
||||||
|
@ -14,7 +13,7 @@ type Redeemer {
|
||||||
|
|
||||||
validator spend {
|
validator spend {
|
||||||
fn(datum: Datum, redeemer: Redeemer, context: ScriptContext) -> Bool {
|
fn(datum: Datum, redeemer: Redeemer, context: ScriptContext) -> Bool {
|
||||||
let must_say_hello = string.from_bytearray(redeemer.msg) == "Hello, World!"
|
let must_say_hello = redeemer.msg == "Hello, World!"
|
||||||
|
|
||||||
let must_be_signed =
|
let must_be_signed =
|
||||||
list.has(context.transaction.extra_signatories, datum.owner)
|
list.has(context.transaction.extra_signatories, datum.owner)
|
||||||
|
@ -22,4 +21,3 @@ validator spend {
|
||||||
must_say_hello && must_be_signed
|
must_say_hello && must_be_signed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue