Merge pull request #454 from aiken-lang/newline-assignment
Enforce newline after assignment / clause.
This commit is contained in:
commit
4ed279b30d
|
@ -17,6 +17,7 @@
|
|||
- **aiken-lang**: update todo warning to include type
|
||||
- **aiken-lang**: `|>` operator can now be formatted as a single (short) line or forced over multiline in a flexible manner
|
||||
- **aiken-lang**: the compiler now provides better feedback for type holes (i.e. `_`) in type annotations
|
||||
- **aiken-lang**: assignment and clause guard are now always formatted on a new line
|
||||
- **aiken-lang**: unused let-bindings are now fully removed from generated code and discarded unused let-binding now raise a warning
|
||||
|
||||
## [v0.0.29] - 2023-MM-DD
|
||||
|
|
|
@ -285,7 +285,11 @@ impl<'comments> Formatter<'comments> {
|
|||
None => head,
|
||||
Some(t) => head.append(": ").append(self.annotation(t)),
|
||||
};
|
||||
head.append(" = ").append(self.const_expr(value))
|
||||
head.append(" =")
|
||||
.append(line())
|
||||
.append(self.const_expr(value))
|
||||
.nest(INDENT)
|
||||
.group()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -602,16 +606,14 @@ impl<'comments> Formatter<'comments> {
|
|||
&mut self,
|
||||
pattern: &'a UntypedPattern,
|
||||
value: &'a UntypedExpr,
|
||||
then: Option<&'a UntypedExpr>,
|
||||
kind: Option<AssignmentKind>,
|
||||
kind: AssignmentKind,
|
||||
annotation: &'a Option<Annotation>,
|
||||
) -> Document<'a> {
|
||||
self.pop_empty_lines(pattern.location().end);
|
||||
|
||||
let keyword = match kind {
|
||||
Some(AssignmentKind::Let) => "let ",
|
||||
Some(AssignmentKind::Expect) => "expect ",
|
||||
None => "try ",
|
||||
AssignmentKind::Let => "let ",
|
||||
AssignmentKind::Expect => "expect ",
|
||||
};
|
||||
|
||||
let pattern = self.pattern(pattern);
|
||||
|
@ -620,25 +622,11 @@ impl<'comments> Formatter<'comments> {
|
|||
.as_ref()
|
||||
.map(|a| ": ".to_doc().append(self.annotation(a)));
|
||||
|
||||
let doc = if then.is_some() {
|
||||
keyword.to_doc().force_break()
|
||||
} else {
|
||||
keyword.to_doc()
|
||||
}
|
||||
.append(pattern.append(annotation).group())
|
||||
.append(" =")
|
||||
.append(self.assigned_value(value));
|
||||
|
||||
if let Some(then) = then {
|
||||
doc.append(if self.pop_empty_lines(then.start_byte_index()) {
|
||||
lines(2)
|
||||
} else {
|
||||
line()
|
||||
})
|
||||
.append(self.expr(then))
|
||||
} else {
|
||||
doc
|
||||
}
|
||||
keyword
|
||||
.to_doc()
|
||||
.append(pattern.append(annotation).group())
|
||||
.append(" =")
|
||||
.append(self.case_clause_value(value))
|
||||
}
|
||||
|
||||
pub fn bytearray<'a>(
|
||||
|
@ -733,7 +721,7 @@ impl<'comments> Formatter<'comments> {
|
|||
annotation,
|
||||
kind,
|
||||
..
|
||||
} => self.assignment(pattern, value, None, Some(*kind), annotation),
|
||||
} => self.assignment(pattern, value, *kind, annotation),
|
||||
|
||||
UntypedExpr::Trace {
|
||||
kind, text, then, ..
|
||||
|
@ -1448,19 +1436,12 @@ impl<'comments> Formatter<'comments> {
|
|||
.force_break(),
|
||||
|
||||
UntypedExpr::Fn { .. } | UntypedExpr::List { .. } => {
|
||||
" ".to_doc().append(self.expr(expr)).group()
|
||||
line().append(self.expr(expr)).nest(INDENT).group()
|
||||
}
|
||||
|
||||
UntypedExpr::When { .. } => line().append(self.expr(expr)).nest(INDENT).group(),
|
||||
|
||||
_ => break_("", " ").append(self.expr(expr)).nest(INDENT).group(),
|
||||
}
|
||||
}
|
||||
|
||||
fn assigned_value<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> {
|
||||
match expr {
|
||||
UntypedExpr::When { .. } => " ".to_doc().append(self.expr(expr)).group(),
|
||||
_ => self.case_clause_value(expr),
|
||||
_ => line().append(self.expr(expr)).nest(INDENT).group(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,8 +90,10 @@ fn test_format_when() {
|
|||
let expected = indoc! {r#"
|
||||
pub fn foo(a) {
|
||||
when a is {
|
||||
True -> 14
|
||||
False -> 42
|
||||
True ->
|
||||
14
|
||||
False ->
|
||||
42
|
||||
}
|
||||
}
|
||||
"#};
|
||||
|
@ -134,8 +136,10 @@ fn test_format_nested_when_if() {
|
|||
xs
|
||||
} else {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[_x, ..rest] -> drop(rest, n - 1)
|
||||
[] ->
|
||||
[]
|
||||
[_x, ..rest] ->
|
||||
drop(rest, n - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,8 +151,10 @@ fn test_format_nested_when_if() {
|
|||
xs
|
||||
} else {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[_x, ..rest] -> drop(rest, n - 1)
|
||||
[] ->
|
||||
[]
|
||||
[_x, ..rest] ->
|
||||
drop(rest, n - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,14 +183,18 @@ fn test_format_nested_when() {
|
|||
let expected = indoc! {r#"
|
||||
fn foo() {
|
||||
when a is {
|
||||
None -> "foo"
|
||||
None ->
|
||||
"foo"
|
||||
Some(b) ->
|
||||
when b is {
|
||||
None -> "foo"
|
||||
None ->
|
||||
"foo"
|
||||
Some(c) ->
|
||||
when c is {
|
||||
None -> "foo"
|
||||
Some(_) -> "foo"
|
||||
None ->
|
||||
"foo"
|
||||
Some(_) ->
|
||||
"foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -343,8 +353,10 @@ fn test_nested_function_calls() {
|
|||
),
|
||||
),
|
||||
when output.datum is {
|
||||
InlineDatum(_) -> True
|
||||
_ -> error @"expected inline datum"
|
||||
InlineDatum(_) ->
|
||||
True
|
||||
_ ->
|
||||
error @"expected inline datum"
|
||||
},
|
||||
]
|
||||
|> list.and
|
||||
|
@ -393,8 +405,10 @@ fn format_trace_todo_error() {
|
|||
|
||||
fn foo_3() {
|
||||
when x is {
|
||||
Foo -> True
|
||||
_ -> error
|
||||
Foo ->
|
||||
True
|
||||
_ ->
|
||||
error
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -517,18 +531,24 @@ fn test_newline_module_comments() {
|
|||
#[test]
|
||||
fn test_bytearray_literals() {
|
||||
let src = indoc! {r#"
|
||||
const foo_const_array = #[102, 111, 111]
|
||||
const foo_const_array =
|
||||
#[102, 111, 111]
|
||||
|
||||
const foo_const_hex = #"666f6f"
|
||||
const foo_const_hex =
|
||||
#"666f6f"
|
||||
|
||||
const foo_const_utf8 = "foo"
|
||||
const foo_const_utf8 =
|
||||
"foo"
|
||||
|
||||
fn foo() {
|
||||
let foo_const_array = #[102, 111, 111]
|
||||
let foo_const_array =
|
||||
#[102, 111, 111]
|
||||
|
||||
let foo_const_hex = #"666f6f"
|
||||
let foo_const_hex =
|
||||
#"666f6f"
|
||||
|
||||
let foo_const_utf8 = "foo"
|
||||
let foo_const_utf8 =
|
||||
"foo"
|
||||
}
|
||||
"#};
|
||||
|
||||
|
@ -538,10 +558,12 @@ fn test_bytearray_literals() {
|
|||
#[test]
|
||||
fn test_string_literal() {
|
||||
let src = indoc! {r#"
|
||||
const foo_const: String = @"foo"
|
||||
const foo_const: String =
|
||||
@"foo"
|
||||
|
||||
fn foo() {
|
||||
let foo_var: String = @"foo"
|
||||
let foo_var: String =
|
||||
@"foo"
|
||||
}
|
||||
"#};
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn length(xs: List<a>) -> Int {
|
||||
when xs is {
|
||||
[] -> 0
|
||||
[_, ..rest] -> 1 + length(rest)
|
||||
[] ->
|
||||
0
|
||||
[_, ..rest] ->
|
||||
1 + length(rest)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn foldr(xs: List<a>, f: fn(a, b) -> b, zero: b) -> b {
|
||||
when xs is {
|
||||
[] -> zero
|
||||
[x, ..rest] -> f(x, foldr(rest, f, zero))
|
||||
[] ->
|
||||
zero
|
||||
[x, ..rest] ->
|
||||
f(x, foldr(rest, f, zero))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn foldr(xs: List<a>, f: fn(a, b) -> b, zero: b) -> b {
|
||||
when xs is {
|
||||
[] -> zero
|
||||
[x, ..rest] -> f(x, foldr(rest, f, zero))
|
||||
[] ->
|
||||
zero
|
||||
[x, ..rest] ->
|
||||
f(x, foldr(rest, f, zero))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@ use aiken/builtin.{head_list}
|
|||
|
||||
pub fn head(xs: List<a>) -> Option<a> {
|
||||
when xs is {
|
||||
[] -> None
|
||||
_ -> Some(head_list(xs))
|
||||
[] ->
|
||||
None
|
||||
_ ->
|
||||
Some(head_list(xs))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
|
||||
when xs is {
|
||||
[] -> ([], [])
|
||||
[] ->
|
||||
([], [])
|
||||
[(a, b), ..rest] -> {
|
||||
let (a_tail, b_tail) = unzip(rest)
|
||||
let (a_tail, b_tail) =
|
||||
unzip(rest)
|
||||
([a, ..a_tail], [b, ..b_tail])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn map(opt: Option<a>, f: fn(a) -> b) -> Option<b> {
|
||||
when opt is {
|
||||
None -> None
|
||||
Some(a) -> Some(f(a))
|
||||
None ->
|
||||
None
|
||||
Some(a) ->
|
||||
Some(f(a))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn map(xs: List<a>, f: fn(a) -> result) -> List<result> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[x, ..rest] -> [f(x), ..map(rest, f)]
|
||||
[] ->
|
||||
[]
|
||||
[x, ..rest] ->
|
||||
[f(x), ..map(rest, f)]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ use aiken/builtin
|
|||
|
||||
pub fn filter(xs: List<a>, f: fn(a) -> Bool) -> List<a> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[] ->
|
||||
[]
|
||||
[x, ..rest] ->
|
||||
if f(x) {
|
||||
[x, ..filter(rest, f)]
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
|
||||
when xs is {
|
||||
[] -> ([], [])
|
||||
[] ->
|
||||
([], [])
|
||||
[(a, b), ..rest] -> {
|
||||
let (a_tail, b_tail) = unzip(rest)
|
||||
let (a_tail, b_tail) =
|
||||
unzip(rest)
|
||||
([a, ..a_tail], [b, ..b_tail])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ pub fn drop(bytes: ByteArray, n: Int) -> ByteArray {
|
|||
}
|
||||
|
||||
test drop_1() {
|
||||
let x = #"01020304050607"
|
||||
let x =
|
||||
#"01020304050607"
|
||||
drop(x, 2) == #"0304050607"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn or_else(opt: Option<a>, default: a) -> a {
|
||||
when opt is {
|
||||
None -> default
|
||||
Some(a) -> a
|
||||
None ->
|
||||
default
|
||||
Some(a) ->
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn map(opt: Option<a>, f: fn(a) -> result) -> Option<result> {
|
||||
when opt is {
|
||||
None -> None
|
||||
Some(a) -> Some(f(a))
|
||||
None ->
|
||||
None
|
||||
Some(a) ->
|
||||
Some(f(a))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn map(opt: Option<a>, f: fn(a) -> result) -> Option<result> {
|
||||
when opt is {
|
||||
None -> None
|
||||
Some(a) -> Some(f(a))
|
||||
None ->
|
||||
None
|
||||
Some(a) ->
|
||||
Some(f(a))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn foldr(xs: List<a>, f: fn(a, b) -> b, zero: b) -> b {
|
||||
when xs is {
|
||||
[] -> zero
|
||||
[x, ..rest] -> f(x, foldr(rest, f, zero))
|
||||
[] ->
|
||||
zero
|
||||
[x, ..rest] ->
|
||||
f(x, foldr(rest, f, zero))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,8 +12,10 @@ pub fn filter_map(xs: List<a>, f: fn(a) -> Option<b>) -> List<b> {
|
|||
xs,
|
||||
fn(x, ys) {
|
||||
when f(x) is {
|
||||
None -> ys
|
||||
Some(y) -> [y, ..ys]
|
||||
None ->
|
||||
ys
|
||||
Some(y) ->
|
||||
[y, ..ys]
|
||||
}
|
||||
},
|
||||
[],
|
||||
|
|
|
@ -20,7 +20,8 @@ pub fn insert(
|
|||
|
||||
fn do_insert(elems: List<(key, value)>, k: key, v: value) -> List<(key, value)> {
|
||||
when elems is {
|
||||
[] -> [(k, v)]
|
||||
[] ->
|
||||
[(k, v)]
|
||||
[(k2, v2), ..rest] ->
|
||||
if k == k2 {
|
||||
[(k, v), ..rest]
|
||||
|
@ -32,8 +33,8 @@ fn do_insert(elems: List<(key, value)>, k: key, v: value) -> List<(key, value)>
|
|||
|
||||
fn fixture_1() {
|
||||
new()
|
||||
|> insert("foo", 42)
|
||||
|> insert("bar", 14)
|
||||
|> insert("foo", 42)
|
||||
|> insert("bar", 14)
|
||||
}
|
||||
|
||||
test to_list_2() {
|
||||
|
|
|
@ -4,11 +4,14 @@ pub fn map2(
|
|||
f: fn(a, b) -> result,
|
||||
) -> Option<result> {
|
||||
when opt_a is {
|
||||
None -> None
|
||||
None ->
|
||||
None
|
||||
Some(a) ->
|
||||
when opt_b is {
|
||||
None -> None
|
||||
Some(b) -> Some(f(a, b))
|
||||
None ->
|
||||
None
|
||||
Some(b) ->
|
||||
Some(f(a, b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn foldr(xs: List<a>, f: fn(a, b) -> b, zero: b) -> b {
|
||||
when xs is {
|
||||
[] -> zero
|
||||
[x, ..rest] -> f(x, foldr(rest, f, zero))
|
||||
[] ->
|
||||
zero
|
||||
[x, ..rest] ->
|
||||
f(x, foldr(rest, f, zero))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,8 +13,10 @@ pub fn concat(left: List<a>, right: List<a>) -> List<a> {
|
|||
|
||||
pub fn flat_map(xs: List<a>, f: fn(a) -> List<b>) -> List<b> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[x, ..rest] -> concat(f(x), flat_map(rest, f))
|
||||
[] ->
|
||||
[]
|
||||
[x, ..rest] ->
|
||||
concat(f(x), flat_map(rest, f))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pub fn filter(xs: List<a>, f: fn(a) -> Bool) -> List<a> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[] ->
|
||||
[]
|
||||
[x, ..rest] ->
|
||||
if f(x) {
|
||||
[x, ..filter(rest, f)]
|
||||
|
@ -12,8 +13,10 @@ pub fn filter(xs: List<a>, f: fn(a) -> Bool) -> List<a> {
|
|||
|
||||
pub fn unique(xs: List<a>) -> List<a> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[x, ..rest] -> [x, ..unique(filter(rest, fn(y) { y != x }))]
|
||||
[] ->
|
||||
[]
|
||||
[x, ..rest] ->
|
||||
[x, ..unique(filter(rest, fn(y) { y != x }))]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +25,7 @@ test unique_1() {
|
|||
}
|
||||
|
||||
test unique_2() {
|
||||
let xs = [1, 2, 3, 1]
|
||||
let xs =
|
||||
[1, 2, 3, 1]
|
||||
unique(xs) == [1, 2, 3]
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ pub fn from_list(xs: List<(key, value)>) -> AssocList<key, value> {
|
|||
|
||||
fn do_from_list(xs: List<(key, value)>) -> List<(key, value)> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[(k, v), ..rest] -> do_insert(do_from_list(rest), k, v)
|
||||
[] ->
|
||||
[]
|
||||
[(k, v), ..rest] ->
|
||||
do_insert(do_from_list(rest), k, v)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +29,8 @@ pub fn insert(
|
|||
|
||||
fn do_insert(elems: List<(key, value)>, k: key, v: value) -> List<(key, value)> {
|
||||
when elems is {
|
||||
[] -> [(k, v)]
|
||||
[] ->
|
||||
[(k, v)]
|
||||
[(k2, v2), ..rest] ->
|
||||
if k == k2 {
|
||||
[(k, v), ..rest]
|
||||
|
@ -49,15 +52,17 @@ fn do_union(
|
|||
right: List<(key, value)>,
|
||||
) -> List<(key, value)> {
|
||||
when left is {
|
||||
[] -> right
|
||||
[(k, v), ..rest] -> do_union(rest, do_insert(right, k, v))
|
||||
[] ->
|
||||
right
|
||||
[(k, v), ..rest] ->
|
||||
do_union(rest, do_insert(right, k, v))
|
||||
}
|
||||
}
|
||||
|
||||
fn fixture_1() {
|
||||
new()
|
||||
|> insert("foo", 42)
|
||||
|> insert("bar", 14)
|
||||
|> insert("foo", 42)
|
||||
|> insert("bar", 14)
|
||||
}
|
||||
|
||||
test union_1() {
|
||||
|
|
|
@ -5,7 +5,7 @@ fn concat(left: String, right: String) -> String {
|
|||
builtin.encode_utf8(left),
|
||||
builtin.encode_utf8(right),
|
||||
)
|
||||
|> builtin.decode_utf8
|
||||
|> builtin.decode_utf8
|
||||
}
|
||||
|
||||
fn is_negative(i: Int) -> Bool {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
test tuple_1() {
|
||||
let coordinates = (14, 42)
|
||||
let coordinates =
|
||||
(14, 42)
|
||||
coordinates.1st == 14 && coordinates.2nd == 42
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn foldr(self: List<a>, with: fn(a, b) -> b, zero: b) -> b {
|
||||
when self is {
|
||||
[] -> zero
|
||||
[x, ..xs] -> with(x, foldr(xs, with, zero))
|
||||
[] ->
|
||||
zero
|
||||
[x, ..xs] ->
|
||||
with(x, foldr(xs, with, zero))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ fn do_union_with(
|
|||
with: fn(ByteArray, value, value) -> Option<value>,
|
||||
) -> List<(ByteArray, value)> {
|
||||
when left is {
|
||||
[] -> right
|
||||
[] ->
|
||||
right
|
||||
[(k, v), ..rest] ->
|
||||
do_union_with(rest, do_insert_with(right, k, v, with), with)
|
||||
}
|
||||
|
@ -50,12 +51,15 @@ fn do_insert_with(
|
|||
with: fn(ByteArray, value, value) -> Option<value>,
|
||||
) -> List<(ByteArray, value)> {
|
||||
when self is {
|
||||
[] -> [(k, v)]
|
||||
[] ->
|
||||
[(k, v)]
|
||||
[(k2, v2), ..rest] ->
|
||||
if k == k2 {
|
||||
when with(k, v, v2) is {
|
||||
Some(combined) -> [(k, combined), ..rest]
|
||||
None -> rest
|
||||
Some(combined) ->
|
||||
[(k, combined), ..rest]
|
||||
None ->
|
||||
rest
|
||||
}
|
||||
} else {
|
||||
[(k2, v2), ..do_insert_with(rest, k, v, with)]
|
||||
|
|
|
@ -16,9 +16,9 @@ pub fn from_asset(
|
|||
) -> Value {
|
||||
let asset =
|
||||
dict.new()
|
||||
|> dict.insert(asset_name, quantity)
|
||||
|> dict.insert(asset_name, quantity)
|
||||
dict.new()
|
||||
|> dict.insert(policy_id, asset)
|
||||
|> dict.insert(policy_id, asset)
|
||||
}
|
||||
|
||||
pub fn from_lovelace(quantity: Int) -> Value {
|
||||
|
@ -35,7 +35,8 @@ pub fn add(left v0: Value, right v1: Value) -> Value {
|
|||
a0,
|
||||
a1,
|
||||
fn(_, q0, q1) {
|
||||
let q = q0 + q1
|
||||
let q =
|
||||
q0 + q1
|
||||
if q == 0 {
|
||||
None
|
||||
} else {
|
||||
|
@ -45,15 +46,19 @@ pub fn add(left v0: Value, right v1: Value) -> Value {
|
|||
)
|
||||
|
||||
when dict.toList(asset) is {
|
||||
[] -> None
|
||||
_ -> Some(asset)
|
||||
[] ->
|
||||
None
|
||||
_ ->
|
||||
Some(asset)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
test add_1() {
|
||||
let v1 = from_lovelace(1)
|
||||
let v2 = from_lovelace(-1)
|
||||
let v1 =
|
||||
from_lovelace(1)
|
||||
let v2 =
|
||||
from_lovelace(-1)
|
||||
add(v1, v2) == dict.new()
|
||||
}
|
||||
|
|
|
@ -3,19 +3,20 @@ use aiken/list
|
|||
use aiken/transaction.{Output, OutputReference, ScriptContext}
|
||||
use aiken/transaction/value.{PolicyId}
|
||||
|
||||
const my_policy_id: PolicyId = #"0000000000"
|
||||
const my_policy_id: PolicyId =
|
||||
#"0000000000"
|
||||
|
||||
pub fn has_policy_id(self: Output, policy_id: PolicyId) -> Bool {
|
||||
self.value
|
||||
|> value.tokens(policy_id)
|
||||
|> dict.is_empty
|
||||
|> not
|
||||
|> value.tokens(policy_id)
|
||||
|> dict.is_empty
|
||||
|> not
|
||||
}
|
||||
|
||||
validator spend {
|
||||
fn(_datum: Data, _redeemer: Data, ctx: ScriptContext) -> Bool {
|
||||
ctx.transaction.outputs
|
||||
|> list.any(has_policy_id(_, my_policy_id))
|
||||
|> list.any(has_policy_id(_, my_policy_id))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,8 +28,10 @@ validator mint(output_reference: OutputReference) {
|
|||
fn(input) { input.output_reference == output_reference },
|
||||
)
|
||||
is {
|
||||
Some(_) -> True
|
||||
None -> False
|
||||
Some(_) ->
|
||||
True
|
||||
None ->
|
||||
False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub fn and(self: List<Bool>) -> Bool {
|
||||
when self is {
|
||||
[] -> True
|
||||
[x, ..xs] -> x && and(xs)
|
||||
[] ->
|
||||
True
|
||||
[x, ..xs] ->
|
||||
x && and(xs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,8 +13,10 @@ test and_1() {
|
|||
|
||||
pub fn or(self: List<Bool>) -> Bool {
|
||||
when self is {
|
||||
[] -> False
|
||||
[x, ..xs] -> x || or(xs)
|
||||
[] ->
|
||||
False
|
||||
[x, ..xs] ->
|
||||
x || or(xs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ test expect_ford1() {
|
|||
builtin.list_data([]),
|
||||
],
|
||||
)
|
||||
expect Ford { owner, wheels, truck_bed_limit, .. }: Car = initial_car
|
||||
expect Ford { owner, wheels, truck_bed_limit, .. }: Car =
|
||||
initial_car
|
||||
owner == #"" && wheels == 4 && truck_bed_limit == 10000
|
||||
}
|
||||
|
||||
|
@ -41,26 +42,32 @@ test expect_ford2() {
|
|||
truck_bed_limit: 15000,
|
||||
car_doors: [],
|
||||
}
|
||||
expect Ford { owner, wheels, remote_connect, .. } = initial_car
|
||||
expect Ford { owner, wheels, remote_connect, .. } =
|
||||
initial_car
|
||||
owner == #"2222222222" && wheels == 6 && remote_connect == #""
|
||||
}
|
||||
|
||||
test expect_list1() {
|
||||
let initial_car = [5, 6, 7]
|
||||
expect [a, b, c] = initial_car
|
||||
let initial_car =
|
||||
[5, 6, 7]
|
||||
expect [a, b, c] =
|
||||
initial_car
|
||||
a == 5 && b == 6 && c == 7
|
||||
}
|
||||
|
||||
test expect_list2() {
|
||||
let initial_car = [5, 6, 7]
|
||||
expect [a, ..d] = initial_car
|
||||
let initial_car =
|
||||
[5, 6, 7]
|
||||
expect [a, ..d] =
|
||||
initial_car
|
||||
a == 5 && d == [6, 7]
|
||||
}
|
||||
|
||||
test expect_list3() {
|
||||
let initial_car =
|
||||
builtin.list_data([builtin.i_data(5), builtin.i_data(6), builtin.i_data(7)])
|
||||
expect [a, ..d]: List<Int> = initial_car
|
||||
expect [a, ..d]: List<Int> =
|
||||
initial_car
|
||||
a == 5 && d == [6, 7]
|
||||
}
|
||||
|
||||
|
@ -69,16 +76,22 @@ type Redeemer {
|
|||
}
|
||||
|
||||
test single_field_expect() {
|
||||
let redeemer = CreateVoteBatch { id: #"" }
|
||||
expect CreateVoteBatch { id } = redeemer
|
||||
let redeemer =
|
||||
CreateVoteBatch { id: #"" }
|
||||
expect CreateVoteBatch { id } =
|
||||
redeemer
|
||||
id == #""
|
||||
}
|
||||
|
||||
test single_when() {
|
||||
let redeemer = CreateVoteBatch { id: #"" }
|
||||
let x = when redeemer is {
|
||||
CreateVoteBatch { id } -> id == #""
|
||||
_ -> False
|
||||
}
|
||||
let redeemer =
|
||||
CreateVoteBatch { id: #"" }
|
||||
let x =
|
||||
when redeemer is {
|
||||
CreateVoteBatch { id } ->
|
||||
id == #""
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
x == True
|
||||
}
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
test foo_1() {
|
||||
let a = False
|
||||
let a =
|
||||
False
|
||||
when a is {
|
||||
True -> False
|
||||
False -> True
|
||||
True ->
|
||||
False
|
||||
False ->
|
||||
True
|
||||
}
|
||||
}
|
||||
|
||||
test foo_2() {
|
||||
let a = False
|
||||
let b = when a is {
|
||||
True -> 14
|
||||
False -> 42
|
||||
}
|
||||
let a =
|
||||
False
|
||||
let b =
|
||||
when a is {
|
||||
True ->
|
||||
14
|
||||
False ->
|
||||
42
|
||||
}
|
||||
b == 42
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ fn fibonnaci(n) {
|
|||
}
|
||||
|
||||
test foo() {
|
||||
let right = fn() { fibonnaci(15) == 610 }
|
||||
let left = False
|
||||
let right =
|
||||
fn() { fibonnaci(15) == 610 }
|
||||
let left =
|
||||
False
|
||||
left || right()
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
test sort_by_1() {
|
||||
let xs = [[4, 3, 2, 1], [2, 3, 4, 5]]
|
||||
let xs =
|
||||
[[4, 3, 2, 1], [2, 3, 4, 5]]
|
||||
when xs is {
|
||||
[[], ys] -> False
|
||||
[xs, []] -> False
|
||||
[[x, ..xs2], [y, ..ys2]] -> True
|
||||
_ -> False
|
||||
[[], ys] ->
|
||||
False
|
||||
[xs, []] ->
|
||||
False
|
||||
[[x, ..xs2], [y, ..ys2]] ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,47 @@
|
|||
test foo_1() {
|
||||
let a = False
|
||||
let a =
|
||||
False
|
||||
when a is {
|
||||
a if a -> False
|
||||
_ -> True
|
||||
a if a ->
|
||||
False
|
||||
_ ->
|
||||
True
|
||||
}
|
||||
}
|
||||
|
||||
test foo_2() {
|
||||
let point = (14, 42)
|
||||
let point =
|
||||
(14, 42)
|
||||
when point is {
|
||||
(x, _) if x > 100 -> False
|
||||
(x, _) if x > 10 -> True
|
||||
_ -> False
|
||||
(x, _) if x > 100 ->
|
||||
False
|
||||
(x, _) if x > 10 ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
test foo_3() {
|
||||
let point = (14, 42)
|
||||
let point =
|
||||
(14, 42)
|
||||
when point is {
|
||||
(x, y) if x == 14 && y <= 100 -> True
|
||||
_ -> False
|
||||
(x, y) if x == 14 && y <= 100 ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
test foo_4() {
|
||||
let a = False
|
||||
let point = (14, 42)
|
||||
let a =
|
||||
False
|
||||
let point =
|
||||
(14, 42)
|
||||
when point is {
|
||||
(x, y) if !a -> x + y == 56
|
||||
_ -> False
|
||||
(x, y) if !a ->
|
||||
x + y == 56
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
fn when_tuple(a: (Int, Int)) -> Int {
|
||||
when a is {
|
||||
(a, b) -> a
|
||||
(a, b) ->
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pub fn when_tuple(a: (Int, Int)) -> Int {
|
||||
when a is {
|
||||
(a, b) -> a
|
||||
(a, b) ->
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,46 +5,55 @@ pub type Thing {
|
|||
}
|
||||
|
||||
test let_1() {
|
||||
let x: Data = 1
|
||||
let x: Data =
|
||||
1
|
||||
|
||||
x == builtin.i_data(1)
|
||||
}
|
||||
|
||||
test let_2() {
|
||||
let x: Data = 1
|
||||
let x: Data =
|
||||
1
|
||||
|
||||
expect y: Int = x
|
||||
expect y: Int =
|
||||
x
|
||||
|
||||
y == 1
|
||||
}
|
||||
|
||||
test assert_1() {
|
||||
expect thing: Thing = builtin.constr_data(0, [builtin.i_data(1)])
|
||||
expect thing: Thing =
|
||||
builtin.constr_data(0, [builtin.i_data(1)])
|
||||
|
||||
thing.wow == 1
|
||||
}
|
||||
|
||||
fn cast_to_thing(x: Data) -> Thing {
|
||||
expect x: Thing = x
|
||||
expect x: Thing =
|
||||
x
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
test assert_2() {
|
||||
let thing = Thing { wow: 1 }
|
||||
let thing =
|
||||
Thing { wow: 1 }
|
||||
|
||||
let still_thing = cast_to_thing(thing)
|
||||
let still_thing =
|
||||
cast_to_thing(thing)
|
||||
|
||||
still_thing.wow == 1
|
||||
}
|
||||
|
||||
test tuple_1() {
|
||||
let thing = (#"aa", #"bb", #"cc")
|
||||
let thing =
|
||||
(#"aa", #"bb", #"cc")
|
||||
thing.1st == #"aa"
|
||||
}
|
||||
|
||||
test pair_1() {
|
||||
let thing = (#"aa", #"bb")
|
||||
let thing =
|
||||
(#"aa", #"bb")
|
||||
thing.1st == #"aa"
|
||||
}
|
||||
// should not typecheck
|
||||
|
|
|
@ -3,15 +3,20 @@ type TransactionId {
|
|||
}
|
||||
|
||||
test pattern_match_let() {
|
||||
let x = TransactionId { inner: #"0000" }
|
||||
let TransactionId(y) = x
|
||||
let x =
|
||||
TransactionId { inner: #"0000" }
|
||||
let TransactionId(y) =
|
||||
x
|
||||
y == #"0000"
|
||||
}
|
||||
|
||||
test pattern_match_when() {
|
||||
let x = TransactionId { inner: #"0000" }
|
||||
let y = when x is {
|
||||
TransactionId(y) -> y
|
||||
}
|
||||
let x =
|
||||
TransactionId { inner: #"0000" }
|
||||
let y =
|
||||
when x is {
|
||||
TransactionId(y) ->
|
||||
y
|
||||
}
|
||||
y == #"0000"
|
||||
}
|
||||
|
|
|
@ -5,12 +5,15 @@ pub type LinkedList<a> {
|
|||
|
||||
pub fn size(t: LinkedList<alg>) -> Int {
|
||||
when t is {
|
||||
Empty -> 0
|
||||
Node(_, tail) -> 1 + size(tail)
|
||||
Empty ->
|
||||
0
|
||||
Node(_, tail) ->
|
||||
1 + size(tail)
|
||||
}
|
||||
}
|
||||
|
||||
test foo() {
|
||||
let xs = Node(0, Node(1, Node(2, Empty)))
|
||||
let xs =
|
||||
Node(0, Node(1, Node(2, Empty)))
|
||||
size(xs) == 3
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use aiken/transaction/value
|
||||
|
||||
test test_quantity_of_1() {
|
||||
let x = value.from_asset(#"000000", #"000020e05363726970744f776e6572", -1)
|
||||
let x =
|
||||
value.from_asset(#"000000", #"000020e05363726970744f776e6572", -1)
|
||||
value.quantity_of(x, #"000000", #"000020e05363726970744f776e6572") < 0
|
||||
}
|
||||
|
|
|
@ -15,9 +15,12 @@ pub type MerkleTree {
|
|||
|
||||
pub fn root_hash(t: MerkleTree) -> Hash<Sha2_256, ByteArray> {
|
||||
when t is {
|
||||
Empty -> #""
|
||||
Leaf { hash, .. } -> hash
|
||||
Node { hash, .. } -> hash
|
||||
Empty ->
|
||||
#""
|
||||
Leaf { hash, .. } ->
|
||||
hash
|
||||
Node { hash, .. } ->
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,9 +30,12 @@ pub fn is_equal(a: MerkleTree, b: MerkleTree) -> Bool {
|
|||
|
||||
pub fn size(t: MerkleTree) -> Int {
|
||||
when t is {
|
||||
Empty -> 0
|
||||
Leaf{..} -> 1
|
||||
Node { left, right, .. } -> size(left) + size(right)
|
||||
Empty ->
|
||||
0
|
||||
Leaf{..} ->
|
||||
1
|
||||
Node { left, right, .. } ->
|
||||
size(left) + size(right)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,27 +49,33 @@ pub fn from_list(items0: List<ByteArray>) -> MerkleTree {
|
|||
|
||||
fn do_from_list(items: List<ByteArray>, len: Int) -> MerkleTree {
|
||||
when items is {
|
||||
[] -> Empty
|
||||
[value] -> Leaf { hash: sha2_256(value), value }
|
||||
[] ->
|
||||
Empty
|
||||
[value] ->
|
||||
Leaf { hash: sha2_256(value), value }
|
||||
all -> {
|
||||
let cutoff: Int = len / 2
|
||||
let cutoff: Int =
|
||||
len / 2
|
||||
let left =
|
||||
all
|
||||
|> list.take(cutoff)
|
||||
|> do_from_list(cutoff)
|
||||
|> list.take(cutoff)
|
||||
|> do_from_list(cutoff)
|
||||
let right =
|
||||
all
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_list(len - cutoff)
|
||||
let hash = combine_hash(root_hash(left), root_hash(right))
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_list(len - cutoff)
|
||||
let hash =
|
||||
combine_hash(root_hash(left), root_hash(right))
|
||||
Node { hash, left, right }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test foo() {
|
||||
let items = [#"aa", #"bb", #"cc"]
|
||||
let mt = from_list(items)
|
||||
let items =
|
||||
[#"aa", #"bb", #"cc"]
|
||||
let mt =
|
||||
from_list(items)
|
||||
size(mt) == 3
|
||||
}
|
||||
|
||||
|
@ -72,20 +84,24 @@ test some_test1() {
|
|||
}
|
||||
|
||||
test intersection_3() {
|
||||
let iv1 = between(0, 1)
|
||||
let iv2 = strictly_between(1, 2)
|
||||
let iv1 =
|
||||
between(0, 1)
|
||||
let iv2 =
|
||||
strictly_between(1, 2)
|
||||
intersection(iv1, iv2)
|
||||
|> is_empty
|
||||
|> is_empty
|
||||
}
|
||||
|
||||
const fooz = #"666f6f"
|
||||
const fooz =
|
||||
#"666f6f"
|
||||
|
||||
const bar = #"626172"
|
||||
const bar =
|
||||
#"626172"
|
||||
|
||||
fn fixture_1() {
|
||||
dict.new()
|
||||
|> dict.insert(fooz, 42, bytearray.compare)
|
||||
|> dict.insert(bar, 14, bytearray.compare)
|
||||
|> dict.insert(fooz, 42, bytearray.compare)
|
||||
|> dict.insert(bar, 14, bytearray.compare)
|
||||
}
|
||||
|
||||
test union_1() {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
// Could possibly be forbidden by the parser instead if we have no intent to support that.
|
||||
pub fn choice(self: List<Option<a>>) -> Option<a> {
|
||||
when self is {
|
||||
[] -> None
|
||||
[Some(_) as result, ..] -> result
|
||||
[None, ..others] -> choice(others)
|
||||
[] ->
|
||||
None
|
||||
[Some(_) as result, ..] ->
|
||||
result
|
||||
[None, ..others] ->
|
||||
choice(others)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
pub fn choice(self: List<Option<a>>) -> Option<a> {
|
||||
when self is {
|
||||
[] -> None
|
||||
[Some(x), ..] -> Some(x)
|
||||
[None, ..others] -> choice(others)
|
||||
[] ->
|
||||
None
|
||||
[Some(x), ..] ->
|
||||
Some(x)
|
||||
[None, ..others] ->
|
||||
choice(others)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
pub fn choice(self: List<Option<a>>) -> Option<a> {
|
||||
when self is {
|
||||
[] -> None
|
||||
[None, ..others] -> choice(others)
|
||||
[result, ..] -> result
|
||||
[] ->
|
||||
None
|
||||
[None, ..others] ->
|
||||
choice(others)
|
||||
[result, ..] ->
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
pub fn alt(left: Option<a>, right: Option<a>) -> Option<a> {
|
||||
when (left, right) is {
|
||||
(Some(a), Some(_)) -> Some(a)
|
||||
(None, Some(a)) -> Some(a)
|
||||
(Some(a), None) -> Some(a)
|
||||
(None, None) -> None
|
||||
(Some(a), Some(_)) ->
|
||||
Some(a)
|
||||
(None, Some(a)) ->
|
||||
Some(a)
|
||||
(Some(a), None) ->
|
||||
Some(a)
|
||||
(None, None) ->
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,17 +3,23 @@ fn whatever(_xs) {
|
|||
}
|
||||
|
||||
test foo() {
|
||||
let xs = [1, 2, 3]
|
||||
let xs =
|
||||
[1, 2, 3]
|
||||
when xs is {
|
||||
[x] -> x == 1
|
||||
_ -> whatever(xs)
|
||||
[x] ->
|
||||
x == 1
|
||||
_ ->
|
||||
whatever(xs)
|
||||
}
|
||||
}
|
||||
|
||||
test bar() {
|
||||
let xs = [1, 2, 3]
|
||||
let xs =
|
||||
[1, 2, 3]
|
||||
when xs is {
|
||||
[x] -> x == 1
|
||||
ys -> whatever(ys)
|
||||
[x] ->
|
||||
x == 1
|
||||
ys ->
|
||||
whatever(ys)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
test foo() {
|
||||
let xs = [[1, 2], [4, 5]]
|
||||
let xs =
|
||||
[[1, 2], [4, 5]]
|
||||
when xs is {
|
||||
[[_, _], [_, _]] -> True
|
||||
_ -> False
|
||||
[[_, _], [_, _]] ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
test sort_by_1() {
|
||||
let xs = [[4, 3], [2, 3]]
|
||||
let g = when xs is {
|
||||
[[x, xs2], [y, ys2]] -> True
|
||||
_ -> False
|
||||
}
|
||||
let xs =
|
||||
[[4, 3], [2, 3]]
|
||||
let g =
|
||||
when xs is {
|
||||
[[x, xs2], [y, ys2]] ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
|
||||
g == True
|
||||
}
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
const int_constant = 42
|
||||
const int_constant =
|
||||
42
|
||||
|
||||
test int() {
|
||||
int_constant == 42
|
||||
}
|
||||
|
||||
const bytearray_constant = #"abcd"
|
||||
const bytearray_constant =
|
||||
#"abcd"
|
||||
|
||||
test bytearray() {
|
||||
bytearray_constant == #"abcd"
|
||||
}
|
||||
|
||||
const string_constant = "FOO"
|
||||
const string_constant =
|
||||
"FOO"
|
||||
|
||||
test string() {
|
||||
string_constant == "FOO"
|
||||
|
|
|
@ -8,9 +8,11 @@ use aiken/transaction/credential.{
|
|||
}
|
||||
use aiken/transaction/value
|
||||
|
||||
const keyhash = #"010203040506"
|
||||
const keyhash =
|
||||
#"010203040506"
|
||||
|
||||
const scripthash = #"060504030201"
|
||||
const scripthash =
|
||||
#"060504030201"
|
||||
|
||||
pub fn keyhash_address(with_stake_credential: Option<StakeCredential>) {
|
||||
Address {
|
||||
|
@ -32,7 +34,8 @@ type SampleData {
|
|||
}
|
||||
|
||||
pub fn tx_1() -> Transaction {
|
||||
let sample_datum = SampleData { a: 1, b: #"01" }
|
||||
let sample_datum =
|
||||
SampleData { a: 1, b: #"01" }
|
||||
let tx =
|
||||
Transaction {
|
||||
inputs: [
|
||||
|
|
|
@ -4,7 +4,8 @@ fn must_be_signed(signatories) {
|
|||
trace @"no signatories"
|
||||
False
|
||||
}
|
||||
[sig, ..] -> (sig == "#ffff")?
|
||||
[sig, ..] ->
|
||||
(sig == "#ffff")?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,14 +15,16 @@ test foo() {
|
|||
|
||||
fn map(list: List<a>, f: fn(a) -> b) -> List<b> {
|
||||
when list is {
|
||||
[] -> []
|
||||
[x, ..xs] -> [f(x), ..map(xs, f)]
|
||||
[] ->
|
||||
[]
|
||||
[x, ..xs] ->
|
||||
[f(x), ..map(xs, f)]
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fields(data: Data) -> List<Int> {
|
||||
builtin.un_constr_data(data).2nd
|
||||
|> map(builtin.un_i_data)
|
||||
|> map(builtin.un_i_data)
|
||||
}
|
||||
|
||||
test bar() {
|
||||
|
|
|
@ -37,13 +37,13 @@ fn inspect_list(_data: Data) -> Data {
|
|||
fn inspect_integer(data: Data) -> Data {
|
||||
let result: Data =
|
||||
builtin.un_i_data(data)
|
||||
|> Integer
|
||||
|> Integer
|
||||
result
|
||||
}
|
||||
|
||||
fn inspect_bytearray(data: Data) -> Data {
|
||||
let result: Data =
|
||||
builtin.un_b_data(data)
|
||||
|> Bytes
|
||||
|> Bytes
|
||||
result
|
||||
}
|
||||
|
|
|
@ -33,20 +33,29 @@ pub type ProofItem {
|
|||
/// Deconstruct a 'MerkleTree' back to a list of elements.
|
||||
pub fn to_list(self: MerkleTree<a>) -> List<a> {
|
||||
when self is {
|
||||
Empty -> []
|
||||
Leaf { value, .. } -> [value]
|
||||
Node { left, right, .. } -> list.concat(to_list(left), to_list(right))
|
||||
Empty ->
|
||||
[]
|
||||
Leaf { value, .. } ->
|
||||
[value]
|
||||
Node { left, right, .. } ->
|
||||
list.concat(to_list(left), to_list(right))
|
||||
}
|
||||
}
|
||||
|
||||
test to_list_1() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let items = [dog, cat, mouse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let items =
|
||||
[dog, cat, mouse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
items == to_list(mt)
|
||||
}
|
||||
|
@ -54,47 +63,68 @@ test to_list_1() {
|
|||
// Function returning a hash of a given Merkle Tree element
|
||||
pub fn root_hash(self: MerkleTree<a>) -> Hash<Sha2_256, ByteArray> {
|
||||
when self is {
|
||||
Empty -> ""
|
||||
Leaf { hash, .. } -> hash
|
||||
Node { hash, .. } -> hash
|
||||
Empty ->
|
||||
""
|
||||
Leaf { hash, .. } ->
|
||||
hash
|
||||
Node { hash, .. } ->
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
test root_hash_1() {
|
||||
let dog = "dog"
|
||||
let items = [dog]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let dog =
|
||||
"dog"
|
||||
let items =
|
||||
[dog]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let node_hash = hash_fn(dog)
|
||||
let node_hash =
|
||||
hash_fn(dog)
|
||||
|
||||
root_hash(mt) == node_hash
|
||||
}
|
||||
|
||||
test root_hash_3() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let items = [dog, cat, mouse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let items =
|
||||
[dog, cat, mouse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let node_hash = sha2_256(bytearray.concat(hash_fn(cat), hash_fn(mouse)))
|
||||
let rh = sha2_256(bytearray.concat(hash_fn(dog), node_hash))
|
||||
let node_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(cat), hash_fn(mouse)))
|
||||
let rh =
|
||||
sha2_256(bytearray.concat(hash_fn(dog), node_hash))
|
||||
|
||||
expect Node { hash: root_hash, .. } = mt
|
||||
expect Node { hash: root_hash, .. } =
|
||||
mt
|
||||
|
||||
rh == root_hash
|
||||
}
|
||||
|
||||
test root_hash_2() {
|
||||
let items = []
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let node_hash = #""
|
||||
let node_hash =
|
||||
#""
|
||||
|
||||
root_hash(mt) == node_hash
|
||||
}
|
||||
|
@ -107,52 +137,78 @@ pub fn is_equal(left: MerkleTree<a>, right: MerkleTree<a>) -> Bool {
|
|||
/// Function returns a total numbers of leaves in the tree.
|
||||
pub fn size(self: MerkleTree<a>) -> Int {
|
||||
when self is {
|
||||
Empty -> 0
|
||||
Leaf{..} -> 1
|
||||
Node { left, right, .. } -> size(left) + size(right)
|
||||
Empty ->
|
||||
0
|
||||
Leaf{..} ->
|
||||
1
|
||||
Node { left, right, .. } ->
|
||||
size(left) + size(right)
|
||||
}
|
||||
}
|
||||
|
||||
test size_1() {
|
||||
let items = []
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
size(mt) == 0
|
||||
}
|
||||
|
||||
test size_2() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list([dog, cat, mouse], hash_fn)
|
||||
let mt =
|
||||
from_list([dog, cat, mouse], hash_fn)
|
||||
size(mt) == 3
|
||||
}
|
||||
|
||||
test size_3() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let items = [dog, cat, mouse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let items =
|
||||
[dog, cat, mouse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
size(mt) == 3
|
||||
}
|
||||
|
||||
test size_4() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let pig = "pig"
|
||||
let bull = "bull"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
let pig =
|
||||
"pig"
|
||||
let bull =
|
||||
"bull"
|
||||
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let items = [dog, cat, mouse, horse, pig, bull]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let items =
|
||||
[dog, cat, mouse, horse, pig, bull]
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
size(mt) == 6
|
||||
}
|
||||
|
||||
|
@ -166,22 +222,28 @@ fn combine_hash(
|
|||
/// Function that returns whether merkle tree has any elements
|
||||
pub fn is_empty(self: MerkleTree<a>) -> Bool {
|
||||
when self is {
|
||||
Empty -> True
|
||||
_ -> False
|
||||
Empty ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
test is_empty_1() {
|
||||
let mt = Empty
|
||||
let mt =
|
||||
Empty
|
||||
|
||||
is_empty(mt)
|
||||
}
|
||||
|
||||
test is_empty_2() {
|
||||
let dog = "dog"
|
||||
let hash = create_string_item_hash_fn()
|
||||
let dog =
|
||||
"dog"
|
||||
let hash =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = Leaf { value: dog, hash: hash(dog) }
|
||||
let mt =
|
||||
Leaf { value: dog, hash: hash(dog) }
|
||||
|
||||
is_empty(mt) == False
|
||||
}
|
||||
|
@ -193,7 +255,8 @@ fn do_proof(
|
|||
hash_fn: fn(a) -> Hash<Sha2_256, a>,
|
||||
) -> Option<Proof> {
|
||||
when self is {
|
||||
Empty -> None
|
||||
Empty ->
|
||||
None
|
||||
Leaf { hash, .. } ->
|
||||
if hash == item_hash {
|
||||
Some(proof)
|
||||
|
@ -201,8 +264,10 @@ fn do_proof(
|
|||
None
|
||||
}
|
||||
Node { left, right, .. } -> {
|
||||
let rh = root_hash(right)
|
||||
let lh = root_hash(left)
|
||||
let rh =
|
||||
root_hash(right)
|
||||
let lh =
|
||||
root_hash(left)
|
||||
let go_left: Option<Proof> =
|
||||
do_proof(left, item_hash, list.push(proof, Right { hash: rh }), hash_fn)
|
||||
let go_right: Option<Proof> =
|
||||
|
@ -220,93 +285,137 @@ pub fn get_proof(
|
|||
item: a,
|
||||
hash_fn: fn(a) -> Hash<Sha2_256, a>,
|
||||
) -> Option<Proof> {
|
||||
let empty: Proof = []
|
||||
let empty: Proof =
|
||||
[]
|
||||
|
||||
do_proof(self, hash_fn(item), empty, hash_fn)
|
||||
}
|
||||
|
||||
test get_proof_1() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let pig = "pig"
|
||||
let bull = "bull"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
let pig =
|
||||
"pig"
|
||||
let bull =
|
||||
"bull"
|
||||
|
||||
let items = [dog, cat, mouse, horse, pig, bull]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let items =
|
||||
[dog, cat, mouse, horse, pig, bull]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let maybe_proof: Option<Proof> = get_proof(mt, "parrot", hash_fn)
|
||||
let maybe_proof: Option<Proof> =
|
||||
get_proof(mt, "parrot", hash_fn)
|
||||
|
||||
is_none(maybe_proof)
|
||||
}
|
||||
|
||||
test get_proof_2() {
|
||||
let dog = "dog"
|
||||
let dog =
|
||||
"dog"
|
||||
|
||||
let items = [dog]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let maybe_proof: Option<Proof> = get_proof(mt, dog, hash_fn)
|
||||
let maybe_proof: Option<Proof> =
|
||||
get_proof(mt, dog, hash_fn)
|
||||
|
||||
expect Some(proof) = maybe_proof
|
||||
expect Some(proof) =
|
||||
maybe_proof
|
||||
|
||||
// when proof is empty list it actually means that root of the tree is in fact element
|
||||
proof == []
|
||||
}
|
||||
|
||||
test get_proof_3() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
|
||||
let items = [dog, cat, mouse]
|
||||
let items =
|
||||
[dog, cat, mouse]
|
||||
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let node_hash = sha2_256(bytearray.concat(hash_fn(cat), hash_fn(mouse)))
|
||||
let node_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(cat), hash_fn(mouse)))
|
||||
|
||||
let maybe_proof: Option<Proof> = get_proof(mt, dog, hash_fn)
|
||||
let maybe_proof: Option<Proof> =
|
||||
get_proof(mt, dog, hash_fn)
|
||||
|
||||
expect Some(proof) = maybe_proof
|
||||
expect Some(proof) =
|
||||
maybe_proof
|
||||
|
||||
let size_match = list.length(proof) == 1
|
||||
let size_match =
|
||||
list.length(proof) == 1
|
||||
|
||||
expect Some(p1) = list.at(proof, 0)
|
||||
expect Some(p1) =
|
||||
list.at(proof, 0)
|
||||
|
||||
let h1: ByteArray = get_proof_item_value(p1)
|
||||
let h1: ByteArray =
|
||||
get_proof_item_value(p1)
|
||||
|
||||
size_match && h1 == node_hash
|
||||
}
|
||||
|
||||
test get_proof_4() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
|
||||
let items = [dog, cat, mouse, horse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat, mouse, horse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let right_node_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(mouse), hash_fn(horse)))
|
||||
let maybe_proof: Option<Proof> = get_proof(mt, dog, hash_fn)
|
||||
let maybe_proof: Option<Proof> =
|
||||
get_proof(mt, dog, hash_fn)
|
||||
|
||||
expect Some(proof) = maybe_proof
|
||||
expect Some(proof) =
|
||||
maybe_proof
|
||||
|
||||
let size_match = list.length(proof) == 2
|
||||
let size_match =
|
||||
list.length(proof) == 2
|
||||
|
||||
expect Some(p1) = list.at(proof, 0)
|
||||
expect Some(p2) = list.at(proof, 1)
|
||||
expect Some(p1) =
|
||||
list.at(proof, 0)
|
||||
expect Some(p2) =
|
||||
list.at(proof, 1)
|
||||
|
||||
let h1: ByteArray = get_proof_item_value(p1)
|
||||
let h2: ByteArray = get_proof_item_value(p2)
|
||||
let h1: ByteArray =
|
||||
get_proof_item_value(p1)
|
||||
let h2: ByteArray =
|
||||
get_proof_item_value(p2)
|
||||
|
||||
size_match && h1 == hash_fn(cat) && h2 == right_node_hash
|
||||
}
|
||||
|
@ -317,22 +426,26 @@ fn do_from_list(
|
|||
hash_fn: fn(a) -> Hash<Sha2_256, a>,
|
||||
) -> MerkleTree<a> {
|
||||
when items is {
|
||||
[] -> Empty
|
||||
[] ->
|
||||
Empty
|
||||
[item] -> {
|
||||
let hashed_item = hash_fn(item)
|
||||
let hashed_item =
|
||||
hash_fn(item)
|
||||
Leaf { value: item, hash: hashed_item }
|
||||
}
|
||||
all -> {
|
||||
let cutoff: Int = len / 2
|
||||
let cutoff: Int =
|
||||
len / 2
|
||||
let left =
|
||||
all
|
||||
|> list.take(cutoff)
|
||||
|> do_from_list(cutoff, hash_fn)
|
||||
|> list.take(cutoff)
|
||||
|> do_from_list(cutoff, hash_fn)
|
||||
let right =
|
||||
all
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_list(len - cutoff, hash_fn)
|
||||
let hash = combine_hash(root_hash(left), root_hash(right))
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_list(len - cutoff, hash_fn)
|
||||
let hash =
|
||||
combine_hash(root_hash(left), root_hash(right))
|
||||
Node { hash, left, right }
|
||||
}
|
||||
}
|
||||
|
@ -349,32 +462,46 @@ pub fn from_list(
|
|||
}
|
||||
|
||||
test from_1() {
|
||||
let _a = -1
|
||||
let items = []
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let _a =
|
||||
-1
|
||||
let items =
|
||||
[]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
Empty == mt
|
||||
}
|
||||
|
||||
test from_2() {
|
||||
let dog = "dog"
|
||||
let items = [dog]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let dog =
|
||||
"dog"
|
||||
let items =
|
||||
[dog]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
Leaf { value: dog, hash: hash_fn(dog) } == mt
|
||||
}
|
||||
|
||||
test from_3() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let items = [dog, cat]
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let items =
|
||||
[dog, cat]
|
||||
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let root_hash = sha2_256(bytearray.concat(hash_fn(dog), hash_fn(cat)))
|
||||
let root_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(dog), hash_fn(cat)))
|
||||
|
||||
Node {
|
||||
hash: root_hash,
|
||||
|
@ -384,17 +511,25 @@ test from_3() {
|
|||
}
|
||||
|
||||
test from_4() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
|
||||
let items = [dog, cat, mouse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let items =
|
||||
[dog, cat, mouse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let mt = from_list(items, hash_fn)
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let node_hash = sha2_256(bytearray.concat(hash_fn(cat), hash_fn(mouse)))
|
||||
let root_hash = sha2_256(bytearray.concat(hash_fn(dog), node_hash))
|
||||
let node_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(cat), hash_fn(mouse)))
|
||||
let root_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(dog), node_hash))
|
||||
|
||||
Node {
|
||||
hash: root_hash,
|
||||
|
@ -408,21 +543,30 @@ test from_4() {
|
|||
}
|
||||
|
||||
test from_5() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let items = [dog, cat, mouse, horse]
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat, mouse, horse]
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let left_node_hash = sha2_256(bytearray.concat(hash_fn(dog), hash_fn(cat)))
|
||||
let left_node_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(dog), hash_fn(cat)))
|
||||
let right_node_hash =
|
||||
sha2_256(bytearray.concat(hash_fn(mouse), hash_fn(horse)))
|
||||
|
||||
let root_hash = sha2_256(bytearray.concat(left_node_hash, right_node_hash))
|
||||
let root_hash =
|
||||
sha2_256(bytearray.concat(left_node_hash, right_node_hash))
|
||||
|
||||
Node {
|
||||
hash: root_hash,
|
||||
|
@ -450,7 +594,8 @@ pub fn member_from_hash(
|
|||
hash_fn: fn(a) -> Hash<Sha2_256, a>,
|
||||
) -> Bool {
|
||||
when proof is {
|
||||
[] -> root_hash == item_hash
|
||||
[] ->
|
||||
root_hash == item_hash
|
||||
[head, ..tail] ->
|
||||
when head is {
|
||||
Left { hash: l } ->
|
||||
|
@ -469,113 +614,173 @@ pub fn member(
|
|||
proof: Proof,
|
||||
hash_fn: fn(a) -> Hash<Sha2_256, a>,
|
||||
) -> Bool {
|
||||
let item_hash = hash_fn(item)
|
||||
let item_hash =
|
||||
hash_fn(item)
|
||||
member_from_hash(item_hash, root_hash, proof, hash_fn)
|
||||
}
|
||||
|
||||
test member_1() {
|
||||
let dog = "dog"
|
||||
let items = [dog]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let dog =
|
||||
"dog"
|
||||
let items =
|
||||
[dog]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let item = dog
|
||||
let rh = root_hash(mt)
|
||||
let item =
|
||||
dog
|
||||
let rh =
|
||||
root_hash(mt)
|
||||
|
||||
expect Some(proof) = get_proof(mt, item, hash_fn)
|
||||
expect Some(proof) =
|
||||
get_proof(mt, item, hash_fn)
|
||||
member(item: item, root_hash: rh, proof: proof, hash_fn: hash_fn)
|
||||
}
|
||||
|
||||
test member_2() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
|
||||
let items = [dog, cat, mouse, horse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat, mouse, horse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let item = cat
|
||||
let rh = root_hash(mt)
|
||||
let item =
|
||||
cat
|
||||
let rh =
|
||||
root_hash(mt)
|
||||
|
||||
expect Some(proof) = get_proof(mt, item, hash_fn)
|
||||
expect Some(proof) =
|
||||
get_proof(mt, item, hash_fn)
|
||||
member(item: item, root_hash: rh, proof: proof, hash_fn: hash_fn)
|
||||
}
|
||||
|
||||
test member_3() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
|
||||
let items = [dog, cat]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let item = cat
|
||||
let rh = root_hash(mt)
|
||||
let item =
|
||||
cat
|
||||
let rh =
|
||||
root_hash(mt)
|
||||
|
||||
expect Some(proof) = get_proof(mt, item, hash_fn)
|
||||
expect Some(proof) =
|
||||
get_proof(mt, item, hash_fn)
|
||||
member(item: item, root_hash: rh, proof: proof, hash_fn: hash_fn)
|
||||
}
|
||||
|
||||
test member_4() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
|
||||
let items = [dog, cat, mouse]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat, mouse]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let item = mouse
|
||||
let rh = root_hash(mt)
|
||||
let item =
|
||||
mouse
|
||||
let rh =
|
||||
root_hash(mt)
|
||||
|
||||
expect Some(proof) = get_proof(mt, item, hash_fn)
|
||||
expect Some(proof) =
|
||||
get_proof(mt, item, hash_fn)
|
||||
member(item: item, root_hash: rh, proof: proof, hash_fn: hash_fn)
|
||||
}
|
||||
|
||||
test member_5() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let pig = "pig"
|
||||
let bull = "bull"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
let pig =
|
||||
"pig"
|
||||
let bull =
|
||||
"bull"
|
||||
|
||||
let items = [dog, cat, mouse, horse, pig, bull]
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat, mouse, horse, pig, bull]
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let item = pig
|
||||
let rh = root_hash(mt)
|
||||
let item =
|
||||
pig
|
||||
let rh =
|
||||
root_hash(mt)
|
||||
|
||||
expect Some(proof) = get_proof(mt, item, hash_fn)
|
||||
expect Some(proof) =
|
||||
get_proof(mt, item, hash_fn)
|
||||
member(item: item, root_hash: rh, proof: proof, hash_fn: hash_fn)
|
||||
}
|
||||
|
||||
test member_6() {
|
||||
let dog = "dog"
|
||||
let cat = "cat"
|
||||
let mouse = "mouse"
|
||||
let horse = "horse"
|
||||
let pig = "pig"
|
||||
let bull = "bull"
|
||||
let dog =
|
||||
"dog"
|
||||
let cat =
|
||||
"cat"
|
||||
let mouse =
|
||||
"mouse"
|
||||
let horse =
|
||||
"horse"
|
||||
let pig =
|
||||
"pig"
|
||||
let bull =
|
||||
"bull"
|
||||
|
||||
let hash_fn = create_string_item_hash_fn()
|
||||
let hash_fn =
|
||||
create_string_item_hash_fn()
|
||||
|
||||
let items = [dog, cat, mouse, horse, pig, bull]
|
||||
let mt = from_list(items, hash_fn)
|
||||
let items =
|
||||
[dog, cat, mouse, horse, pig, bull]
|
||||
let mt =
|
||||
from_list(items, hash_fn)
|
||||
|
||||
let item = "parrot"
|
||||
let item =
|
||||
"parrot"
|
||||
|
||||
let proof = get_proof(mt, item, hash_fn)
|
||||
let proof =
|
||||
get_proof(mt, item, hash_fn)
|
||||
proof == None
|
||||
}
|
||||
|
||||
fn get_proof_item_value(proof_item: ProofItem) -> Hash<Sha2_256, ByteArray> {
|
||||
when proof_item is {
|
||||
Left(x) -> x
|
||||
Right(y) -> y
|
||||
Left(x) ->
|
||||
x
|
||||
Right(y) ->
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,10 @@ pub fn from_asset(
|
|||
) -> Value {
|
||||
let asset =
|
||||
dict.new()
|
||||
|> dict.insert(asset_name, quantity, bytearray.compare)
|
||||
|> dict.insert(asset_name, quantity, bytearray.compare)
|
||||
dict.new()
|
||||
|> dict.insert(policy_id, asset, bytearray.compare)
|
||||
|> Value
|
||||
|> dict.insert(policy_id, asset, bytearray.compare)
|
||||
|> Value
|
||||
}
|
||||
|
||||
pub fn add(left v0: Value, right v1: Value) -> Value {
|
||||
|
@ -40,7 +40,8 @@ pub fn add(left v0: Value, right v1: Value) -> Value {
|
|||
a0,
|
||||
a1,
|
||||
fn(_, q0, q1) {
|
||||
let q = q0 + q1
|
||||
let q =
|
||||
q0 + q1
|
||||
if q == 0 {
|
||||
None
|
||||
} else {
|
||||
|
@ -58,7 +59,7 @@ pub fn add(left v0: Value, right v1: Value) -> Value {
|
|||
},
|
||||
bytearray.compare,
|
||||
)
|
||||
|> Value
|
||||
|> Value
|
||||
}
|
||||
|
||||
/// Flatten a value as a list of results, possibly discarding some along the way.
|
||||
|
@ -75,8 +76,10 @@ pub fn flatten_with(
|
|||
asset,
|
||||
fn(asset_name, quantity, xs) {
|
||||
when transform(policy_id, asset_name, quantity) is {
|
||||
None -> xs
|
||||
Some(x) -> [x, ..xs]
|
||||
None ->
|
||||
xs
|
||||
Some(x) ->
|
||||
[x, ..xs]
|
||||
}
|
||||
},
|
||||
assets,
|
||||
|
@ -93,9 +96,9 @@ test flatten_with_1() {
|
|||
test flatten_with_2() {
|
||||
let v =
|
||||
zero()
|
||||
|> add(from_asset("a", "1", 14))
|
||||
|> add(from_asset("b", "", 42))
|
||||
|> add(from_asset("a", "2", 42))
|
||||
|> add(from_asset("a", "1", 14))
|
||||
|> add(from_asset("b", "", 42))
|
||||
|> add(from_asset("a", "2", 42))
|
||||
|
||||
flatten_with(
|
||||
v,
|
||||
|
|
|
@ -69,10 +69,13 @@ pub fn validate_pool_deposit(
|
|||
datum: PoolDatum,
|
||||
redeemer: PoolDepositRedeemer,
|
||||
) -> Bool {
|
||||
let validator_address = scripthash_address(#"ff")
|
||||
let validator_address =
|
||||
scripthash_address(#"ff")
|
||||
|
||||
expect Some(pool_output) = get_output(ctx, validator_address)
|
||||
expect Some(pool_input) = get_input(ctx, validator_address)
|
||||
expect Some(pool_output) =
|
||||
get_output(ctx, validator_address)
|
||||
expect Some(pool_input) =
|
||||
get_input(ctx, validator_address)
|
||||
|
||||
True
|
||||
}
|
||||
|
@ -83,28 +86,34 @@ pub fn validate_pool_borrow(
|
|||
datum: PoolDatum,
|
||||
redeemer: PoolBorrowRedeemer,
|
||||
) -> Bool {
|
||||
let validator_address = scripthash_address(#"ff")
|
||||
let validator_address =
|
||||
scripthash_address(#"ff")
|
||||
|
||||
expect Some(pool_output) = get_output(ctx, validator_address)
|
||||
expect Some(pool_input) = get_input(ctx, validator_address)
|
||||
expect Some(pool_output) =
|
||||
get_output(ctx, validator_address)
|
||||
expect Some(pool_input) =
|
||||
get_input(ctx, validator_address)
|
||||
True
|
||||
}
|
||||
|
||||
validator pool_contract {
|
||||
fn(datum: PoolDatum, redeemer: PoolRedeemer, ctx: ScriptContext) {
|
||||
when redeemer.action is {
|
||||
PoolWithdraw(_) -> True
|
||||
PoolWithdraw(_) ->
|
||||
True
|
||||
PoolDeposit(pool_deposit_redeemer) ->
|
||||
when ctx.purpose is {
|
||||
Spend(output_ref) ->
|
||||
validate_pool_deposit(ctx, output_ref, datum, pool_deposit_redeemer)
|
||||
_ -> False
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
PoolBorrow(pool_borrow_redeemer) ->
|
||||
when ctx.purpose is {
|
||||
Spend(output_ref) ->
|
||||
validate_pool_borrow(ctx, output_ref, datum, pool_borrow_redeemer)
|
||||
_ -> False
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,24 +30,34 @@ fn find_outbound_datum(possible_output: Option<Output>) -> Data {
|
|||
when possible_output is {
|
||||
Some(possible_output) ->
|
||||
when possible_output.datum is {
|
||||
InlineDatum(outbound_datum) -> outbound_datum
|
||||
_ -> error @"expected outbound inline datum"
|
||||
InlineDatum(outbound_datum) ->
|
||||
outbound_datum
|
||||
_ ->
|
||||
error @"expected outbound inline datum"
|
||||
}
|
||||
None -> error @"no outbound datum found"
|
||||
None ->
|
||||
error @"no outbound datum found"
|
||||
}
|
||||
}
|
||||
|
||||
fn datum_a_cont() -> OtherDatum {
|
||||
let owner: OwnerInfo = OwnerInfo { pkh: #"", sc: #"" }
|
||||
let have: TokenInfo = TokenInfo { pid: #"", tkn: #"", amt: 100 }
|
||||
let want: TokenInfo = TokenInfo { pid: #"acab", tkn: #"beef", amt: 50 }
|
||||
let info: SwapInfo = SwapInfo { slip: 40 }
|
||||
let owner: OwnerInfo =
|
||||
OwnerInfo { pkh: #"", sc: #"" }
|
||||
let have: TokenInfo =
|
||||
TokenInfo { pid: #"", tkn: #"", amt: 100 }
|
||||
let want: TokenInfo =
|
||||
TokenInfo { pid: #"acab", tkn: #"beef", amt: 50 }
|
||||
let info: SwapInfo =
|
||||
SwapInfo { slip: 40 }
|
||||
OtherDatum { owner, have, want, info }
|
||||
}
|
||||
|
||||
test foo() {
|
||||
let outbound_datum = InlineDatum(datum_a_cont())
|
||||
let outbound_output = Some(Output { datum: outbound_datum })
|
||||
expect outbound_datum: OtherDatum = find_outbound_datum(outbound_output)
|
||||
let outbound_datum =
|
||||
InlineDatum(datum_a_cont())
|
||||
let outbound_output =
|
||||
Some(Output { datum: outbound_datum })
|
||||
expect outbound_datum: OtherDatum =
|
||||
find_outbound_datum(outbound_output)
|
||||
outbound_datum == datum_a_cont()
|
||||
}
|
||||
|
|
|
@ -25,9 +25,12 @@ pub type ProofItem {
|
|||
// Function returning a hash of a given Merkle Tree element
|
||||
pub fn root_hash(self: MerkleTree<a>) -> Hash<Sha2_256, ByteArray> {
|
||||
when self is {
|
||||
Empty -> #""
|
||||
Leaf { hash } -> hash
|
||||
Node { hash, .. } -> hash
|
||||
Empty ->
|
||||
#""
|
||||
Leaf { hash } ->
|
||||
hash
|
||||
Node { hash, .. } ->
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,9 +42,12 @@ pub fn is_equal(left: MerkleTree<a>, right: MerkleTree<a>) -> Bool {
|
|||
/// Function returns a total numbers of leaves in the tree.
|
||||
pub fn size(self: MerkleTree<a>) -> Int {
|
||||
when self is {
|
||||
Empty -> 0
|
||||
Leaf{..} -> 1
|
||||
Node { left, right, .. } -> size(left) + size(right)
|
||||
Empty ->
|
||||
0
|
||||
Leaf{..} ->
|
||||
1
|
||||
Node { left, right, .. } ->
|
||||
size(left) + size(right)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,8 +61,10 @@ fn combine_hash(
|
|||
/// Function that returns whether merkle tree has any elements
|
||||
pub fn is_empty(self: MerkleTree<a>) -> Bool {
|
||||
when self is {
|
||||
Empty -> True
|
||||
_ -> False
|
||||
Empty ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +75,8 @@ fn do_proof(
|
|||
serialise_fn: fn(a) -> ByteArray,
|
||||
) -> Option<Proof> {
|
||||
when self is {
|
||||
Empty -> None
|
||||
Empty ->
|
||||
None
|
||||
Leaf { hash } ->
|
||||
if hash == item_hash {
|
||||
Some(proof)
|
||||
|
@ -75,8 +84,10 @@ fn do_proof(
|
|||
None
|
||||
}
|
||||
Node { left, right, .. } -> {
|
||||
let rh = root_hash(right)
|
||||
let lh = root_hash(left)
|
||||
let rh =
|
||||
root_hash(right)
|
||||
let lh =
|
||||
root_hash(left)
|
||||
let go_left: Option<Proof> =
|
||||
do_proof(
|
||||
left,
|
||||
|
@ -104,7 +115,8 @@ pub fn get_proof(
|
|||
item: a,
|
||||
serialise_fn: fn(a) -> ByteArray,
|
||||
) -> Option<Proof> {
|
||||
let empty: Proof = []
|
||||
let empty: Proof =
|
||||
[]
|
||||
|
||||
do_proof(self, sha2_256(serialise_fn(item)), empty, serialise_fn)
|
||||
}
|
||||
|
@ -115,22 +127,26 @@ fn do_from_list(
|
|||
serialise_fn: fn(a) -> ByteArray,
|
||||
) -> MerkleTree<a> {
|
||||
when items is {
|
||||
[] -> Empty
|
||||
[] ->
|
||||
Empty
|
||||
[item] -> {
|
||||
let hashed_item = sha2_256(serialise_fn(item))
|
||||
let hashed_item =
|
||||
sha2_256(serialise_fn(item))
|
||||
Leaf { hash: hashed_item }
|
||||
}
|
||||
all -> {
|
||||
let cutoff: Int = len / 2
|
||||
let cutoff: Int =
|
||||
len / 2
|
||||
let left =
|
||||
all
|
||||
|> list.take(cutoff)
|
||||
|> do_from_list(cutoff, serialise_fn)
|
||||
|> list.take(cutoff)
|
||||
|> do_from_list(cutoff, serialise_fn)
|
||||
let right =
|
||||
all
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_list(len - cutoff, serialise_fn)
|
||||
let hash = combine_hash(root_hash(left), root_hash(right))
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_list(len - cutoff, serialise_fn)
|
||||
let hash =
|
||||
combine_hash(root_hash(left), root_hash(right))
|
||||
Node { hash, left, right }
|
||||
}
|
||||
}
|
||||
|
@ -151,19 +167,23 @@ fn do_from_hashes_list(
|
|||
len: Int,
|
||||
) -> MerkleTree<a> {
|
||||
when items is {
|
||||
[] -> Empty
|
||||
[hashed_item] -> Leaf { hash: hashed_item }
|
||||
[] ->
|
||||
Empty
|
||||
[hashed_item] ->
|
||||
Leaf { hash: hashed_item }
|
||||
all -> {
|
||||
let cutoff: Int = len / 2
|
||||
let cutoff: Int =
|
||||
len / 2
|
||||
let left =
|
||||
all
|
||||
|> list.take(cutoff)
|
||||
|> do_from_hashes_list(cutoff)
|
||||
|> list.take(cutoff)
|
||||
|> do_from_hashes_list(cutoff)
|
||||
let right =
|
||||
all
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_hashes_list(len - cutoff)
|
||||
let hash = combine_hash(root_hash(left), root_hash(right))
|
||||
|> list.drop(cutoff)
|
||||
|> do_from_hashes_list(len - cutoff)
|
||||
let hash =
|
||||
combine_hash(root_hash(left), root_hash(right))
|
||||
Node { hash, left, right }
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +207,8 @@ pub fn member_from_hash(
|
|||
serialise_fn: fn(a) -> ByteArray,
|
||||
) -> Bool {
|
||||
when proof is {
|
||||
[] -> root_hash == item_hash
|
||||
[] ->
|
||||
root_hash == item_hash
|
||||
[head, ..tail] ->
|
||||
when head is {
|
||||
Left { hash: l } ->
|
||||
|
@ -216,7 +237,8 @@ pub fn member(
|
|||
proof: Proof,
|
||||
serialise_fn: fn(a) -> ByteArray,
|
||||
) -> Bool {
|
||||
let item_hash = sha2_256(serialise_fn(item))
|
||||
let item_hash =
|
||||
sha2_256(serialise_fn(item))
|
||||
member_from_hash(item_hash, root_hash, proof, serialise_fn)
|
||||
}
|
||||
|
||||
|
@ -225,12 +247,16 @@ pub fn member_from_tree(
|
|||
item: a,
|
||||
serialise_fn: fn(a) -> ByteArray,
|
||||
) -> Bool {
|
||||
let proof: Option<Proof> = get_proof(tree, item, serialise_fn)
|
||||
let rh = root_hash(tree)
|
||||
let proof: Option<Proof> =
|
||||
get_proof(tree, item, serialise_fn)
|
||||
let rh =
|
||||
root_hash(tree)
|
||||
|
||||
when proof is {
|
||||
Some(p) -> member(item, rh, p, serialise_fn)
|
||||
None -> False
|
||||
Some(p) ->
|
||||
member(item, rh, p, serialise_fn)
|
||||
None ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,17 +266,25 @@ fn create_string_item_serialise_fn() -> fn(String) -> ByteArray {
|
|||
}
|
||||
|
||||
test from_hashes_list_5() {
|
||||
let dog = @"dog"
|
||||
let cat = @"cat"
|
||||
let mouse = @"mouse"
|
||||
let horse = @"horse"
|
||||
let dog =
|
||||
@"dog"
|
||||
let cat =
|
||||
@"cat"
|
||||
let mouse =
|
||||
@"mouse"
|
||||
let horse =
|
||||
@"horse"
|
||||
|
||||
let serialise_fn = create_string_item_serialise_fn()
|
||||
let serialise_fn =
|
||||
create_string_item_serialise_fn()
|
||||
|
||||
let items = [dog, cat, mouse, horse]
|
||||
let hashes_items = list.map(items, fn(item) { sha2_256(serialise_fn(item)) })
|
||||
let items =
|
||||
[dog, cat, mouse, horse]
|
||||
let hashes_items =
|
||||
list.map(items, fn(item) { sha2_256(serialise_fn(item)) })
|
||||
|
||||
let mt = from_hashes_list(hashes_items)
|
||||
let mt =
|
||||
from_hashes_list(hashes_items)
|
||||
|
||||
let left_node_hash =
|
||||
sha2_256(
|
||||
|
@ -264,7 +298,8 @@ test from_hashes_list_5() {
|
|||
),
|
||||
)
|
||||
|
||||
let root_hash = sha2_256(bytearray.concat(left_node_hash, right_node_hash))
|
||||
let root_hash =
|
||||
sha2_256(bytearray.concat(left_node_hash, right_node_hash))
|
||||
|
||||
Node {
|
||||
hash: root_hash,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
test expect_positive() {
|
||||
let val = 5
|
||||
expect True = val > 0
|
||||
let val =
|
||||
5
|
||||
expect True =
|
||||
val > 0
|
||||
True
|
||||
}
|
||||
|
|
|
@ -4,12 +4,15 @@ use aiken/transaction/value.{add, zero}
|
|||
|
||||
validator staking {
|
||||
fn(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
|
||||
expect Spend(ref) = context.purpose
|
||||
expect Spend(ref) =
|
||||
context.purpose
|
||||
|
||||
expect Some(i) =
|
||||
find(context.transaction.inputs, fn(x) { x.output_reference == ref })
|
||||
let Input { output, .. } = i
|
||||
let staking_addr = output.address
|
||||
let Input { output, .. } =
|
||||
i
|
||||
let staking_addr =
|
||||
output.address
|
||||
|
||||
let v_in =
|
||||
foldr(
|
||||
|
|
|
@ -3,14 +3,16 @@ use aiken/transaction.{Output, ScriptContext}
|
|||
|
||||
validator backtrace {
|
||||
fn(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
|
||||
expect Some(_) = list.find(context.transaction.outputs, fn(_) { True })
|
||||
let _ = find_stuff(context)
|
||||
expect Some(_) =
|
||||
list.find(context.transaction.outputs, fn(_) { True })
|
||||
let _ =
|
||||
find_stuff(context)
|
||||
True
|
||||
}
|
||||
}
|
||||
|
||||
fn find_stuff(context) -> Output {
|
||||
expect Some(stuff) = list.find(context.transaction.outputs, fn(_) { True })
|
||||
expect Some(stuff) =
|
||||
list.find(context.transaction.outputs, fn(_) { True })
|
||||
stuff
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue