1355 lines
30 KiB
Rust
1355 lines
30 KiB
Rust
#[cfg(test)]
|
|
mod test {
|
|
use indoc::indoc;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn test_tuple_literal_declaration() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let (x, y) = (1, 2);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 1
|
|
move r9 2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_declaration_with_underscore() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let (x, _) = (1, 2);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 1
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_assignment() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let x = 0;
|
|
let y = 0;
|
|
(x, y) = (5, 10);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 0
|
|
move r9 0
|
|
move r8 5
|
|
move r9 10
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_with_variables() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let a = 42;
|
|
let b = 99;
|
|
let (x, y) = (a, b);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 42
|
|
move r9 99
|
|
move r10 r8
|
|
move r11 r9
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_three_elements() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let (x, y, z) = (1, 2, 3);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 1
|
|
move r9 2
|
|
move r10 3
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_assignment_with_underscore() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let i = 0;
|
|
let x = 123;
|
|
(i, _) = (456, 789);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 0
|
|
move r9 123
|
|
move r8 456
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_simple() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getPair() {
|
|
return (10, 20);
|
|
};
|
|
let (x, y) = getPair();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getPair:
|
|
push sp
|
|
push ra
|
|
push 10
|
|
push 20
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
jal getPair
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_with_underscore() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getPair() {
|
|
return (5, 15);
|
|
};
|
|
let (x, _) = getPair();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getPair:
|
|
push sp
|
|
push ra
|
|
push 5
|
|
push 15
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
jal getPair
|
|
pop r0
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_three_elements() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getTriple() {
|
|
return (1, 2, 3);
|
|
};
|
|
let (a, b, c) = getTriple();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getTriple:
|
|
push sp
|
|
push ra
|
|
push 1
|
|
push 2
|
|
push 3
|
|
sub r0 sp 5
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 4
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
jal getTriple
|
|
pop r10
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_assignment() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getPair() {
|
|
return (42, 84);
|
|
};
|
|
let i = 1;
|
|
let j = 2;
|
|
(i, j) = getPair();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getPair:
|
|
push sp
|
|
push ra
|
|
push 42
|
|
push 84
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
move r8 1
|
|
move r9 2
|
|
jal getPair
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_mismatch() -> anyhow::Result<()> {
|
|
let errors = compile!(
|
|
result
|
|
r#"
|
|
fn doSomething() {
|
|
return (1, 2, 3);
|
|
};
|
|
let (x, y) = doSomething();
|
|
"#
|
|
);
|
|
|
|
// Should have exactly one error about tuple size mismatch
|
|
assert_eq!(errors.len(), 1);
|
|
|
|
// Check for the specific TupleSizeMismatch error
|
|
match &errors[0] {
|
|
crate::Error::TupleSizeMismatch(expected_size, actual_count, _) => {
|
|
assert_eq!(*expected_size, 3);
|
|
assert_eq!(*actual_count, 2);
|
|
}
|
|
e => panic!("Expected TupleSizeMismatch error, got: {:?}", e),
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_called_by_non_tuple_return() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn doSomething() {
|
|
return (1, 2);
|
|
};
|
|
|
|
fn doSomethingElse() {
|
|
let (x, y) = doSomething();
|
|
return y;
|
|
};
|
|
|
|
let returnedValue = doSomethingElse();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
doSomething:
|
|
push sp
|
|
push ra
|
|
push 1
|
|
push 2
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
doSomethingElse:
|
|
push sp
|
|
push ra
|
|
jal doSomething
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
move r15 r9
|
|
j __internal_L2
|
|
__internal_L2:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
main:
|
|
jal doSomethingElse
|
|
move r8 r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_non_tuple_return_called_by_tuple_return() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getValue() {
|
|
return 42;
|
|
};
|
|
|
|
fn getTuple() {
|
|
let x = getValue();
|
|
return (x, x);
|
|
};
|
|
|
|
let (a, b) = getTuple();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getValue:
|
|
push sp
|
|
push ra
|
|
move r15 42
|
|
j __internal_L1
|
|
__internal_L1:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
getTuple:
|
|
push sp
|
|
push ra
|
|
jal getValue
|
|
move r8 r15
|
|
push r8
|
|
push r8
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L2
|
|
__internal_L2:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
jal getTuple
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_size_mismatch() -> anyhow::Result<()> {
|
|
let errors = compile!(
|
|
result
|
|
r#"
|
|
let (x, y) = (1, 2, 3);
|
|
"#
|
|
);
|
|
|
|
// Should have exactly one error about tuple size mismatch
|
|
assert_eq!(errors.len(), 1);
|
|
assert!(matches!(
|
|
errors[0],
|
|
crate::Error::TupleSizeMismatch(_, _, _)
|
|
));
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_tuple_returns_in_function() -> anyhow::Result<()> {
|
|
// Test multiple return paths in tuple-returning function
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getValue(x) {
|
|
if (x) {
|
|
return (1, 2);
|
|
} else {
|
|
return (3, 4);
|
|
}
|
|
};
|
|
|
|
let (a, b) = getValue(1);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getValue:
|
|
pop r8
|
|
push sp
|
|
push ra
|
|
beqz r8 __internal_L3
|
|
push 1
|
|
push 2
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
j __internal_L2
|
|
__internal_L3:
|
|
push 3
|
|
push 4
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L2:
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
push 1
|
|
jal getValue
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
},
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_with_expression() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn add(x, y) {
|
|
return (x, y);
|
|
};
|
|
|
|
let (a, b) = add(5, 10);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
add:
|
|
pop r8
|
|
pop r9
|
|
push sp
|
|
push ra
|
|
push r9
|
|
push r8
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
push 5
|
|
push 10
|
|
jal add
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_function_tuple_calls() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn inner() {
|
|
return (1, 2);
|
|
};
|
|
|
|
fn outer() {
|
|
let (x, y) = inner();
|
|
return (y, x);
|
|
};
|
|
|
|
let (a, b) = outer();
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
inner:
|
|
push sp
|
|
push ra
|
|
push 1
|
|
push 2
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
outer:
|
|
push sp
|
|
push ra
|
|
jal inner
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
push r9
|
|
push r8
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L2
|
|
__internal_L2:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
jal outer
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_with_constant_expressions() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let (a, b) = (1 + 2, 3 * 4);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 3
|
|
move r9 12
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_with_variable_expressions() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let x = 5;
|
|
let y = 10;
|
|
let (a, b) = (x + 1, y * 2);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 5
|
|
move r9 10
|
|
add r1 r8 1
|
|
move r10 r1
|
|
mul r2 r9 2
|
|
move r11 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_assignment_with_expressions() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let a = 0;
|
|
let b = 0;
|
|
let x = 5;
|
|
(a, b) = (x + 1, x * 2);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 0
|
|
move r9 0
|
|
move r10 5
|
|
add r1 r10 1
|
|
move r8 r1
|
|
mul r2 r10 2
|
|
move r9 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_literal_with_function_calls() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getValue() { return 42; };
|
|
fn getOther() { return 99; };
|
|
|
|
let (a, b) = (getValue(), getOther());
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getValue:
|
|
push sp
|
|
push ra
|
|
move r15 42
|
|
j __internal_L1
|
|
__internal_L1:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
getOther:
|
|
push sp
|
|
push ra
|
|
move r15 99
|
|
j __internal_L2
|
|
__internal_L2:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
main:
|
|
push r8
|
|
jal getValue
|
|
pop r8
|
|
move r1 r15
|
|
move r8 r1
|
|
push r8
|
|
push r9
|
|
jal getOther
|
|
pop r9
|
|
pop r8
|
|
move r2 r15
|
|
move r9 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_with_logical_expressions() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let x = 1;
|
|
let y = 0;
|
|
let (a, b) = (x && y, x || y);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 1
|
|
move r9 0
|
|
and r1 r8 r9
|
|
move r10 r1
|
|
or r2 r8 r9
|
|
move r11 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_with_comparison_expressions() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
let x = 5;
|
|
let y = 10;
|
|
let (a, b) = (x > y, x < y);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
move r8 5
|
|
move r9 10
|
|
sgt r1 r8 r9
|
|
move r10 r1
|
|
slt r2 r8 r9
|
|
move r11 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_with_device_property_access() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
device sensor = "d0";
|
|
device display = "d1";
|
|
|
|
let (temp, pressure) = (sensor.Temperature, sensor.Pressure);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
main:
|
|
l r1 d0 Temperature
|
|
move r8 r1
|
|
l r2 d0 Pressure
|
|
move r9 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_with_device_property_and_function_call() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
device self = "db";
|
|
|
|
fn getY() {
|
|
return 42;
|
|
}
|
|
|
|
let (x, y) = (self.Setting, getY());
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getY:
|
|
push sp
|
|
push ra
|
|
move r15 42
|
|
j __internal_L1
|
|
__internal_L1:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
main:
|
|
l r1 db Setting
|
|
move r8 r1
|
|
push r8
|
|
push r9
|
|
jal getY
|
|
pop r9
|
|
pop r8
|
|
move r2 r15
|
|
move r9 r2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_with_function_call_expressions() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getValue() { return 10; }
|
|
fn getOther() { return 20; }
|
|
|
|
let (a, b) = (getValue() + 5, getOther() * 2);
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getValue:
|
|
push sp
|
|
push ra
|
|
move r15 10
|
|
j __internal_L1
|
|
__internal_L1:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
getOther:
|
|
push sp
|
|
push ra
|
|
move r15 20
|
|
j __internal_L2
|
|
__internal_L2:
|
|
pop ra
|
|
pop sp
|
|
j ra
|
|
main:
|
|
push r8
|
|
jal getValue
|
|
pop r8
|
|
move r1 r15
|
|
add r2 r1 5
|
|
move r8 r2
|
|
push r8
|
|
push r9
|
|
jal getOther
|
|
pop r9
|
|
pop r8
|
|
move r3 r15
|
|
mul r4 r3 2
|
|
move r9 r4
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_with_stack_spillover() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn get8() {
|
|
return (1, 2, 3, 4, 5, 6, 7, 8);
|
|
}
|
|
|
|
let (a, b, c, d, e, f, g, h) = get8();
|
|
let sum = a + h;
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
get8:
|
|
push sp
|
|
push ra
|
|
push 1
|
|
push 2
|
|
push 3
|
|
push 4
|
|
push 5
|
|
push 6
|
|
push 7
|
|
push 8
|
|
sub r0 sp 10
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 9
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
jal get8
|
|
pop r0
|
|
sub r0 sp 0
|
|
put db r0 r0
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop r11
|
|
pop r10
|
|
pop r9
|
|
pop r8
|
|
move sp r15
|
|
sub r0 sp 1
|
|
get r1 db r0
|
|
add r2 r8 r1
|
|
push r2
|
|
sub sp sp 2
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_return_in_loop() -> anyhow::Result<()> {
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn getValues(i) {
|
|
return (i, i * 2);
|
|
};
|
|
|
|
let sum = 0;
|
|
let i = 0;
|
|
loop {
|
|
let (a, b) = getValues(i);
|
|
sum = sum + a + b;
|
|
i = i + 1;
|
|
if (i > 3) {
|
|
break;
|
|
}
|
|
}
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
getValues:
|
|
pop r8
|
|
push sp
|
|
push ra
|
|
push r8
|
|
mul r1 r8 2
|
|
push r1
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
move r8 0
|
|
move r9 0
|
|
__internal_L2:
|
|
push r9
|
|
jal getValues
|
|
pop r11
|
|
pop r10
|
|
move sp r15
|
|
add r1 r8 r10
|
|
add r2 r1 r11
|
|
move r8 r2
|
|
add r3 r9 1
|
|
move r9 r3
|
|
sgt r4 r9 3
|
|
beqz r4 __internal_L4
|
|
j __internal_L3
|
|
__internal_L4:
|
|
j __internal_L2
|
|
__internal_L3:
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple_all_forms_combined() -> anyhow::Result<()> {
|
|
// Test all three tuple forms in one test:
|
|
// 1. Tuple literal declaration: let (x, y) = (1, 2);
|
|
// 2. Tuple literal assignment: (x, y) = (3, 4);
|
|
// 3. Function return tuple: let (a, b) = func();
|
|
let compiled = compile!(
|
|
check
|
|
r#"
|
|
fn swap(x, y) {
|
|
return (y, x);
|
|
};
|
|
|
|
let (a, b) = (10, 20); // Literal declaration
|
|
(a, b) = (30, 40); // Literal assignment
|
|
let (c, d) = swap(a, b); // Function return
|
|
"#
|
|
);
|
|
|
|
assert!(
|
|
compiled.errors.is_empty(),
|
|
"Expected no errors, got: {:?}",
|
|
compiled.errors
|
|
);
|
|
|
|
assert_eq!(
|
|
compiled.output,
|
|
indoc! {
|
|
"
|
|
j main
|
|
swap:
|
|
pop r8
|
|
pop r9
|
|
push sp
|
|
push ra
|
|
push r8
|
|
push r9
|
|
sub r0 sp 4
|
|
get r0 db r0
|
|
move r15 r0
|
|
j __internal_L1
|
|
__internal_L1:
|
|
sub r0 sp 3
|
|
get ra db r0
|
|
j ra
|
|
main:
|
|
move r8 10
|
|
move r9 20
|
|
move r8 30
|
|
move r9 40
|
|
push r8
|
|
push r9
|
|
jal swap
|
|
pop r11
|
|
pop r10
|
|
move sp r15
|
|
"
|
|
}
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
}
|