Merge pull request #255 from aiken-lang/better-tuples

Better tuples
This commit is contained in:
Matthias Benkort 2023-01-14 20:30:02 +01:00 committed by GitHub
commit bfeb26c9a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 277 additions and 180 deletions

View File

@ -703,7 +703,7 @@ pub enum Pattern<Constructor, Type> {
}, },
/// A name given to a sub-pattern using the `as` keyword. /// A name given to a sub-pattern using the `as` keyword.
/// e.g. `assert #(1, [_, _] as the_list) = x` /// e.g. `assert (1, [_, _] as the_list) = x`
Assign { Assign {
name: String, name: String,
location: Span, location: Span,

View File

@ -396,13 +396,9 @@ impl<'comments> Formatter<'comments> {
.. ..
} => docvec![module, ".", name], } => docvec![module, ".", name],
Constant::Tuple { elements, .. } => "#" Constant::Tuple { elements, .. } => {
.to_doc() wrap_args(false, elements.iter().map(|e| (self.const_expr(e), false))).group()
.append(wrap_args( }
false,
elements.iter().map(|e| (self.const_expr(e), false)),
))
.group(),
} }
} }
@ -480,10 +476,9 @@ impl<'comments> Formatter<'comments> {
.append(break_("", " ").append(self.annotation(retrn)).nest(INDENT)), .append(break_("", " ").append(self.annotation(retrn)).nest(INDENT)),
Annotation::Var { name, .. } => name.to_doc(), Annotation::Var { name, .. } => name.to_doc(),
Annotation::Tuple { elems, .. } => "#".to_doc().append(wrap_args( Annotation::Tuple { elems, .. } => {
false, wrap_args(false, elems.iter().map(|t| (self.annotation(t), false)))
elems.iter().map(|t| (self.annotation(t), false)), }
)),
} }
.group() .group()
} }
@ -768,13 +763,9 @@ impl<'comments> Formatter<'comments> {
.. ..
} => self.record_update(constructor, spread, args), } => self.record_update(constructor, spread, args),
UntypedExpr::Tuple { elems, .. } => "#" UntypedExpr::Tuple { elems, .. } => {
.to_doc() wrap_args(false, elems.iter().map(|e| (self.wrap_expr(e), false))).group()
.append(wrap_args( }
false,
elems.iter().map(|e| (self.wrap_expr(e), false)),
))
.group(),
UntypedExpr::TupleIndex { index, tuple, .. } => { UntypedExpr::TupleIndex { index, tuple, .. } => {
let suffix = Ordinal(*index + 1).suffix().to_doc(); let suffix = Ordinal(*index + 1).suffix().to_doc();
@ -1500,13 +1491,9 @@ impl<'comments> Formatter<'comments> {
Pattern::Discard { name, .. } => name.to_doc(), Pattern::Discard { name, .. } => name.to_doc(),
Pattern::Tuple { elems, .. } => "#" Pattern::Tuple { elems, .. } => {
.to_doc() wrap_args(false, elems.iter().map(|e| (self.pattern(e), false))).group()
.append(wrap_args( }
false,
elems.iter().map(|e| (self.pattern(e), false)),
))
.group(),
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
let elements_document = let elements_document =

View File

@ -346,12 +346,14 @@ fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = P
} }
}); });
let constant_tuple_parser = just(Token::Hash) let constant_tuple_parser = r
.ignore_then( .clone()
r.clone()
.separated_by(just(Token::Comma)) .separated_by(just(Token::Comma))
.at_least(2)
.allow_trailing() .allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen)), .delimited_by(
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
just(Token::RightParen),
) )
.map_with_span(|elements, span| ast::UntypedConstant::Tuple { .map_with_span(|elements, span| ast::UntypedConstant::Tuple {
location: span, location: span,
@ -897,12 +899,14 @@ pub fn expr_parser(
label, label,
}); });
let tuple = just(Token::Hash) let tuple = r
.ignore_then( .clone()
r.clone()
.separated_by(just(Token::Comma)) .separated_by(just(Token::Comma))
.at_least(2)
.allow_trailing() .allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen)), .delimited_by(
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
just(Token::RightParen),
) )
.map_with_span(|elems, span| expr::UntypedExpr::Tuple { .map_with_span(|elems, span| expr::UntypedExpr::Tuple {
location: span, location: span,
@ -1380,13 +1384,11 @@ pub fn type_parser() -> impl Parser<Token, ast::Annotation, Error = ParseError>
} }
}), }),
// Tuple // Tuple
just(Token::Hash)
.ignore_then(
r.clone() r.clone()
.separated_by(just(Token::Comma)) .separated_by(just(Token::Comma))
.at_least(2)
.allow_trailing() .allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen)), .delimited_by(just(Token::LeftParen), just(Token::RightParen))
)
.map_with_span(|elems, span| ast::Annotation::Tuple { .map_with_span(|elems, span| ast::Annotation::Tuple {
location: span, location: span,
elems, elems,
@ -1607,13 +1609,10 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
value, value,
} }
}), }),
just(Token::Hash)
.ignore_then(
r.clone() r.clone()
.separated_by(just(Token::Comma)) .separated_by(just(Token::Comma))
.allow_trailing() .allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen)), .delimited_by(just(Token::LeftParen), just(Token::RightParen))
)
.map_with_span(|elems, span| ast::UntypedPattern::Tuple { .map_with_span(|elems, span| ast::UntypedPattern::Tuple {
location: span, location: span,
elems, elems,

View File

@ -1444,7 +1444,7 @@ fn record_create_unlabeled() {
fn parse_tuple() { fn parse_tuple() {
let code = indoc! {r#" let code = indoc! {r#"
fn foo() { fn foo() {
let tuple = #(1, 2, 3, 4) let tuple = (1, 2, 3, 4)
tuple.1st + tuple.2nd + tuple.3rd + tuple.4th tuple.1st + tuple.2nd + tuple.3rd + tuple.4th
} }
"#}; "#};
@ -1454,27 +1454,27 @@ fn parse_tuple() {
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..86), location: Span::new((), 13..85),
expressions: vec![ expressions: vec![
expr::UntypedExpr::Assignment { expr::UntypedExpr::Assignment {
location: Span::new((), 13..38), location: Span::new((), 13..37),
value: Box::new(expr::UntypedExpr::Tuple { value: Box::new(expr::UntypedExpr::Tuple {
location: Span::new((), 25..38), location: Span::new((), 25..37),
elems: vec![ elems: vec![
expr::UntypedExpr::Int { expr::UntypedExpr::Int {
location: Span::new((), 27..28), location: Span::new((), 26..27),
value: "1".to_string(), value: "1".to_string(),
}, },
expr::UntypedExpr::Int { expr::UntypedExpr::Int {
location: Span::new((), 30..31), location: Span::new((), 29..30),
value: "2".to_string(), value: "2".to_string(),
}, },
expr::UntypedExpr::Int { expr::UntypedExpr::Int {
location: Span::new((), 33..34), location: Span::new((), 32..33),
value: "3".to_string(), value: "3".to_string(),
}, },
expr::UntypedExpr::Int { expr::UntypedExpr::Int {
location: Span::new((), 36..37), location: Span::new((), 35..36),
value: "4".to_string(), value: "4".to_string(),
}, },
], ],
@ -1487,45 +1487,45 @@ fn parse_tuple() {
annotation: None, annotation: None,
}, },
expr::UntypedExpr::BinOp { expr::UntypedExpr::BinOp {
location: Span::new((), 41..86), location: Span::new((), 40..85),
name: ast::BinOp::AddInt, name: ast::BinOp::AddInt,
left: Box::new(expr::UntypedExpr::BinOp { left: Box::new(expr::UntypedExpr::BinOp {
location: Span::new((), 41..74), location: Span::new((), 40..73),
name: ast::BinOp::AddInt, name: ast::BinOp::AddInt,
left: Box::new(expr::UntypedExpr::BinOp { left: Box::new(expr::UntypedExpr::BinOp {
location: Span::new((), 41..62), location: Span::new((), 40..61),
name: ast::BinOp::AddInt, name: ast::BinOp::AddInt,
left: Box::new(expr::UntypedExpr::TupleIndex { left: Box::new(expr::UntypedExpr::TupleIndex {
location: Span::new((), 41..50), location: Span::new((), 40..49),
index: 0, index: 0,
tuple: Box::new(expr::UntypedExpr::Var { tuple: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 41..46), location: Span::new((), 40..45),
name: "tuple".to_string(), name: "tuple".to_string(),
}), }),
}), }),
right: Box::new(expr::UntypedExpr::TupleIndex { right: Box::new(expr::UntypedExpr::TupleIndex {
location: Span::new((), 53..62), location: Span::new((), 52..61),
index: 1, index: 1,
tuple: Box::new(expr::UntypedExpr::Var { tuple: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 53..58), location: Span::new((), 52..57),
name: "tuple".to_string(), name: "tuple".to_string(),
}), }),
}), }),
}), }),
right: Box::new(expr::UntypedExpr::TupleIndex { right: Box::new(expr::UntypedExpr::TupleIndex {
location: Span::new((), 65..74), location: Span::new((), 64..73),
index: 2, index: 2,
tuple: Box::new(expr::UntypedExpr::Var { tuple: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 65..70), location: Span::new((), 64..69),
name: "tuple".to_string(), name: "tuple".to_string(),
}), }),
}), }),
}), }),
right: Box::new(expr::UntypedExpr::TupleIndex { right: Box::new(expr::UntypedExpr::TupleIndex {
location: Span::new((), 77..86), location: Span::new((), 76..85),
index: 3, index: 3,
tuple: Box::new(expr::UntypedExpr::Var { tuple: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 77..82), location: Span::new((), 76..81),
name: "tuple".to_string(), name: "tuple".to_string(),
}), }),
}), }),
@ -1538,11 +1538,77 @@ fn parse_tuple() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
end_position: 87, end_position: 86,
})], })],
) )
} }
#[test]
fn parse_tuple2() {
let code = indoc! {r#"
fn foo() {
let a = foo(14)
(a, 42)
}
"#};
assert_definitions(
code,
vec![ast::UntypedDefinition::Fn(Function {
arguments: vec![],
body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..38),
expressions: vec![
expr::UntypedExpr::Assignment {
location: Span::new((), 13..28),
value: Box::new(expr::UntypedExpr::Call {
arguments: vec![ast::CallArg {
label: None,
location: Span::new((), 25..27),
value: expr::UntypedExpr::Int {
location: Span::new((), 25..27),
value: "14".to_string(),
},
}],
fun: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 21..24),
name: "foo".to_string(),
}),
location: Span::new((), 24..28),
}),
pattern: ast::Pattern::Var {
location: Span::new((), 17..18),
name: "a".to_string(),
},
kind: ast::AssignmentKind::Let,
annotation: None,
},
expr::UntypedExpr::Tuple {
location: Span::new((), 31..38),
elems: vec![
expr::UntypedExpr::Var {
location: Span::new((), 32..33),
name: "a".to_string(),
},
expr::UntypedExpr::Int {
location: Span::new((), 35..37),
value: "42".to_string(),
},
],
},
],
},
doc: None,
location: Span::new((), 0..8),
name: "foo".to_string(),
public: false,
return_annotation: None,
return_type: (),
end_position: 39,
})],
);
}
#[test] #[test]
fn plain_bytearray_literals() { fn plain_bytearray_literals() {
let code = indoc! {r#" let code = indoc! {r#"

View File

@ -75,7 +75,7 @@ impl Printer {
Type::Var { tipo: typ, .. } => self.type_var_doc(&typ.borrow()), Type::Var { tipo: typ, .. } => self.type_var_doc(&typ.borrow()),
Type::Tuple { elems, .. } => self.args_to_aiken_doc(elems).surround("#(", ")"), Type::Tuple { elems, .. } => self.args_to_aiken_doc(elems).surround("(", ")"),
} }
} }

View File

@ -1,3 +1,3 @@
test foo() { test foo() {
#(1, []) == #(1, []) (1, []) == (1, [])
} }

View File

@ -1,9 +1,9 @@
pub fn unzip(xs: List<#(a, b)>) -> #(List<a>, List<b>) { pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
when xs is { when xs is {
[] -> #([], []) [] -> ([], [])
[#(a, b), ..rest] -> { [(a, b), ..rest] -> {
let #(a_tail, b_tail) = unzip(rest) let (a_tail, b_tail) = unzip(rest)
#([a, ..a_tail], [b, ..b_tail]) ([a, ..a_tail], [b, ..b_tail])
} }
} }
} }

View File

@ -1,13 +1,13 @@
pub fn unzip(xs: List<#(a, b)>) -> #(List<a>, List<b>) { pub fn unzip(xs: List<(a, b)>) -> (List<a>, List<b>) {
when xs is { when xs is {
[] -> #([], []) [] -> ([], [])
[#(a, b), ..rest] -> { [(a, b), ..rest] -> {
let #(a_tail, b_tail) = unzip(rest) let (a_tail, b_tail) = unzip(rest)
#([a, ..a_tail], [b, ..b_tail]) ([a, ..a_tail], [b, ..b_tail])
} }
} }
} }
test unzip_1() { test unzip_1() {
unzip([#(1, "a"), #(2, "b")]) == #([1, 2], ["a", "b"]) unzip([(1, "a"), (2, "b")]) == ([1, 2], ["a", "b"])
} }

View File

@ -1,5 +1,5 @@
pub opaque type Map<key, value> { pub opaque type Map<key, value> {
inner: List<#(key, value)>, inner: List<(key, value)>,
} }
pub fn new() { pub fn new() {

View File

@ -16,4 +16,3 @@ test drop_1() {
let x = #[1, 2, 3, 4, 5, 6, 7] let x = #[1, 2, 3, 4, 5, 6, 7]
drop(x, 2) == #[3, 4, 5, 6, 7] drop(x, 2) == #[3, 4, 5, 6, 7]
} }

View File

@ -1,12 +1,12 @@
pub opaque type AssocList<key, value> { pub opaque type AssocList<key, value> {
inner: List<#(key, value)>, inner: List<(key, value)>,
} }
pub fn new() -> AssocList<key, value> { pub fn new() -> AssocList<key, value> {
AssocList { inner: [] } AssocList { inner: [] }
} }
pub fn to_list(m: AssocList<key, value>) -> List<#(key, value)> { pub fn to_list(m: AssocList<key, value>) -> List<(key, value)> {
m.inner m.inner
} }
@ -19,17 +19,17 @@ pub fn insert(
} }
fn do_insert( fn do_insert(
elems: List<#(key, value)>, elems: List<(key, value)>,
k: key, k: key,
v: value, v: value,
) -> List<#(key, value)> { ) -> List<(key, value)> {
when elems is { when elems is {
[] -> [#(k, v)] [] -> [(k, v)]
[#(k2, v2), ..rest] -> [(k2, v2), ..rest] ->
if k == k2 { if k == k2 {
[#(k, v), ..rest] [(k, v), ..rest]
} else { } else {
[#(k2, v2), ..do_insert(rest, k, v)] [(k2, v2), ..do_insert(rest, k, v)]
} }
} }
} }
@ -41,5 +41,5 @@ fn fixture_1() {
} }
test to_list_2() { test to_list_2() {
to_list(fixture_1()) == [#("foo", 42), #("bar", 14)] to_list(fixture_1()) == [("foo", 42), ("bar", 14)]
} }

View File

@ -14,5 +14,5 @@ pub fn map2(
} }
test map2_3() { test map2_3() {
map2(Some(14), Some(42), fn(a, b) { #(a, b) }) == Some(#(14, 42)) map2(Some(14), Some(42), fn(a, b) { (a, b) }) == Some((14, 42))
} }

View File

@ -1,4 +1,4 @@
pub fn foo(_a : a) -> Bool { pub fn foo(_a: a) -> Bool {
True True
} }

View File

@ -1,19 +1,19 @@
pub opaque type AssocList<key, value> { pub opaque type AssocList<key, value> {
inner: List<#(key, value)>, inner: List<(key, value)>,
} }
pub fn new() -> AssocList<key, value> { pub fn new() -> AssocList<key, value> {
AssocList { inner: [] } AssocList { inner: [] }
} }
pub fn from_list(xs: List<#(key, value)>) -> AssocList<key, value> { pub fn from_list(xs: List<(key, value)>) -> AssocList<key, value> {
AssocList { inner: do_from_list(xs) } AssocList { inner: do_from_list(xs) }
} }
fn do_from_list(xs: List<#(key, value)>) -> List<#(key, value)> { fn do_from_list(xs: List<(key, value)>) -> List<(key, value)> {
when xs is { 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)
} }
} }
@ -26,35 +26,35 @@ pub fn insert(
} }
fn do_insert( fn do_insert(
elems: List<#(key, value)>, elems: List<(key, value)>,
k: key, k: key,
v: value, v: value,
) -> List<#(key, value)> { ) -> List<(key, value)> {
when elems is { when elems is {
[] -> [#(k, v)] [] -> [(k, v)]
[#(k2, v2), ..rest] -> [(k2, v2), ..rest] ->
if k == k2 { if k == k2 {
[#(k, v), ..rest] [(k, v), ..rest]
} else { } else {
[#(k2, v2), ..do_insert(rest, k, v)] [(k2, v2), ..do_insert(rest, k, v)]
} }
} }
} }
pub fn union( pub fn union(
left left: AssocList<key, value>, left: AssocList<key, value>,
right right: AssocList<key, value>, right: AssocList<key, value>,
) -> AssocList<key, value> { ) -> AssocList<key, value> {
AssocList { inner: do_union(left.inner, right.inner) } AssocList { inner: do_union(left.inner, right.inner) }
} }
fn do_union( fn do_union(
left: List<#(key, value)>, left: List<(key, value)>,
right: List<#(key, value)>, right: List<(key, value)>,
) -> List<#(key, value)> { ) -> List<(key, value)> {
when left is { when left is {
[] -> right [] -> right
[#(k, v), ..rest] -> do_union(rest, do_insert(right, k, v)) [(k, v), ..rest] -> do_union(rest, do_insert(right, k, v))
} }
} }

View File

@ -1,11 +1,9 @@
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("is non-negative") trace("is non-negative")
False False
} }
} }

View File

@ -1,4 +1,4 @@
test tuple_1() { test tuple_1() {
let coordinates = #(14, 42) let coordinates = (14, 42)
coordinates.1st == 14 && coordinates.2nd == 42 coordinates.1st == 14 && coordinates.2nd == 42
} }

View File

@ -1,10 +1,10 @@
/// An opaque `Dict`. The type is opaque because the module maintains some /// An opaque `Dict`. The type is opaque because the module maintains some
/// invariant, namely: there's only one occurence of a given key in the dictionnary. /// invariant, namely: there's only one occurence of a given key in the dictionnary.
pub opaque type Dict<key, value> { pub opaque type Dict<key, value> {
inner: List<#(ByteArray, value)>, inner: List<(ByteArray, value)>,
} }
pub fn toList(self: Dict<ByteArray, value>){ pub fn toList(self: Dict<ByteArray, value>) {
self.inner self.inner
} }
@ -32,33 +32,33 @@ pub fn union_with(
} }
fn do_union_with( fn do_union_with(
left: List<#(ByteArray, value)>, left: List<(ByteArray, value)>,
right: List<#(ByteArray, value)>, right: List<(ByteArray, value)>,
with: fn(ByteArray, value, value) -> Option<value>, with: fn(ByteArray, value, value) -> Option<value>,
) -> List<#(ByteArray, value)> { ) -> List<(ByteArray, value)> {
when left is { when left is {
[] -> right [] -> right
[#(k, v), ..rest] -> [(k, v), ..rest] ->
do_union_with(rest, do_insert_with(right, k, v, with), with) do_union_with(rest, do_insert_with(right, k, v, with), with)
} }
} }
fn do_insert_with( fn do_insert_with(
self: List<#(ByteArray, value)>, self: List<(ByteArray, value)>,
key k: ByteArray, key k: ByteArray,
value v: value, value v: value,
with: fn(ByteArray, value, value) -> Option<value>, with: fn(ByteArray, value, value) -> Option<value>,
) -> List<#(ByteArray, value)> { ) -> List<(ByteArray, value)> {
when self is { when self is {
[] -> [#(k, v)] [] -> [(k, v)]
[#(k2, v2), ..rest] -> [(k2, v2), ..rest] ->
if k == k2 { if k == k2 {
when with(k, v, v2) is { when with(k, v, v2) is {
Some(combined) -> [#(k, combined), ..rest] Some(combined) -> [(k, combined), ..rest]
None -> rest None -> rest
} }
} else { } else {
[#(k2, v2), ..do_insert_with(rest, k, v, with)] [(k2, v2), ..do_insert_with(rest, k, v, with)]
} }
} }
} }

View File

@ -30,7 +30,8 @@ pub fn add(left v0: Value, right v1: Value) -> Value {
v0, v0,
v1, v1,
fn(_, a0, a1) { fn(_, a0, a1) {
let asset = dict.union_with( let asset =
dict.union_with(
a0, a0,
a1, a1,
fn(_, q0, q1) { fn(_, q0, q1) {

View File

@ -3,11 +3,11 @@
[[requirements]] [[requirements]]
name = "aiken-lang/stdlib" name = "aiken-lang/stdlib"
version = "6b482fa00ec37fe936c93155e8c670f32288a686" version = "1cedbe85b7c7e9c4036d63d45cad4ced27b0d50b"
source = "github" source = "github"
[[packages]] [[packages]]
name = "aiken-lang/stdlib" name = "aiken-lang/stdlib"
version = "6b482fa00ec37fe936c93155e8c670f32288a686" version = "1cedbe85b7c7e9c4036d63d45cad4ced27b0d50b"
requirements = [] requirements = []
source = "github" source = "github"

View File

@ -2,5 +2,5 @@ name = "aiken-lang/acceptance_test_036"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
{ name = "aiken-lang/stdlib", version = "6b482fa00ec37fe936c93155e8c670f32288a686", source = "github" }, { name = "aiken-lang/stdlib", version = "1cedbe85b7c7e9c4036d63d45cad4ced27b0d50b", source = "github" },
] ]

View File

@ -1,60 +1,107 @@
pub type Door {
pub type Door{
locked: Bool, locked: Bool,
hinge_angle: Int hinge_angle: Int,
} }
pub type Car {
pub type Car{
owner: ByteArray, owner: ByteArray,
wheels: Int, wheels: Int,
door: Door, door: Door,
vin: ByteArray, vin: ByteArray,
} }
pub fn update_owner(new_owner: ByteArray, car: Car) {
pub fn update_owner(new_owner: ByteArray, car: Car){ Car { ..car, owner: new_owner }
Car{..car, owner: new_owner}
} }
pub fn update_vin(new_vin: ByteArray, car: Car){ pub fn update_vin(new_vin: ByteArray, car: Car) {
Car{..car, vin: new_vin} Car { ..car, vin: new_vin }
} }
pub fn update_door_angle(new_hinge_angle: Int, car: Car) {
pub fn update_door_angle(new_hinge_angle: Int, car: Car){ Car { ..car, door: Door { ..car.door, hinge_angle: new_hinge_angle } }
Car{..car, door: Door{..car.door, hinge_angle: new_hinge_angle}}
} }
pub fn update_door_locked_and_wheels(new_locked: Bool, new_wheels: Int, car: Car){ pub fn update_door_locked_and_wheels(
Car{..car, door: Door{..car.door, locked: new_locked}, wheels: new_wheels} new_locked: Bool,
new_wheels: Int,
car: Car,
) {
Car {
..car,
door: Door { ..car.door, locked: new_locked },
wheels: new_wheels,
}
} }
test update_owner1(){ test update_owner1() {
let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} let initial_car =
let final_car = Car{owner: #[244, 244, 244, 244], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} Car {
owner: #[],
wheels: 4,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: False, hinge_angle: 45 },
}
let final_car =
Car {
owner: #[244, 244, 244, 244],
wheels: 4,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: False, hinge_angle: 45 },
}
update_owner(#[244, 244, 244, 244], initial_car) == final_car update_owner(#[244, 244, 244, 244], initial_car) == final_car
} }
test update_vin1(){ test update_vin1() {
let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} let initial_car =
let final_car = Car{owner: #[], wheels: 4, vin: #[2,2,2,2,2,2,2,2,2], door: Door{locked: False, hinge_angle: 45}} Car {
update_vin(#[2,2,2,2,2,2,2,2,2], initial_car) == final_car owner: #[],
wheels: 4,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: False, hinge_angle: 45 },
}
let final_car =
Car {
owner: #[],
wheels: 4,
vin: #[2, 2, 2, 2, 2, 2, 2, 2, 2],
door: Door { locked: False, hinge_angle: 45 },
}
update_vin(#[2, 2, 2, 2, 2, 2, 2, 2, 2], initial_car) == final_car
} }
test update_door_angle1(){ test update_door_angle1() {
let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} let initial_car =
let final_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 90}} Car {
owner: #[],
wheels: 4,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: False, hinge_angle: 45 },
}
let final_car =
Car {
owner: #[],
wheels: 4,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: False, hinge_angle: 90 },
}
update_door_angle(90, initial_car) == final_car update_door_angle(90, initial_car) == final_car
} }
test update_door_locked_and_wheels1(){ test update_door_locked_and_wheels1() {
let initial_car = Car{owner: #[], wheels: 4, vin: #[1,1,1,1,1,1,1], door: Door{locked: False, hinge_angle: 45}} let initial_car =
let final_car = Car{owner: #[], wheels: 5, vin: #[1,1,1,1,1,1,1], door: Door{locked: True, hinge_angle: 45}} Car {
owner: #[],
wheels: 4,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: False, hinge_angle: 45 },
}
let final_car =
Car {
owner: #[],
wheels: 5,
vin: #[1, 1, 1, 1, 1, 1, 1],
door: Door { locked: True, hinge_angle: 45 },
}
update_door_locked_and_wheels(True, 5, initial_car) == final_car update_door_locked_and_wheels(True, 5, initial_car) == final_car
} }