diff --git a/README.md b/README.md index 60fa28f7..43896184 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ func main() { # own a int32 = 1 - own b int32 = x + own b int32 = a # This is invalid, it would not compile if I uncomment it. # a = 2 diff --git a/src/ast/stmts.rs b/src/ast/stmts.rs index bf16d326..745dce69 100644 --- a/src/ast/stmts.rs +++ b/src/ast/stmts.rs @@ -12,6 +12,7 @@ pub struct VariableDeclaration { pub name: String, pub type_name: Type, pub value: Expr, + pub explicitly_initialized: bool, pub span: Span, } diff --git a/src/compile.rs b/src/compile.rs index 97346a52..5f18554d 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -25,6 +25,14 @@ pub fn compile(rcode: &str, target_dir: &str) -> Result<(), HolyError> { name = "holyprogram" version = "0.0.1" edition = "2024" + +[profile.dev] +opt-level = 0 +panic = "abort" + +[profile.release] +opt-level = 0 +panic = "abort" "#; cargo_file.write_all(cargo_content.as_bytes()).expect(&format!("Compile error: Couldnt write to file `{}`, please check your permissions", cargo_file_path.display())); diff --git a/src/consts.rs b/src/consts.rs index c2ad553e..f569472c 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -6,5 +6,7 @@ pub const RESERVED_KEYWORDS: &[&str] = &[ "func", "own", "const", "infinite", "return", "for", "in", "range", "if", "elif", "else", "true", "false", "int8", "int16", "int32", "int64", "int128", "byte", "uint16", "uint32", "uint64", "uint128", "float64", "usize", "bool", "string", "copy", "format", - "lock", "unlock", "while", "break", "continue", "and", "or", "not" + "lock", "unlock", "while", "break", "continue", "and", "or", "not", + + "_checkedopsf64" ]; diff --git a/src/parser.rs b/src/parser.rs index 24dd207e..80d11293 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -705,7 +705,7 @@ fn parse_stmt_line(line: &str, line_no: usize) -> Result { let value = parse_expr::parse_expr(right, span)?; - return Ok(Stmt::VarDecl(VariableDeclaration { name, type_name: var_type, value: value, span: span })); + return Ok(Stmt::VarDecl(VariableDeclaration { name, type_name: var_type, value: value, explicitly_initialized: true, span: span })); @@ -722,7 +722,7 @@ fn parse_stmt_line(line: &str, line_no: usize) -> Result { let ty = parse_type(parts[1], &span)?; let default_value = ty.get_default_value(span); - return Ok(Stmt::VarDecl(VariableDeclaration { name, type_name: ty, value: default_value, span: span })) + return Ok(Stmt::VarDecl(VariableDeclaration { name, type_name: ty, value: default_value, explicitly_initialized: false, span: span })) } } diff --git a/src/parser/blackbox_tests.rs b/src/parser/blackbox_tests.rs index 4cc32d0c..a34db528 100644 --- a/src/parser/blackbox_tests.rs +++ b/src/parser/blackbox_tests.rs @@ -90,7 +90,7 @@ fn span() -> Span { // all literals (ints, floats, array, strings literals of ints, floats, strings, other arrays, and variable names, and array access and slicing. // Some of these literals are illegal semantically, but syntaxally, should be valid. // -fn get_all_literals_edge_cases() -> [String; 126] { +fn get_all_literals_edge_cases() -> [String; 143] { return [ i8::MIN.to_string(), i8::MAX.to_string(), i16::MIN.to_string(), i16::MAX.to_string(), @@ -109,7 +109,15 @@ fn get_all_literals_edge_cases() -> [String; 126] { "false".to_string(), "true".to_string(), "\"\"".to_string(), "\"h\"".to_string(), "\"hi\"".to_string(), - "\"hi, lmao\"".to_string(), + "\"hi, lmao\"".to_string(), "\"hi ] lmao\"".to_string(), "\"hi [ lmao\"".to_string(), + "\"foo]\"".to_string(), "\"foo[\"".to_string(), + "\"]foo\"".to_string(), "\"[foo\"".to_string(), + "\"]foo]\"".to_string(), "\"[foo[\"".to_string(), + "\"[foo]\"".to_string(), + "\"foo\\\"]\"".to_string(), "\"foo\\\"[\"".to_string(), + "\"\\\"]foo\"".to_string(), "\"\\\"[foo[\"".to_string(), + "\"foo)\"".to_string(), "\"foo(\"".to_string(), + "\")foo\"".to_string(), "\"(foo\"".to_string(), "i".to_string(), "arr".to_string(), "x".to_string(), "y".to_string(), "xyz".to_string(), format!("arr[{}]", i8::MIN.to_string()), format!("arr[{}]", i8::MAX.to_string()), diff --git a/src/parser/blackbox_tests/function_tests.rs b/src/parser/blackbox_tests/function_tests.rs index da4135bf..86405a53 100644 --- a/src/parser/blackbox_tests/function_tests.rs +++ b/src/parser/blackbox_tests/function_tests.rs @@ -150,7 +150,13 @@ mod function_tests { assert!(result.is_err()); let assert_cond = result.unwrap_err().to_string(); - assert!(assert_cond.contains("Unknown type") || assert_cond.contains("Missing opening parentheses for return type")); + println!("wtf? {:?}", assert_cond); + + let assert_cond = assert_cond.contains("Unknown type") || + assert_cond.contains("Missing opening parentheses for return type") + || assert_cond.contains("Invalid parameter"); + + assert!(assert_cond); } } diff --git a/src/parser/blackbox_tests/string_literal_tests.rs b/src/parser/blackbox_tests/string_literal_tests.rs index e758a12e..d4cf2aba 100644 --- a/src/parser/blackbox_tests/string_literal_tests.rs +++ b/src/parser/blackbox_tests/string_literal_tests.rs @@ -41,15 +41,16 @@ mod string_literals_tests { #[test] fn string_literal_with_escaped_quote() { for t in ALL_TYPES_NO_ARR { - let stmts = parse_body(&format!("own x {} = \"say \\\"hi\\\"\"", t)); + let stmts = parse_body(&format!(r#"own x {} = "say \"hi\"""#, t)); assert_eq!(stmts.len(), 1); if let Stmt::VarDecl(v) = &stmts[0] { assert_eq!(v.name, "x"); assert_eq!(v.type_name, t.clone()); + println!("huh {:?}", v.value); if let Expr::StringLiteral { value, .. } = &v.value { - assert_eq!(value, r#"say "hi""#); + assert_eq!(value, r#"say \"hi\""#); } else { panic!(); } } else { panic!("Expected VarDecl"); } } diff --git a/src/parser/helpers.rs b/src/parser/helpers.rs index 9e3680ff..ce428786 100644 --- a/src/parser/helpers.rs +++ b/src/parser/helpers.rs @@ -3,7 +3,156 @@ use super::*; use crate::consts; +/// Gets parenthesis contents. +/// I.e. ( .. EXPRESSIONS .. ) would give Some(EXPRESSIONS) +/// +/// This only gets parenthesis content if the parenthesis extends to the end of the string +/// like, ( .. EXPRESSIONS ..) is ok but ( .. EXPRESSIONS .. ) == EXPRESSION, etc, is not. +/// +/// +pub fn get_parenthesis_contents(s: &str) -> Option<&str> { + if s.len() == 0 { + return None + } + + let matching_close = { + let mut depth = 0usize; + let mut found = None; + let mut in_string = false; + let mut in_escape = false; + for (i, c) in s[1..].char_indices() { + if in_escape { + in_escape = false; + continue; + } + + match c { + '(' => { + if !in_string { + depth += 1 + } + }, + '"' => in_string = !in_string, + '\\' => in_escape = true, + ')' => { + if !in_string { + if depth == 0 { + found = Some(1 + i); + break; + } + depth -= 1; + } + } + _ => {} + } + } + found + }; + + + if let Some(close_pos) = matching_close && close_pos == s.len() - 1 { + let parenthesis_str = &s[1.. s.len() - 1]; + return Some(parenthesis_str) + } + + None +} + + +/// Gets array contents. +/// I.e. [ .. EXPRESSIONS .. ] would give Some(EXPRESSIONS, opening_bracket_position) +/// +/// This only gets array content if the array extends to the end of the string +/// like, [ .. EXPRESSIONS ..] is ok but [ .. EXPRESSIONS .. ] == EXPRESSION, etc, is not. +/// +/// +pub fn get_array_contents(s: &str) -> Option<(&str, usize)> { + let bracket_opening = { + let mut depth = 0usize; + let mut found = None; + let mut in_string = false; + let mut in_escape = false; + for (i, c) in s.char_indices() { + if in_escape { + in_escape = false; + continue; + } + + match c { + ']' => { + if !in_string { + depth += 1 + } + }, + '"' => in_string = !in_string, + '\\' => in_escape = true, + '[' => { + if !in_string { + if depth == 0 { + found = Some(i + 1); + break; + } + depth -= 1; + } + } + _ => {} + } + } + found + }; + + + if let Some(first_bracket) = bracket_opening { + let matching_close = { + let mut depth = 0usize; + let mut found = None; + let mut in_string = false; + let mut in_escape = false; + for (i, c) in s[first_bracket..].char_indices() { + if in_escape { + in_escape = false; + continue; + } + + match c { + '[' => { + if !in_string { + depth += 1 + } + }, + '"' => in_string = !in_string, + '\\' => in_escape = true, + ']' => { + if !in_string { + if depth == 0 { + found = Some(first_bracket + i); + break; + } + depth -= 1; + } + } + _ => {} + } + } + found + }; + + + if let Some(close_pos) = matching_close && close_pos == s.len() - 1 { + let elems_str = &s[first_bracket .. s.len() - 1]; + + return Some((elems_str, first_bracket - 1)) + } + } + + None +} + + +/// Finds binary operators at top level only +/// i.e. "or", "and", "==", "<", ">", etc. +/// pub fn find_top_level_op_any(s: &str) -> Option<(usize, &str)> { fn precedence(op: &str) -> u8 { match op { @@ -25,85 +174,104 @@ pub fn find_top_level_op_any(s: &str) -> Option<(usize, &str)> { let chars: Vec<(usize, char)> = s.char_indices().collect(); let mut depth = 0usize; + let mut in_string = false; + let mut in_escape = false; let mut best: Option<(usize, &str)> = None; let mut best_prec = u8::MAX; let mut i = 0; while i < chars.len() { let (idx, c) = chars[i]; - match c { - '(' | '[' | '{' => depth += 1, - ')' | ']' | '}' => { if depth > 0 { depth -= 1; } } - _ if depth == 0 => { - // Peek next char - let next = chars.get(i + 1).map(|(_, nc)| *nc); - - // Determine operator string at this position - let op_str: Option<&str> = match c { - '=' if next == Some('=') => Some(&s[idx..idx + 2]), - '!' if next == Some('=') => Some(&s[idx..idx + 2]), - '>' if next == Some('=') => Some(&s[idx..idx + 2]), - '<' if next == Some('=') => Some(&s[idx..idx + 2]), - '>' if next == Some('>') => Some(&s[idx..idx + 2]), - '<' if next == Some('<') => Some(&s[idx..idx + 2]), - 'a' if s[idx..].starts_with("and") => { - let before = if i == 0 { None } else { Some(chars[i - 1].1) }; - let after = chars.get(i + 3).map(|(_, ch)| *ch); - - if before.map_or(true, |ch| !is_ident_char(ch)) - && after.map_or(true, |ch| !is_ident_char(ch)) - { - Some(&s[idx..idx + 3]) - } else { - None - } + + if in_escape { + in_escape = false; + } else { + match c { + '"' => in_string = !in_string, + '\\' => in_escape = true, + '(' | '[' | '{' => { + if !in_string { + depth += 1 } - - 'o' if s[idx..].starts_with("or") => { - let before = if i == 0 { None } else { Some(chars[i - 1].1) }; - let after = chars.get(i + 2).map(|(_, ch)| *ch); - - if before.map_or(true, |ch| !is_ident_char(ch)) - && after.map_or(true, |ch| !is_ident_char(ch)) - { - Some(&s[idx..idx + 2]) - } else { - None - } + }, + ')' | ']' | '}' => { + if !in_string { + if depth > 0 { depth -= 1; } } - - '+' | '-' | '*' | '/' | '>' | '<' | '|' | '&' => Some(&s[idx..idx+1]), - _ => None, - }; - - if let Some(op) = op_str { - // Skip unary (negate, logical not,m bitwise not) - if op == "-" || op == "!" || op == "~" { - let prev_non_ws = (0..i).rev() - .map(|j| chars[j].1) - .find(|ch| !ch.is_whitespace()); - match prev_non_ws { - None => { i += 1; continue; } - Some(prev) if "+-*/&|!~=<>(".contains(prev) => { i += 1; continue; } - _ => {} + } + _ if depth == 0 => { + if !in_string { + // Peek next char + let next = chars.get(i + 1).map(|(_, nc)| *nc); + + // Determine operator string at this position + let op_str: Option<&str> = match c { + '=' if next == Some('=') => Some(&s[idx..idx + 2]), + '!' if next == Some('=') => Some(&s[idx..idx + 2]), + '>' if next == Some('=') => Some(&s[idx..idx + 2]), + '<' if next == Some('=') => Some(&s[idx..idx + 2]), + '>' if next == Some('>') => Some(&s[idx..idx + 2]), + '<' if next == Some('<') => Some(&s[idx..idx + 2]), + 'a' if s[idx..].starts_with("and") => { + let before = if i == 0 { None } else { Some(chars[i - 1].1) }; + let after = chars.get(i + 3).map(|(_, ch)| *ch); + + if before.map_or(true, |ch| !is_ident_char(ch)) + && after.map_or(true, |ch| !is_ident_char(ch)) + { + Some(&s[idx..idx + 3]) + } else { + None + } + } + + 'o' if s[idx..].starts_with("or") => { + let before = if i == 0 { None } else { Some(chars[i - 1].1) }; + let after = chars.get(i + 2).map(|(_, ch)| *ch); + + if before.map_or(true, |ch| !is_ident_char(ch)) + && after.map_or(true, |ch| !is_ident_char(ch)) + { + Some(&s[idx..idx + 2]) + } else { + None + } + } + + '+' | '-' | '*' | '/' | '>' | '<' | '|' | '&' => Some(&s[idx..idx+1]), + _ => None, + }; + + if let Some(op) = op_str { + // Skip unary (negate, logical not,m bitwise not) + if op == "-" || op == "!" || op == "~" { + let prev_non_ws = (0..i).rev() + .map(|j| chars[j].1) + .find(|ch| !ch.is_whitespace()); + match prev_non_ws { + None => { i += 1; continue; } + Some(prev) if "+-*/&|!~=<>(".contains(prev) => { i += 1; continue; } + _ => {} + } + } + + let prec = precedence(op); + if prec <= best_prec { + best_prec = prec; + best = Some((idx, op)); + } + + // Skip both chars for two-char operators so we don't + // match the second char again + if op.len() == 2 { + i += 2; + continue; + } } } - - let prec = precedence(op); - if prec <= best_prec { - best_prec = prec; - best = Some((idx, op)); - } - - // Skip both chars for two-char operators so we don't - // match the second char again - if op.len() == 2 { - i += 2; - continue; - } } + _ => {} } - _ => {} } i += 1; } @@ -112,13 +280,12 @@ pub fn find_top_level_op_any(s: &str) -> Option<(usize, &str)> { -/// Split "char"-separated args at top-level only. -/// - respects nested (), [], {} -/// - respects "..." and '...' with backslash escapes -/// - returns slices into `s` (no allocation for substrings beyond the Vec) +/// Split "char"-separated args at top-level only (i.e. ignores nested (), [], {}) +/// - respects backslash escapes +/// pub fn split_char_top_level(split_char: char, s: &str) -> Result, HolyError> { if (split_char != ',') && (split_char != ':') { - panic!("(Compiler bug guard) You are most likely misusing split_char_top_level, we expected char to be one of ':', ',', ' ', but instead we got `{}`", split_char); + panic!("(Compiler bug) You are most likely misusing split_char_top_level, we expected char to be one of ':', ',', ' ', but instead we got `{}`", split_char); } let mut parts = Vec::new(); @@ -218,19 +385,15 @@ pub fn string_strip_outer_quotes_and_unescape(s: &str) -> Result out.push('\r'), Some('t') => out.push('\t'), Some('\\') => out.push('\\'), - Some('"') => out.push('"'), + Some('"') => out.push_str("\\\""), Some('\'') => out.push('\''), Some('0') => out.push('\0'), Some(other) => return Err(HolyError::Parse(format!( "Unknown escape sequence `\\{}`", other ))), - None => return Err(HolyError::Parse( - "Trailing backslash in string".into() - )), + None => return Err(HolyError::Parse(format!("Trailing backslash in string: `{}`", s))), }, - '"' => return Err(HolyError::Parse(format!( - "Unexpected unescaped quote inside string: `{}`", s - ))), + '"' => return Err(HolyError::Parse(format!("Unexpected unescaped quote inside string: `{}`", s))), _ => out.push(c), } } diff --git a/src/parser/helpers_tests.rs b/src/parser/helpers_tests.rs index 48c3c43a..9acc1e44 100644 --- a/src/parser/helpers_tests.rs +++ b/src/parser/helpers_tests.rs @@ -1,7 +1,8 @@ use super::*; use crate::consts; use crate::tests_consts::{ - ALL_TYPES_NO_ARR + ALL_TYPES_NO_ARR, + BIN_OP_KIND_SYMBOLS }; // all literals (ints, floats, array, strings literals of ints, floats, strings, other arrays, and variable names, and array access and slicing. @@ -94,6 +95,235 @@ fn get_all_literals_edge_cases() -> [String; 125] { mod tests { use super::*; + // get_parenthesis_contents + // + mod get_parenthesis_contents { + use super::*; + + #[test] + fn empty() { + assert_eq!( + helpers::get_parenthesis_contents(&""), + None + ); + } + + #[test] + fn empty_parenthesis() { + assert_eq!( + helpers::get_parenthesis_contents(&"()"), + Some("") + ); + } + + #[test] + fn empty_parenthesis_inside_empty_parenthesis() { + assert_eq!( + helpers::get_parenthesis_contents(&"(())"), + Some("()") + ); + } + + + #[test] + fn two_empty_parenthesis() { + assert_eq!( + helpers::get_parenthesis_contents(&"() ()"), + None, + ); + } + + #[test] + fn two_empty_parenthesis_inside_two_empty_parenthesis() { + assert_eq!( + helpers::get_parenthesis_contents(&"(()) (())"), + None, + ); + } + + #[test] + fn two_empty_parenthesis_inside_empty_parenthesis() { + assert_eq!( + helpers::get_parenthesis_contents(&"(() ())"), + Some("() ()") + ); + } + + #[test] + fn parenthesis_full_of_literals_with_splits() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in [',', ':'] { + assert_eq!( + helpers::get_parenthesis_contents(&format!("({}{} {}{} {})", l, s, l, s, l)), + Some(format!("{}{} {}{} {}", l, s, l, s, l).as_str()) + ); + } + } + } + + #[test] + fn two_parenthesis_full_of_literals_with_splits() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in [',', ':'] { + assert_eq!( + helpers::get_parenthesis_contents(&format!("({}{} {}{} {}) ({}{} {}{} {})", l, s, l, s, l, l, s, l, s, l)), + None + ); + } + } + } + + #[test] + fn parenthesis_binop_literals() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in BIN_OP_KIND_SYMBOLS { + assert_eq!( + helpers::get_parenthesis_contents(&format!("({}{} {}{} {})", l, s, l, s, l)), + Some(format!("{}{} {}{} {}", l, s, l, s, l).as_str()) + ); + } + } + } + + #[test] + fn two_parenthesis_binop_literals() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in BIN_OP_KIND_SYMBOLS { + assert_eq!( + helpers::get_parenthesis_contents(&format!("({}{} {}{} {}) ({}{} {}{} {})", l, s, l, s, l, l, s, l, s, l)), + None + ); + } + } + } + } + + + + // get_array_contents + // + mod get_array_contents { + use super::*; + + #[test] + fn empty() { + assert_eq!( + helpers::get_array_contents(&""), + None + ); + } + + #[test] + fn array_literal_empty() { + assert_eq!( + helpers::get_array_contents(&"[]"), + Some(("", 0)) + ); + } + + #[test] + fn array_literal_empty_inside_array_literal() { + assert_eq!( + helpers::get_array_contents(&"[[]]"), + Some(("[]", 0)) + ); + } + + + #[test] + fn two_array_literal_empty_inside_array_literal() { + assert_eq!( + helpers::get_array_contents(&"[[] []]"), + Some(("[] []", 0)) + ); + } + + #[test] + fn two_empty_array_literals() { + assert_eq!( + helpers::get_array_contents(&"[] []"), + None + ); + } + + #[test] + fn array_literal_full_of_literals_with_splits() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in [',', ':'] { + assert_eq!( + helpers::get_array_contents(&format!("[{}{} {}{} {}]", l, s, l, s, l)), + Some((format!("{}{} {}{} {}", l, s, l, s, l).as_str(), 0)) + ); + } + } + } + + #[test] + fn two_array_literal_full_of_literals_with_splits() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in [',', ':'] { + assert_eq!( + helpers::get_array_contents(&format!("[{}{} {}{} {}] [{}{} {}{} {}]", l, s, l, s, l, l, s, l, s, l)), + None + ); + } + } + } + + #[test] + fn array_literal_full_of_binop_literals() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in BIN_OP_KIND_SYMBOLS { + assert_eq!( + helpers::get_array_contents(&format!("[{}{} {}{} {}]", l, s, l, s, l)), + Some((format!("{}{} {}{} {}", l, s, l, s, l).as_str(), 0)) + ); + } + } + } + + #[test] + fn two_array_literal_full_of_binop_literals() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + for s in BIN_OP_KIND_SYMBOLS { + assert_eq!( + helpers::get_parenthesis_contents(&format!("({}{} {}{} {}) ({}{} {}{} {})", l, s, l, s, l, l, s, l, s, l)), + None, + ); + } + } + } + + #[test] + fn array_access() { + let literals = get_all_literals_edge_cases(); + + for l in literals { + assert_eq!( + helpers::get_array_contents(&format!("x[{}]", l)), + Some((format!("{}", l).as_str(), 1)) + ); + } + } + } + + // find_top_level_op_any // mod find_top_level_op_any { @@ -142,7 +372,7 @@ mod tests { #[test] fn left_associativity_picks_rightmost_lowest_precedence() { - // "a+b+c" both '+' have the same precedence; should get the RIGHTMOST one + // "a+b+c" both '+' have the same precedence, should get the right most one let result = helpers::find_top_level_op_any("a+b+c"); assert_eq!(result, Some((3, "+"))); } @@ -486,8 +716,8 @@ mod tests { #[test] fn escape_double_quote_inside() { - // \" inside should produce a literal " - assert_eq!(helpers::string_strip_outer_quotes_and_unescape(r#""a\"b""#).unwrap(), r#"a"b"#); + // \" inside should not be touched + assert_eq!(helpers::string_strip_outer_quotes_and_unescape(r#""a\"b""#).unwrap(), r#"a\"b"#); } #[test] diff --git a/src/parser/parse_expr.rs b/src/parser/parse_expr.rs index f22b0469..fb3c8ab1 100644 --- a/src/parser/parse_expr.rs +++ b/src/parser/parse_expr.rs @@ -29,6 +29,8 @@ pub fn parse_expr(s: &str, span: Span) -> Result { // string_strip_outer_quotes_and_unescape due to fact it errors on invalid strings thinking // its a string, but it could also be an expression concerning strings. so we have to still // manually basic match here. + // so binary operations regarding strings fall through, but if this is truly a string + // literal, we strip and unquote it. // let mut chars = s.char_indices().skip(1); let closing = loop { @@ -64,32 +66,10 @@ pub fn parse_expr(s: &str, span: Span) -> Result { // Parentheses grouping: if the whole expression is wrapped in top-level parentheses, parse inner - if s.starts_with('(') && s.ends_with(')') { - // ensure the closing paren matches the opening at position 0 (top-level wrap) - let mut depth = 0usize; - let mut matched_at_end = false; - for (i, c) in s.char_indices() { - match c { - '(' => depth += 1, - ')' => { - // NOTE: We dont check depth > 0 here because, we already checkk starts_with - // and ends_with, so ) is guaranteed to be > 0 - // - depth -= 1; - if depth == 0 && i == s.len() - 1 { - matched_at_end = true; - } - } - _ => {} - } - if depth == 0 && i < s.len() - 1 { - // top-level closed before end means its not a full wrap - matched_at_end = false; - break; - } - } - if matched_at_end { - let inner = &s[1..s.len() - 1]; + // + + if s.starts_with('(') { + if let Some(inner) = helpers::get_parenthesis_contents(&s) { return parse_expr(inner, span); } } @@ -169,6 +149,7 @@ pub fn parse_expr(s: &str, span: Span) -> Result { if let Some((pos, op)) = helpers::find_top_level_op_any(s) { let left = s[..pos].trim(); let right = s[pos + op.len()..].trim(); + if left.is_empty() { return Err(HolyError::Parse(format!( "Expected expression before '{}' at line {} column {}", @@ -279,41 +260,13 @@ pub fn parse_expr(s: &str, span: Span) -> Result { } - - // special-case: array literal: // e.g. "[1, 2, 3]", "[]", "[1, [2, 3], 4, 5]" // detect pattern: "[ ... ]" // if s.starts_with("[") { - // Find the bracket that actually closes this opening '[', not just the last ']' - let matching_close = { - let mut depth = 0usize; - let mut found = None; - for (i, c) in s[1..].char_indices() { - match c { - '[' => depth += 1, - ']' => { - if depth == 0 { - found = Some(1 + i); - break; - } - depth -= 1; - } - _ => {} - } - } - found - }; - - // Only take the array path if the matching ']' is the very last character. - // If it isn't (e.g. `[1, 2, 3] == [1, 2, 3]`, etc), then we just let it fall through to other expression detections. - // - - if let Some(close_pos) = matching_close && close_pos == s.len() - 1 { - let elems_str = &s[1..s.len() - 1]; - + if let Some((elems_str, _)) = helpers::get_array_contents(&s) { let mut elems: Vec = Vec::new(); if !elems_str.trim().is_empty() { let split_parts = helpers::split_char_top_level(',', elems_str) @@ -338,99 +291,76 @@ pub fn parse_expr(s: &str, span: Span) -> Result { // Array access // e.g. "x[0]", "x[0:1]", etc. - if let Some(first_bracket) = s.find("[") { - // Find the bracket that actually closes this opening '[', not just the last ']' - let matching_close = { - let mut depth = 0usize; - let mut found = None; - for (i, c) in s[first_bracket..].char_indices() { - match c { - '[' => depth += 1, - ']' => { - depth -= 1; - if depth == 0 { - found = Some(first_bracket + i); - break; - } - } - _ => {} - } - } - found - }; - - if let Some(close_pos) = matching_close && close_pos == s.len() - 1 { - let arr_expr = parse_expr(&s[..first_bracket], span)?; - - // like whats inside the a[...] - let inner_str = &s[first_bracket + 1 .. s.len() - 1]; + // + if let Some((inner_str, first_bracket)) = helpers::get_array_contents(&s) { + // The array holder expression + let arr_expr = parse_expr(&s[..first_bracket], span)?; - let indx_parts = helpers::split_char_top_level(':', inner_str) - .map_err(|e| HolyError::Parse(format!("{} (line {} column {})", e.to_string(), span.line, span.column)))?; + let indx_parts = helpers::split_char_top_level(':', inner_str) + .map_err(|e| HolyError::Parse(format!("{} (line {} column {})", e.to_string(), span.line, span.column)))?; + + // If only one part, treat as access to a single element. + if indx_parts.len() == 1 { + let index = parse_expr(indx_parts[0], span)?; - // If only one part, treat as access to a single element. - if indx_parts.len() == 1 { - let index = parse_expr(indx_parts[0], span)?; - - let value = Expr::ArrayAccess { array: Box::new(arr_expr), index: Box::new(index), span }; - - return Ok(value); + let value = Expr::ArrayAccess { array: Box::new(arr_expr), index: Box::new(index), span }; - // Otherwise this is a slicing operation - // We do >= here to print helpful error messages - // - // NOTE TODO: Ensure this doesnt mess with nested expressions within array - // access/slicing. - } else { - if indx_parts.len() != 2 { - return Err(HolyError::Parse(format!( - "Invalid array slicing syntax `{}` ! (line {} column {})", - s, span.line, span.column - ))); - } + return Ok(value); - let start = indx_parts[0].trim(); - let end = indx_parts[indx_parts.len() - 1].trim(); + // Otherwise this is a slicing operation + // We do >= here to print helpful error messages + // + // NOTE TODO: Ensure this doesnt mess with nested expressions within array + // access/slicing. + } else { + if indx_parts.len() != 2 { + return Err(HolyError::Parse(format!( + "Invalid array slicing syntax `{}` ! (line {} column {})", + s, span.line, span.column + ))); + } - if start.is_empty() && end.is_empty() { - return Err(HolyError::Parse(format!( - "Start and end expressions are both missing from array slice expression! (line {} column {})", - span.line, span.column - ))); - } + let start = indx_parts[0].trim(); + let end = indx_parts[indx_parts.len() - 1].trim(); - // i.e. x[:EXPRESSION] - if start.is_empty() { - let end_expr = Box::new(parse_expr(end, span)?); - - return Ok(Expr::ArraySlicing { - array: Box::new(arr_expr), - range: ArraySliceRange::To(end_expr), - span - }) - - // i.e. x[EXPRESSION:] - } else if end.is_empty() { - let start_expr = Box::new(parse_expr(start, span)?); - - return Ok(Expr::ArraySlicing { - array: Box::new(arr_expr), - range: ArraySliceRange::From(start_expr), - span - }) - } else { - // i.e. x[EXPRESSION:EXPRESSION] - let start_expr = Box::new(parse_expr(start, span)?); - let end_expr = Box::new(parse_expr(end, span)?); - - return Ok(Expr::ArraySlicing { - array: Box::new(arr_expr), - range: ArraySliceRange::FromTo(start_expr, end_expr), - span - }) - } + if start.is_empty() && end.is_empty() { + return Err(HolyError::Parse(format!( + "Start and end expressions are both missing from array slice expression! (line {} column {})", + span.line, span.column + ))); + } + // i.e. x[:EXPRESSION] + if start.is_empty() { + let end_expr = Box::new(parse_expr(end, span)?); + + return Ok(Expr::ArraySlicing { + array: Box::new(arr_expr), + range: ArraySliceRange::To(end_expr), + span + }) + + // i.e. x[EXPRESSION:] + } else if end.is_empty() { + let start_expr = Box::new(parse_expr(start, span)?); + + return Ok(Expr::ArraySlicing { + array: Box::new(arr_expr), + range: ArraySliceRange::From(start_expr), + span + }) + } else { + // i.e. x[EXPRESSION:EXPRESSION] + let start_expr = Box::new(parse_expr(start, span)?); + let end_expr = Box::new(parse_expr(end, span)?); + + return Ok(Expr::ArraySlicing { + array: Box::new(arr_expr), + range: ArraySliceRange::FromTo(start_expr, end_expr), + span + }) } + } } diff --git a/src/parser/parse_expr_tests/string_literal_tests.rs b/src/parser/parse_expr_tests/string_literal_tests.rs index 5a2288c5..651f878f 100644 --- a/src/parser/parse_expr_tests/string_literal_tests.rs +++ b/src/parser/parse_expr_tests/string_literal_tests.rs @@ -31,7 +31,7 @@ mod string_literals_tests { #[test] fn test_string_with_escaped_quote() { match parse(r#""say \"hi\"""#).unwrap() { - Expr::StringLiteral { value, .. } => assert_eq!(value, r#"say "hi""#), + Expr::StringLiteral { value, .. } => assert_eq!(value, r#"say \"hi\""#), other => panic!("expected StringLiteral, got {:?}", other), } } diff --git a/src/semantic.rs b/src/semantic.rs index fa3ca01e..a78217c3 100644 --- a/src/semantic.rs +++ b/src/semantic.rs @@ -59,8 +59,18 @@ pub fn check_semantics(ast: &mut AST) -> Result<(), HolyError> { if fun_sigs.insert(f.name.clone(), (param_tys, f.return_type.clone())).is_some() { return Err(HolyError::Semantic(format!("Duplicate function declaration: {}", f.name))); } + + if f.name == "main" && f.return_type.is_some() { + return Err(HolyError::Semantic("function `main` must not return.".to_string())); + } + + if f.name == "main" && f.params.len() != 0 { + return Err(HolyError::Semantic("function `main` must not have any parameters.".to_string())); + } + } - + + // Second pass: check each global statement let mut globals: HashMap = HashMap::new(); for global_stmt in &mut ast.globals { @@ -88,17 +98,17 @@ fn check_function( // Build local symbol table starting with params let mut upstream_var_names: Vec = vec![]; - for p in &func.params { - if locals.contains_key(&p.name) { + for parameter in &func.params { + if locals.contains_key(¶meter.name) { return Err(HolyError::Semantic(format!( - "Cannot use `{}` as function parameter name, because it is already declared globally", // (line {} column {})", - &p.name //, cons.span.line, cons.span.column + "Cannot use `{}` as function parameter name, because it is already declared globally (line {} column {})", + ¶meter.name, parameter.span.line, parameter.span.column ))); } locals.insert( - p.name.clone(), + parameter.name.clone(), BindingInfo { - ty: p.type_name.clone(), + ty: parameter.type_name.clone(), kind: BindingKind::Var { moved: false, @@ -112,7 +122,7 @@ fn check_function( } }); - upstream_var_names.push(p.name.clone()); + upstream_var_names.push(parameter.name.clone()); } check_stmts(func.clone(), &mut func.body, locals, upstream_var_names, fun_sigs, false)?; @@ -329,7 +339,7 @@ fn check_stmts( kind: BindingKind::Var { value: Some(var.value.clone()), moved: false, - locked: false, + locked: var.explicitly_initialized, len: value_len } } diff --git a/src/semantic/blackbox_tests.rs b/src/semantic/blackbox_tests.rs index 7390034b..1d2eb177 100644 --- a/src/semantic/blackbox_tests.rs +++ b/src/semantic/blackbox_tests.rs @@ -512,7 +512,7 @@ fn ast_one(func: Function) -> AST { fn void_func(name: &str, params: Vec, mut body: Vec) -> Function { if body.len() == 0 { // Dummy body because empty branches are not allowed. - body = vec![var_decl("x", Type::Int8, int32_lit(69))]; + body = vec![var_decl(true, "x", Type::Int8, int32_lit(69))]; } Function { @@ -558,11 +558,12 @@ fn const_define_globally(name: &str, ty: Type, value: Expr) -> GlobalStmt { }) } -fn var_decl(name: &str, ty: Type, value: Expr) -> Stmt { +fn var_decl(explicitly_initialized: bool, name: &str, ty: Type, value: Expr) -> Stmt { Stmt::VarDecl(VariableDeclaration { name: name.to_string(), type_name: ty, value, + explicitly_initialized, span: span(), }) } diff --git a/src/semantic/blackbox_tests/array_tests.rs b/src/semantic/blackbox_tests/array_tests.rs index f6233b1d..d90cf778 100644 --- a/src/semantic/blackbox_tests/array_tests.rs +++ b/src/semantic/blackbox_tests/array_tests.rs @@ -21,7 +21,7 @@ mod array_tests { span: span(), }; let body = vec![ - var_decl("x", t.clone(), access), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -44,7 +44,7 @@ mod array_tests { span: span(), }; let body = vec![ - var_decl("x", t.clone(), access), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -68,8 +68,8 @@ mod array_tests { span: span(), }; let body = vec![ - var_decl("e", t.clone(), l.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "e", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -93,8 +93,8 @@ mod array_tests { span: span(), }; let body = vec![ - var_decl("e", t.clone(), l.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "e", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/bin_op_tests.rs b/src/semantic/blackbox_tests/bin_op_tests.rs index 7d9e3190..8a952841 100644 --- a/src/semantic/blackbox_tests/bin_op_tests.rs +++ b/src/semantic/blackbox_tests/bin_op_tests.rs @@ -14,7 +14,7 @@ mod bin_op_tests { right: Box::new(str_lit("world")), span: span(), }; - let body = vec![var_decl("s", Type::String, bin)]; + let body = vec![var_decl(true, "s", Type::String, bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -41,7 +41,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", Type::Bool, bin.clone())]; + let body = vec![var_decl(true, "s", Type::Bool, bin.clone())]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -75,7 +75,7 @@ mod bin_op_tests { right: Box::new(l2.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -98,7 +98,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -126,7 +126,7 @@ mod bin_op_tests { right: Box::new(l2.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -158,7 +158,7 @@ mod bin_op_tests { }; - let body = vec![var_decl("s", Type::Bool, bin)]; + let body = vec![var_decl(true, "s", Type::Bool, bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -182,7 +182,7 @@ mod bin_op_tests { right: Box::new(bv.clone()), span: span(), }; - let body = vec![var_decl("s", Type::Bool, bin)]; + let body = vec![var_decl(true, "s", Type::Bool, bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -207,8 +207,8 @@ mod bin_op_tests { span: span(), }; let body = vec![ - var_decl("a", t.clone(), l.clone()), - var_decl("s", t.clone(), bin) + var_decl(true, "a", t.clone(), l.clone()), + var_decl(true, "s", t.clone(), bin) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -234,7 +234,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -254,7 +254,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -275,7 +275,7 @@ mod bin_op_tests { right: Box::new(bool_lit(bv)), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -299,7 +299,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -326,7 +326,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -349,7 +349,7 @@ mod bin_op_tests { right: Box::new(l.clone()), span: span(), }; - let body = vec![var_decl("s", t.clone(), bin)]; + let body = vec![var_decl(true, "s", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -380,7 +380,7 @@ mod bin_op_tests { op: b.clone(), span: span(), }; - let body = vec![var_decl("x", t.clone(), bin)]; + let body = vec![var_decl(true, "x", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -406,7 +406,7 @@ mod bin_op_tests { op: b.clone(), span: span(), }; - let body = vec![var_decl("x", t.clone(), bin)]; + let body = vec![var_decl(true, "x", t.clone(), bin)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -449,9 +449,9 @@ mod bin_op_tests { }; let body = vec![ - var_decl("x", t1.clone(), l1.clone()), - var_decl("y", t2.clone(), l2.clone()), - var_decl("z", t1.clone(), bin) + var_decl(true, "x", t1.clone(), l1.clone()), + var_decl(true, "y", t2.clone(), l2.clone()), + var_decl(true, "z", t1.clone(), bin) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -487,9 +487,9 @@ mod bin_op_tests { }; let body = vec![ - var_decl("x", t1.clone(), l1.clone()), - var_decl("y", t2.clone(), l2.clone()), - var_decl("z", t2.clone(), bin) + var_decl(true, "x", t1.clone(), l1.clone()), + var_decl(true, "y", t2.clone(), l2.clone()), + var_decl(true, "z", t2.clone(), bin) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/break_stmt_tests.rs b/src/semantic/blackbox_tests/break_stmt_tests.rs index 4534482e..d7e2d4f5 100644 --- a/src/semantic/blackbox_tests/break_stmt_tests.rs +++ b/src/semantic/blackbox_tests/break_stmt_tests.rs @@ -136,7 +136,7 @@ mod break_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -168,7 +168,7 @@ mod break_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -282,7 +282,7 @@ mod break_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -306,7 +306,7 @@ mod break_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -334,7 +334,7 @@ mod break_stmt_tests { let arr_lit = array_lit(vec![], Some(Type::Array(Box::new(t.clone())))); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -377,7 +377,7 @@ mod break_stmt_tests { let arr_lit = array_lit(vec![], Some(Type::Array(Box::new(t.clone())))); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -440,14 +440,14 @@ mod break_stmt_tests { span: span() }), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -468,14 +468,14 @@ mod break_stmt_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -625,7 +625,7 @@ mod break_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -654,7 +654,7 @@ mod break_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), diff --git a/src/semantic/blackbox_tests/const_tests.rs b/src/semantic/blackbox_tests/const_tests.rs index 38961ebd..ce1bd0b0 100644 --- a/src/semantic/blackbox_tests/const_tests.rs +++ b/src/semantic/blackbox_tests/const_tests.rs @@ -295,7 +295,7 @@ mod const_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), const_define_locally("y", t.clone(), unary.clone()) ]; @@ -547,7 +547,7 @@ mod const_tests { }; let body = vec![ - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), const_define_locally("x", t.clone(), access) ]; @@ -579,7 +579,7 @@ mod const_tests { }; let body = vec![ - var_decl("h", Type::Usize, usize_lit(i - 1)), + var_decl(true, "h", Type::Usize, usize_lit(i - 1)), const_define_locally("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), const_define_locally("x", t.clone(), access) ]; @@ -715,7 +715,7 @@ mod const_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let main = void_func("main", vec![], vec![ - var_decl("foo", t.clone(), l.clone()), + var_decl(true, "foo", t.clone(), l.clone()), const_define_locally("foo", t.clone(), l.clone()) ]); diff --git a/src/semantic/blackbox_tests/continue_stmt_tests.rs b/src/semantic/blackbox_tests/continue_stmt_tests.rs index 34f022a5..bd26b3d8 100644 --- a/src/semantic/blackbox_tests/continue_stmt_tests.rs +++ b/src/semantic/blackbox_tests/continue_stmt_tests.rs @@ -140,7 +140,7 @@ mod continue_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -172,7 +172,7 @@ mod continue_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -289,7 +289,7 @@ mod continue_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -311,7 +311,7 @@ mod continue_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), @@ -338,7 +338,7 @@ mod continue_stmt_tests { let arr_lit = array_lit(vec![], Some(Type::Array(Box::new(t.clone())))); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -385,7 +385,7 @@ mod continue_stmt_tests { let arr_lit = array_lit(vec![], Some(Type::Array(Box::new(t.clone())))); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -453,14 +453,14 @@ mod continue_stmt_tests { span: span() }), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -480,14 +480,14 @@ mod continue_stmt_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -632,7 +632,7 @@ mod continue_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -661,7 +661,7 @@ mod continue_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), diff --git a/src/semantic/blackbox_tests/copy_tests.rs b/src/semantic/blackbox_tests/copy_tests.rs index a75755ef..fe54f3e8 100644 --- a/src/semantic/blackbox_tests/copy_tests.rs +++ b/src/semantic/blackbox_tests/copy_tests.rs @@ -17,7 +17,7 @@ mod copy_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let copy_lit = Expr::CopyCall { expr: Box::new(l.clone()), span: span() }; - let body = vec![var_decl("x", t.clone(), copy_lit)]; + let body = vec![var_decl(true, "x", t.clone(), copy_lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -37,7 +37,7 @@ mod copy_tests { for t in ALL_TYPES_NO_ARR { let copy_expr = Expr::CopyCall { expr: Box::new(call_expr.clone()), span: span() }; - let body = vec![var_decl("x", t.clone(), copy_expr)]; + let body = vec![var_decl(true, "x", t.clone(), copy_expr)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -59,7 +59,7 @@ mod copy_tests { let copy_expr = Expr::CopyCall { expr: Box::new(array_expr), span: span() }; - let body = vec![var_decl("x", t.clone(), copy_expr)]; + let body = vec![var_decl(true, "x", t.clone(), copy_expr)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -81,7 +81,7 @@ mod copy_tests { }; let copy_expr = Expr::CopyCall { expr: Box::new(array_expr), span: span() }; - let body = vec![var_decl("x", t.clone(), copy_expr)]; + let body = vec![var_decl(true, "x", t.clone(), copy_expr)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -100,8 +100,8 @@ mod copy_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("a", t.clone(), l.clone()), - var_decl("b", t.clone(), Expr::CopyCall { + var_decl(true, "a", t.clone(), l.clone()), + var_decl(true, "b", t.clone(), Expr::CopyCall { expr: Box::new(Expr::CopyCall { expr: Box::new(var_expr("a")), span: span() }), span: span(), } @@ -138,9 +138,9 @@ mod copy_tests { }; let body = vec![ - var_decl("e", Type::Usize, usize_lit(i2)), - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "e", Type::Usize, usize_lit(i2)), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -173,9 +173,9 @@ mod copy_tests { }; let body = vec![ - var_decl("e", Type::Usize, usize_lit(i2)), - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "e", Type::Usize, usize_lit(i2)), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/dyn_array_access_tests.rs b/src/semantic/blackbox_tests/dyn_array_access_tests.rs index 464a1389..a959d511 100644 --- a/src/semantic/blackbox_tests/dyn_array_access_tests.rs +++ b/src/semantic/blackbox_tests/dyn_array_access_tests.rs @@ -23,8 +23,8 @@ mod dyn_arrays_access_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("x", t.clone(), access), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -50,9 +50,9 @@ mod dyn_arrays_access_tests { }; let body = vec![ - var_decl("e", t.clone(), l.clone()), - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("x", t.clone(), access), + var_decl(true, "e", t.clone(), l.clone()), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -81,8 +81,8 @@ mod dyn_arrays_access_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/dyn_array_slicing_tests.rs b/src/semantic/blackbox_tests/dyn_array_slicing_tests.rs index b0fa8512..4d48c465 100644 --- a/src/semantic/blackbox_tests/dyn_array_slicing_tests.rs +++ b/src/semantic/blackbox_tests/dyn_array_slicing_tests.rs @@ -22,8 +22,8 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("x", t.clone(), access), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -54,8 +54,8 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -84,10 +84,10 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("e", Type::Usize, usize_lit(1)), - var_decl("h", Type::Usize, usize_lit(i2+1)), - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "e", Type::Usize, usize_lit(1)), + var_decl(true, "h", Type::Usize, usize_lit(i2+1)), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -117,10 +117,10 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("e", t.clone(), l.clone()), - var_decl("h", Type::Usize, usize_lit(i2+1)), - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "e", t.clone(), l.clone()), + var_decl(true, "h", Type::Usize, usize_lit(i2+1)), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -146,10 +146,10 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("e", Type::Usize, usize_lit(1)), - var_decl("h", t.clone(), l.clone()), - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "e", Type::Usize, usize_lit(1)), + var_decl(true, "h", t.clone(), l.clone()), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -175,8 +175,8 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -197,8 +197,8 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -221,8 +221,8 @@ mod dyn_arrays_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("s", Type::Array(Box::new(t.clone())), slice), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "s", Type::Array(Box::new(t.clone())), slice), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/dyn_array_tests.rs b/src/semantic/blackbox_tests/dyn_array_tests.rs index a7522b2a..47d37bc5 100644 --- a/src/semantic/blackbox_tests/dyn_array_tests.rs +++ b/src/semantic/blackbox_tests/dyn_array_tests.rs @@ -32,8 +32,8 @@ mod dyn_arrays_tests { span: span(), }; let body = vec![ - var_decl("x", Type::Array(Box::new(t1.clone())), arr_lit.clone()), - var_decl("y", t1.clone(), access), + var_decl(true, "x", Type::Array(Box::new(t1.clone())), arr_lit.clone()), + var_decl(true, "y", t1.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -71,9 +71,9 @@ mod dyn_arrays_tests { span: span(), }; let body = vec![ - var_decl("e", t2.clone(), l2.clone()), - var_decl("x", Type::Array(Box::new(t1.clone())), arr_lit.clone()), - var_decl("y", t1.clone(), access), + var_decl(true, "e", t2.clone(), l2.clone()), + var_decl(true, "x", Type::Array(Box::new(t1.clone())), arr_lit.clone()), + var_decl(true, "y", t1.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -104,7 +104,7 @@ mod dyn_arrays_tests { span: span(), }; let body = vec![ - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -127,7 +127,7 @@ mod dyn_arrays_tests { span: span(), }; let body = vec![ - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/expr_tests.rs b/src/semantic/blackbox_tests/expr_tests.rs index be99e438..763ac92f 100644 --- a/src/semantic/blackbox_tests/expr_tests.rs +++ b/src/semantic/blackbox_tests/expr_tests.rs @@ -21,8 +21,8 @@ mod expr_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")), Stmt::Expr(var_expr("x")) ]; // x not declared let func = void_func("foo", vec![], body); diff --git a/src/semantic/blackbox_tests/fixed_array_access_tests.rs b/src/semantic/blackbox_tests/fixed_array_access_tests.rs index 8722dc5f..76d4dff5 100644 --- a/src/semantic/blackbox_tests/fixed_array_access_tests.rs +++ b/src/semantic/blackbox_tests/fixed_array_access_tests.rs @@ -21,8 +21,8 @@ mod fixed_array_access_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -45,9 +45,9 @@ mod fixed_array_access_tests { span: span(), }; let body = vec![ - var_decl("e", t.clone(), l.clone()), - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(3)), arr_lit.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "e", t.clone(), l.clone()), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(3)), arr_lit.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -75,9 +75,9 @@ mod fixed_array_access_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(3)), arr_lit.clone()), - // var_decl("arr", Type::Array(Box::new(t.clone())), Some(arr_lit)), - var_decl("x", t.clone(), access), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(3)), arr_lit.clone()), + // var_decl(true, "arr", Type::Array(Box::new(t.clone())), Some(arr_lit)), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/fixed_array_slicing_tests.rs b/src/semantic/blackbox_tests/fixed_array_slicing_tests.rs index 9cd67daa..fbc2dc4e 100644 --- a/src/semantic/blackbox_tests/fixed_array_slicing_tests.rs +++ b/src/semantic/blackbox_tests/fixed_array_slicing_tests.rs @@ -22,8 +22,8 @@ mod fixed_array_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(3)), arr_lit.clone()), - var_decl("x", t.clone(), access), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(3)), arr_lit.clone()), + var_decl(true, "x", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -52,8 +52,8 @@ mod fixed_array_slicing_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -82,10 +82,10 @@ mod fixed_array_slicing_tests { span: span(), }; let body = vec![ - var_decl("e", Type::Usize, usize_lit(1)), - var_decl("h", Type::Usize, usize_lit(i2+1)), - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), - var_decl("x", Type::Array(Box::new(t.clone())), access), + var_decl(true, "e", Type::Usize, usize_lit(1)), + var_decl(true, "h", Type::Usize, usize_lit(i2+1)), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "x", Type::Array(Box::new(t.clone())), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -115,10 +115,10 @@ mod fixed_array_slicing_tests { span: span(), }; let body = vec![ - var_decl("e", t.clone(), l.clone()), - var_decl("h", Type::Usize, usize_lit(i2+1)), - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), - var_decl("x", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), access), + var_decl(true, "e", t.clone(), l.clone()), + var_decl(true, "h", Type::Usize, usize_lit(i2+1)), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "x", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -144,10 +144,10 @@ mod fixed_array_slicing_tests { span: span(), }; let body = vec![ - var_decl("e", Type::Usize, usize_lit(1)), - var_decl("h", t.clone(), l.clone()), - var_decl("arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), - var_decl("x", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), access), + var_decl(true, "e", Type::Usize, usize_lit(1)), + var_decl(true, "h", t.clone(), l.clone()), + var_decl(true, "arr", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "x", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/fixed_array_tests.rs b/src/semantic/blackbox_tests/fixed_array_tests.rs index f56cad88..0c1cd117 100644 --- a/src/semantic/blackbox_tests/fixed_array_tests.rs +++ b/src/semantic/blackbox_tests/fixed_array_tests.rs @@ -31,8 +31,8 @@ mod fixed_array_tests { span: span(), }; let body = vec![ - var_decl("x", Type::FixedArray(Box::new(t1.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), - var_decl("y", t1.clone(), access), + var_decl(true, "x", Type::FixedArray(Box::new(t1.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), + var_decl(true, "y", t1.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -71,9 +71,9 @@ mod fixed_array_tests { span: span(), }; let body = vec![ - var_decl("e", t2.clone(), l2.clone()), - var_decl("x", Type::FixedArray(Box::new(t1.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), - var_decl("y", t1.clone(), access), + var_decl(true, "e", t2.clone(), l2.clone()), + var_decl(true, "x", Type::FixedArray(Box::new(t1.clone()), FixedArraySize::Literal(i)), arr_lit.clone()), + var_decl(true, "y", t1.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/for_stmt_tests.rs b/src/semantic/blackbox_tests/for_stmt_tests.rs index 24454eb5..84217c66 100644 --- a/src/semantic/blackbox_tests/for_stmt_tests.rs +++ b/src/semantic/blackbox_tests/for_stmt_tests.rs @@ -16,14 +16,14 @@ mod for_stmt_tests { let arr_lit = array_lit(elements.clone(), Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -48,14 +48,14 @@ mod for_stmt_tests { let arr_lit = array_lit(elements.clone(), Some(t.clone())); let body = vec![ - var_decl("a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit), + var_decl(true, "a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -88,7 +88,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -120,7 +120,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -156,7 +156,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -185,7 +185,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -208,7 +208,7 @@ mod for_stmt_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: Expr::RangeCall{ @@ -220,7 +220,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -246,8 +246,8 @@ mod for_stmt_tests { let arr_lit = array_lit(elements.clone(), Some(t.clone())); let body = vec![ - var_decl("a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit), - var_decl("x", t.clone(), l.clone()), + var_decl(true, "a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -255,7 +255,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -281,8 +281,8 @@ mod for_stmt_tests { let arr_lit = array_lit(elements.clone(), Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), - var_decl("x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -290,7 +290,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -319,7 +319,7 @@ mod for_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -345,7 +345,7 @@ mod for_stmt_tests { let arr_lit = array_lit(elements.clone(), Some(t.clone())); let body = vec![ - var_decl("a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit), + var_decl(true, "a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), @@ -375,7 +375,7 @@ mod for_stmt_tests { let arr_lit = array_lit(elements.clone(), Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), diff --git a/src/semantic/blackbox_tests/format_tests.rs b/src/semantic/blackbox_tests/format_tests.rs index 6e380f32..93698bb5 100644 --- a/src/semantic/blackbox_tests/format_tests.rs +++ b/src/semantic/blackbox_tests/format_tests.rs @@ -15,7 +15,7 @@ mod format_tests { expressions: vec![l.clone()], // plain literals not allowed span: span(), }; - let body = vec![var_decl("s", Type::String, fmt)]; + let body = vec![var_decl(true, "s", Type::String, fmt)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -37,7 +37,7 @@ mod format_tests { expressions: vec![l.clone()], span: span(), }; - let body = vec![var_decl("s", Type::String, fmt)]; + let body = vec![var_decl(true, "s", Type::String, fmt)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let _ = check_semantics(&mut ast); @@ -55,8 +55,8 @@ mod format_tests { span: span(), }; let body = vec![ - var_decl("n", t.clone(), l.clone()), - var_decl("s", Type::String, fmt), + var_decl(true, "n", t.clone(), l.clone()), + var_decl(true, "s", Type::String, fmt), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -79,8 +79,8 @@ mod format_tests { span: span(), }; let body = vec![ - var_decl("n", t.clone(), l.clone()), - var_decl("s", Type::String, fmt), + var_decl(true, "n", t.clone(), l.clone()), + var_decl(true, "s", Type::String, fmt), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -109,8 +109,8 @@ mod format_tests { let body = vec![ - var_decl("n", t.clone(), l.clone()), - var_decl("s", Type::String, fmt), + var_decl(true, "n", t.clone(), l.clone()), + var_decl(true, "s", Type::String, fmt), ]; let func = void_func("foo", vec![], body); diff --git a/src/semantic/blackbox_tests/function_call_tests.rs b/src/semantic/blackbox_tests/function_call_tests.rs index a565156f..21caa6eb 100644 --- a/src/semantic/blackbox_tests/function_call_tests.rs +++ b/src/semantic/blackbox_tests/function_call_tests.rs @@ -66,7 +66,7 @@ mod function_calls_tests { let callee = void_func("bar", vec![param("a", t2.clone())], vec![]); let body = vec![ - var_decl("x", t1.clone(), l.clone()), + var_decl(true, "x", t1.clone(), l.clone()), Stmt::Expr(call_expr("bar", vec![var_expr("x")])) ]; @@ -88,7 +88,7 @@ mod function_calls_tests { return_stmt(vec![l.clone(), l.clone()]) ]); let body = vec![ - var_decl("x", t.clone(), call_expr("bar", vec![])) + var_decl(true, "x", t.clone(), call_expr("bar", vec![])) ]; let caller = void_func("main", vec![], body); let mut ast = AST { functions: vec![callee, caller], globals: vec![] }; @@ -106,7 +106,7 @@ mod function_calls_tests { for t in ALL_TYPES_NO_ARR { let callee = void_func("bar", vec![], vec![]); let body = vec![ - var_decl("x", t.clone(), call_expr("bar", vec![])) + var_decl(true, "x", t.clone(), call_expr("bar", vec![])) ]; let caller = void_func("main", vec![], body); let mut ast = AST { functions: vec![callee, caller], globals: vec![] }; @@ -148,7 +148,7 @@ mod function_calls_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let callee = void_func("bar", vec![param("a", t.clone())], vec![]); let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Expr(call_expr("bar", vec![var_expr("x")])) ]; let caller = void_func("main", vec![], body); diff --git a/src/semantic/blackbox_tests/function_tests.rs b/src/semantic/blackbox_tests/function_tests.rs index 111020da..e26471f5 100644 --- a/src/semantic/blackbox_tests/function_tests.rs +++ b/src/semantic/blackbox_tests/function_tests.rs @@ -7,6 +7,32 @@ use super::*; mod function_tests { use super::*; + #[test] + fn main_func_with_return_type_errors() { + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + for i in 1..100 { + let main = returning_func("main", vec![], vec![t.clone(); i], vec![]); + let mut ast = AST { functions: vec![main], globals: vec![] }; + let result = check_semantics(&mut ast); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("function `main` must not return.")); + } + } + } + + #[test] + fn main_func_with_parameters_errors() { + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + for i in 1..100 { + let main = void_func("main", vec![param("a", t.clone()); i], vec![]); + let mut ast = AST { functions: vec![main], globals: vec![] }; + let result = check_semantics(&mut ast); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("function `main` must not have any parameters")); + } + } + } + #[test] fn function_name_taken_by_function_name_errors() { let f1 = void_func("foo", vec![], vec![]); diff --git a/src/semantic/blackbox_tests/happy_path_tests.rs b/src/semantic/blackbox_tests/happy_path_tests.rs index 1579d533..43e4bcb9 100644 --- a/src/semantic/blackbox_tests/happy_path_tests.rs +++ b/src/semantic/blackbox_tests/happy_path_tests.rs @@ -30,7 +30,7 @@ mod happy_path_tests { ); let main_body = vec![ - var_decl("r", t.clone(), call_expr("add", vec![l.clone(), l.clone()])), + var_decl(true, "r", t.clone(), call_expr("add", vec![l.clone(), l.clone()])), ]; let main = void_func("main", vec![], main_body); diff --git a/src/semantic/blackbox_tests/if_stmt_tests.rs b/src/semantic/blackbox_tests/if_stmt_tests.rs index 1668d842..fdfae0bd 100644 --- a/src/semantic/blackbox_tests/if_stmt_tests.rs +++ b/src/semantic/blackbox_tests/if_stmt_tests.rs @@ -15,7 +15,7 @@ mod if_stmt_tests { let body = vec![ Stmt::If(IfStmt{ condition: nbl.clone(), - if_branch: vec![ var_decl("z", t.clone(), l.clone()) ], + if_branch: vec![ var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: None, span: span(), @@ -43,10 +43,10 @@ mod if_stmt_tests { let body = vec![ Stmt::If(IfStmt{ condition: bl.clone(), - if_branch: vec![ var_decl("z", t.clone(), l.clone()) ], + if_branch: vec![ var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![(nbl.clone(), vec![ // For above reason - var_decl("e", t.clone(), l.clone()), + var_decl(true, "e", t.clone(), l.clone()), ])], else_branch: None, span: span(), @@ -75,7 +75,7 @@ mod if_stmt_tests { let body = vec![ Stmt::If(IfStmt{ condition: bl.clone(), - if_branch: vec![ var_decl("z", t.clone(), l.clone()) ], + if_branch: vec![ var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: None, span: span(), @@ -114,12 +114,12 @@ mod if_stmt_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, - if_branch: vec![ var_decl("z", t.clone(), l.clone()) ], + if_branch: vec![ var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: None, span: span(), @@ -149,13 +149,13 @@ mod if_stmt_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: None, @@ -179,13 +179,13 @@ mod if_stmt_tests { }; let body = vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: None, @@ -223,11 +223,11 @@ mod if_stmt_tests { if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![(elif_condition, vec![ // For above reason - var_decl("e", t.clone(), l.clone()), + var_decl(true, "e", t.clone(), l.clone()), ])], else_branch: None, span: span(), @@ -259,19 +259,19 @@ mod if_stmt_tests { let elif_condition = condition.clone(); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![(elif_condition, vec![ // For above reason - var_decl("e", t.clone(), l.clone()), + var_decl(true, "e", t.clone(), l.clone()), ])], else_branch: None, span: span(), @@ -305,18 +305,18 @@ mod if_stmt_tests { let elif_condition = condition.clone(); let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![(elif_condition, vec![ // For above reason - var_decl("e", t.clone(), l.clone()), + var_decl(true, "e", t.clone(), l.clone()), ])], else_branch: None, span: span(), @@ -343,18 +343,18 @@ mod if_stmt_tests { let elif_condition = condition.clone(); let body = vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![(elif_condition, vec![ // For above reason - var_decl("e", t.clone(), l.clone()), + var_decl(true, "e", t.clone(), l.clone()), ])], else_branch: None, span: span(), @@ -399,12 +399,12 @@ mod if_stmt_tests { if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: Some(vec![ // For above reason - var_decl("q", t.clone(), l.clone()) + var_decl(true, "q", t.clone(), l.clone()) ]), span: span(), }), @@ -432,20 +432,20 @@ mod if_stmt_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: Some(vec![ // For above reason - var_decl("q", t.clone(), l.clone()) + var_decl(true, "q", t.clone(), l.clone()) ]), span: span(), }), @@ -474,18 +474,18 @@ mod if_stmt_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: Some(vec![ // For above reason - var_decl("q", t.clone(), l.clone()) + var_decl(true, "q", t.clone(), l.clone()) ]), span: span(), }), @@ -507,19 +507,19 @@ mod if_stmt_tests { }; let body = vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: condition, if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: Some(vec![ // For above reason - var_decl("q", t.clone(), l.clone()) + var_decl(true, "q", t.clone(), l.clone()) ]), span: span(), }), diff --git a/src/semantic/blackbox_tests/infinite_stmt_tests.rs b/src/semantic/blackbox_tests/infinite_stmt_tests.rs index 31bdc472..9d617cbd 100644 --- a/src/semantic/blackbox_tests/infinite_stmt_tests.rs +++ b/src/semantic/blackbox_tests/infinite_stmt_tests.rs @@ -14,7 +14,7 @@ mod infinite_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), diff --git a/src/semantic/blackbox_tests/int_literals_internal_inference_tests.rs b/src/semantic/blackbox_tests/int_literals_internal_inference_tests.rs index b88a5048..9b230387 100644 --- a/src/semantic/blackbox_tests/int_literals_internal_inference_tests.rs +++ b/src/semantic/blackbox_tests/int_literals_internal_inference_tests.rs @@ -21,7 +21,7 @@ mod int_literal_internal_inference_tests { for l in float64_lits { for t in ALL_INT_TYPES_NO_ARR { - let body = vec![var_decl("x", t.clone(), l.clone())]; + let body = vec![var_decl(true, "x", t.clone(), l.clone())]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -39,7 +39,7 @@ mod int_literal_internal_inference_tests { let literals_signed_ints = get_all_signed_literals_no_arr_no_float(); for l in literals_signed_ints { - let body = vec![var_decl("x", Type::Int8, l)]; + let body = vec![var_decl(true, "x", Type::Int8, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -59,7 +59,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = int16_lit(i); - let body = vec![var_decl("x", Type::Int8, lit)]; + let body = vec![var_decl(true, "x", Type::Int8, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -82,7 +82,7 @@ mod int_literal_internal_inference_tests { let literals_signed_ints = get_all_signed_literals_no_arr_no_float(); for l in literals_signed_ints { - let body = vec![var_decl("x", Type::Int16, l)]; + let body = vec![var_decl(true, "x", Type::Int16, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -101,7 +101,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = int32_lit(i); - let body = vec![var_decl("x", Type::Int16, lit)]; + let body = vec![var_decl(true, "x", Type::Int16, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -123,7 +123,7 @@ mod int_literal_internal_inference_tests { let literals_signed_ints = get_all_signed_literals_no_arr_no_float(); for l in literals_signed_ints { - let body = vec![var_decl("x", Type::Int32, l)]; + let body = vec![var_decl(true, "x", Type::Int32, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -142,7 +142,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = int64_lit(i); - let body = vec![var_decl("x", Type::Int32, lit)]; + let body = vec![var_decl(true, "x", Type::Int32, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -165,7 +165,7 @@ mod int_literal_internal_inference_tests { let literals_signed_ints = get_all_signed_literals_no_arr_no_float(); for l in literals_signed_ints { - let body = vec![var_decl("x", Type::Int64, l)]; + let body = vec![var_decl(true, "x", Type::Int64, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -184,7 +184,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = int128_lit(i); - let body = vec![var_decl("x", Type::Int64, lit)]; + let body = vec![var_decl(true, "x", Type::Int64, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -206,7 +206,7 @@ mod int_literal_internal_inference_tests { let literals_signed_ints = get_all_signed_literals_no_arr_no_float(); for l in literals_signed_ints { - let body = vec![var_decl("x", Type::Int128, l)]; + let body = vec![var_decl(true, "x", Type::Int128, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -224,7 +224,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = uint128_lit(i); - let body = vec![var_decl("x", Type::Int128, lit)]; + let body = vec![var_decl(true, "x", Type::Int128, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -246,7 +246,7 @@ mod int_literal_internal_inference_tests { let literals_unsigned_ints = get_all_unsigned_literals_no_arr(); for l in literals_unsigned_ints { - let body = vec![var_decl("x", Type::Byte, l)]; + let body = vec![var_decl(true, "x", Type::Byte, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -266,7 +266,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = uint16_lit(i); - let body = vec![var_decl("x", Type::Byte, lit)]; + let body = vec![var_decl(true, "x", Type::Byte, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -288,7 +288,7 @@ mod int_literal_internal_inference_tests { let literals_unsigned_ints = get_all_unsigned_literals_no_arr(); for l in literals_unsigned_ints { - let body = vec![var_decl("x", Type::Uint16, l)]; + let body = vec![var_decl(true, "x", Type::Uint16, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -308,7 +308,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = uint32_lit(i); - let body = vec![var_decl("x", Type::Uint16, lit)]; + let body = vec![var_decl(true, "x", Type::Uint16, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -331,7 +331,7 @@ mod int_literal_internal_inference_tests { let literals_unsigned_ints = get_all_unsigned_literals_no_arr(); for l in literals_unsigned_ints { - let body = vec![var_decl("x", Type::Uint32, l)]; + let body = vec![var_decl(true, "x", Type::Uint32, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -351,7 +351,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = uint64_lit(i); - let body = vec![var_decl("x", Type::Uint32, lit)]; + let body = vec![var_decl(true, "x", Type::Uint32, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -374,7 +374,7 @@ mod int_literal_internal_inference_tests { let literals_unsigned_ints = get_all_unsigned_literals_no_arr(); for l in literals_unsigned_ints { - let body = vec![var_decl("x", Type::Uint64, l)]; + let body = vec![var_decl(true, "x", Type::Uint64, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -394,7 +394,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = uint128_lit(i); - let body = vec![var_decl("x", Type::Uint64, lit)]; + let body = vec![var_decl(true, "x", Type::Uint64, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -415,7 +415,7 @@ mod int_literal_internal_inference_tests { let literals_unsigned_ints = get_all_unsigned_literals_no_arr(); for l in literals_unsigned_ints { - let body = vec![var_decl("x", Type::Usize, l)]; + let body = vec![var_decl(true, "x", Type::Usize, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -435,7 +435,7 @@ mod int_literal_internal_inference_tests { for i in edge_cases_numbers { let lit = uint128_lit(i); - let body = vec![var_decl("x", Type::Usize, lit)]; + let body = vec![var_decl(true, "x", Type::Usize, lit)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -456,7 +456,7 @@ mod int_literal_internal_inference_tests { let literals_signed_ints = get_all_signed_literals_no_arr_no_float(); for l in literals_signed_ints { - let body = vec![var_decl("x", Type::Uint128, l)]; + let body = vec![var_decl(true, "x", Type::Uint128, l)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); diff --git a/src/semantic/blackbox_tests/locking_unlocking_tests.rs b/src/semantic/blackbox_tests/locking_unlocking_tests.rs index 356b9b81..c629f3f9 100644 --- a/src/semantic/blackbox_tests/locking_unlocking_tests.rs +++ b/src/semantic/blackbox_tests/locking_unlocking_tests.rs @@ -7,12 +7,12 @@ mod locking_unlocking_tests { use super::*; #[test] - fn lock_var() { + fn lock_non_inited_var() { let literals = get_all_literals(); for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(false, "x", t.clone(), l.clone()), Stmt::Lock(vec![var_expr("x")]), ]; let func = void_func("foo", vec![], body); @@ -195,7 +195,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x")]), Stmt::Unlock(vec![var_expr("x")]), ]; @@ -213,7 +213,7 @@ mod locking_unlocking_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for i in 2..=100 { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Lock(vec![var_expr("x"); i]), ]; let func = void_func("foo", vec![], body); @@ -231,7 +231,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Lock(vec![var_expr("x")]), Stmt::Lock(vec![var_expr("x")]), ]; @@ -249,7 +249,7 @@ mod locking_unlocking_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for i in 2..=100 { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x"); i]), ]; let func = void_func("foo", vec![], body); @@ -267,7 +267,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x")]), Stmt::Unlock(vec![var_expr("x")]), ]; @@ -285,8 +285,7 @@ mod locking_unlocking_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - Stmt::Lock(vec![var_expr("x")]), + var_decl(true, "x", t.clone(), l.clone()), var_assign("x", l.clone()) ]; let func = void_func("foo", vec![], body); @@ -298,12 +297,29 @@ mod locking_unlocking_tests { } #[test] - fn assign_locked_variable_same_literal_errors() { + fn assign_to_unlocked_variable() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + var_decl(true, "x", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("x")]), + var_assign("x", l.clone()) + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + check_semantics(&mut ast).unwrap(); + } + } + + #[test] + fn assign_unlock_then_lock_variable_same_literal_errors() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("x")]), Stmt::Lock(vec![var_expr("x")]), var_assign("x", l.clone()), ]; @@ -317,7 +333,7 @@ mod locking_unlocking_tests { // Same test as above, but re-declartion use a different literal #[test] - fn assign_locked_variable_different_literal_errors() { + fn assign_unlock_then_lock_variable_different_literal_errors() { let literals = get_all_literals_no_arr(); let literals_scattered = get_all_literals_no_arr_scattered_order(); @@ -327,7 +343,8 @@ mod locking_unlocking_tests { .zip(literals_scattered.iter()) { let body = vec![ - var_decl("x", t.clone(), l1.clone()), + var_decl(true, "x", t.clone(), l1.clone()), + Stmt::Unlock(vec![var_expr("x")]), Stmt::Lock(vec![var_expr("x")]), var_assign("x", l2.clone()), ]; @@ -337,8 +354,9 @@ mod locking_unlocking_tests { assert!(result.is_err()); let assert_cond = result.unwrap_err().to_string(); - let assert_cond = assert_cond.contains("is locked") | - assert_cond.contains("Type mismatch assigning to"); + let assert_cond = assert_cond.contains("Type mismatch assigning to") | + assert_cond.contains("is locked"); + assert!(assert_cond); } @@ -350,7 +368,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![l.clone()]), ]; let func = void_func("foo", vec![], body); @@ -367,8 +385,7 @@ mod locking_unlocking_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - Stmt::Lock(vec![var_expr("x")]), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x")]), var_assign("x", l.clone()), ]; @@ -389,8 +406,7 @@ mod locking_unlocking_tests { .zip(literals_scattered.iter()) { let body = vec![ - var_decl("x", t.clone(), l1.clone()), - Stmt::Lock(vec![var_expr("x")]), + var_decl(true, "x", t.clone(), l1.clone()), Stmt::Unlock(vec![var_expr("x")]), var_assign("x", l2.clone()), ]; @@ -410,8 +426,7 @@ mod locking_unlocking_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - Stmt::Lock(vec![var_expr("x")]), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x")]), var_assign("x", l.clone()) ]; @@ -470,7 +485,7 @@ mod locking_unlocking_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "i".to_string(), @@ -495,7 +510,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: bool_lit(false), branch: vec![ @@ -518,7 +533,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Infinite(InfiniteStmt{ branch: vec![ Stmt::Unlock(vec![var_expr("x")]), @@ -542,8 +557,8 @@ mod locking_unlocking_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "i".to_string(), @@ -563,15 +578,15 @@ mod locking_unlocking_tests { } #[test] - fn lock_unlock_lock_unlock_variable() { + fn unlock_lock_unlock_lock_variable() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - Stmt::Lock(vec![var_expr("x")]), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x")]), Stmt::Lock(vec![var_expr("x")]), Stmt::Unlock(vec![var_expr("x")]), + Stmt::Lock(vec![var_expr("x")]), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -585,7 +600,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Lock(vec![l.clone()]), ]; let func = void_func("foo", vec![], body); @@ -597,11 +612,11 @@ mod locking_unlocking_tests { } #[test] - fn unlock_unlocked_variable_errors() { + fn unlock_uninitied_variable_errors() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(false, "x", t.clone(), l.clone()), Stmt::Unlock(vec![var_expr("x")]), ]; let func = void_func("foo", vec![], body); @@ -612,15 +627,16 @@ mod locking_unlocking_tests { } } - // overshadowing is not allowed at all in holylang + // overshadowing is not allowed at all in holylang, this just ensures that unlocking doesnt + // somehow break this rule. #[test] - fn shadowing_variable_locked_errors() { + fn shadowing_unlocked_variable_errors() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - Stmt::Lock(vec![var_expr("x")]), - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("x")]), + var_decl(true, "x", t.clone(), l.clone()), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -679,7 +695,7 @@ mod locking_unlocking_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "i".to_string(), @@ -704,7 +720,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: bool_lit(false), branch: vec![ @@ -727,7 +743,7 @@ mod locking_unlocking_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Infinite(InfiniteStmt{ branch: vec![ Stmt::Lock(vec![var_expr("x")]), @@ -751,8 +767,8 @@ mod locking_unlocking_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "i".to_string(), @@ -786,10 +802,8 @@ mod locking_unlocking_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), - - Stmt::Lock(vec![var_expr("a")]), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(false, "b", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -817,10 +831,8 @@ mod locking_unlocking_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), - - Stmt::Lock(vec![var_expr("b")]), + var_decl(false, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -846,8 +858,8 @@ mod locking_unlocking_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(false, "a", t1.clone(), l1.clone()), + var_decl(false, "b", t2.clone(), l2.clone()), Stmt::Lock(vec![var_expr("a"), var_expr("b")]), diff --git a/src/semantic/blackbox_tests/multi_return_tests.rs b/src/semantic/blackbox_tests/multi_return_tests.rs index 702a169a..0ddb4cd5 100644 --- a/src/semantic/blackbox_tests/multi_return_tests.rs +++ b/src/semantic/blackbox_tests/multi_return_tests.rs @@ -6,8 +6,10 @@ mod multi_return_tests { // return statement with multiple values (aka multi-return) // with multi-assignments + // + // variable declarations are initialized impliclity though. #[test] - fn multi_return_assign() { + fn multi_return_assign_uninited() { // func pair() (t1, t2,) { return l1, l2 } // func main() { // own a t1 @@ -28,8 +30,8 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(false, "a", t1.clone(), l1.clone()), + var_decl(false, "b", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -68,6 +70,85 @@ mod multi_return_tests { } } + // return statement with multiple values (aka multi-return) + // with multi-assignments + // + // variable declarations are initialized expliclity though. + #[test] + fn multi_return_assign_inited() { + // func pair() (t1, t2,) { return l1, l2 } + // func main() { + // own a t1 + // own b t2 + // a, b = pair() + // } + + let literals = get_all_literals_no_arr(); + let literals_scattered = get_all_literals_no_arr_scattered_order(); + + for (((l1, t1), l2), t2) in literals.iter() + .zip(ALL_TYPES_NO_ARR.iter()) + .zip(literals_scattered.iter()) + .zip(ALL_TYPES_NO_ARR_SCATTERED) + { + let pair_body = vec![return_stmt(vec![l1.clone(), l2.clone()])]; + let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); + + let body = vec![ + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), + + Stmt::VarAssignMulti(MultiAssignment{ + names: vec!["a".to_string(), "b".to_string()], + value: call_expr("pair", vec![]), + span: span() + }) + ]; + let main = void_func("main", vec![], body); + + let mut ast = AST { functions: vec![pair, main] , globals: vec![] }; + check_semantics(&mut ast).unwrap(); + + assert_eq!(ast.functions.len(), 2); + assert_eq!(ast.functions[0].body.len(), 1); + assert_eq!(ast.functions[1].body.len(), 4); + assert_eq!(ast.globals.len(), 0); + + + if let Stmt::VarDecl(v) = &ast.functions[1].body[0] { + assert_eq!(v.name, "a"); + assert_eq!(v.type_name, t1.clone()); + assert_eq!(v.value, l1.clone()); + } else { panic!("Expected VarDecl") } + + + if let Stmt::VarDecl(v) = &ast.functions[1].body[1] { + assert_eq!(v.name, "b"); + assert_eq!(v.type_name, t2.clone()); + assert_eq!(v.value, l2.clone()); + } else { panic!("Expected VarDecl") } + + if let Stmt::Unlock(vec) = &ast.functions[1].body[2] { + assert_eq!(vec.len(), 2); + } else { panic!("Expected Lock stmt") } + + if let Stmt::VarAssignMulti(ma) = &ast.functions[1].body[3] { + assert_eq!(ma.names.len(), 2, "Expected 2 variable names"); + assert_eq!(ma.names[0], "a"); + assert_eq!(ma.names[1], "b"); + + if let Expr::Call { name, .. } = &ma.value { + assert_eq!(name, "pair"); + } else { panic!("Expected Call expression, instead got {:?}", ma.value) } + + } else { panic!("Expected VarAssignMulti") } + } + } + + + #[test] fn multi_return_assign_first_var_is_const_errors() { let literals = get_all_literals_no_arr(); @@ -83,7 +164,7 @@ mod multi_return_tests { let body = vec![ const_define_locally("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -115,8 +196,10 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), const_define_locally("b", t2.clone(), l2.clone()), + + Stmt::Unlock(vec![var_expr("a")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -168,11 +251,106 @@ mod multi_return_tests { } + #[test] + fn test_multi_return_assign_to_uninited_vars_type_mismatch_errors() { + let literals = get_all_literals_no_arr(); + let literals_scattered = get_all_literals_no_arr_scattered_order(); + + // a is mismatch, b is correct + for (((l1, t1), l2), t2) in literals.iter() + .zip(ALL_TYPES_NO_ARR.iter()) + .zip(literals_scattered.iter()) + .zip(ALL_TYPES_NO_ARR_SCATTERED) + { + let pair_body = vec![return_stmt(vec![l1.clone(), l1.clone()])]; + let pair = returning_func("pair", vec![], vec![t1.clone(), t1.clone()], pair_body); + + let body = vec![ + var_decl(false, "a", t2.clone(), l2.clone()), + var_decl(false, "b", t1.clone(), l1.clone()), + + Stmt::VarAssignMulti(MultiAssignment{ + names: vec!["a".to_string(), "b".to_string()], + value: call_expr("pair", vec![]), + span: span() + }) + ]; + let main = void_func("main", vec![], body); + + let mut ast = AST { functions: vec![pair, main] , globals: vec![] }; + let result = check_semantics(&mut ast); + + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("Type mismatch for variable `a`")); + } + + // now b is mismatched while a is correct + + for (((l1, t1), l2), t2) in literals.iter() + .zip(ALL_TYPES_NO_ARR.iter()) + .zip(literals_scattered.iter()) + .zip(ALL_TYPES_NO_ARR_SCATTERED) + { + let pair_body = vec![return_stmt(vec![l1.clone(), l1.clone()])]; + let pair = returning_func("pair", vec![], vec![t1.clone(), t1.clone()], pair_body); + + let body = vec![ + var_decl(false, "a", t1.clone(), l1.clone()), + var_decl(false, "b", t2.clone(), l2.clone()), + + Stmt::VarAssignMulti(MultiAssignment{ + names: vec!["a".to_string(), "b".to_string()], + value: call_expr("pair", vec![]), + span: span() + }) + ]; + let main = void_func("main", vec![], body); + + let mut ast = AST { functions: vec![pair, main], globals: vec![] }; + let result = check_semantics(&mut ast); + + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("Type mismatch for variable `b`")); + + } + + + + // Both mismatched + for (((l1, t1), l2), t2) in literals.iter() + .zip(ALL_TYPES_NO_ARR.iter()) + .zip(literals_scattered.iter()) + .zip(ALL_TYPES_NO_ARR_SCATTERED) + { + let pair_body = vec![return_stmt(vec![l1.clone(), l1.clone()])]; + let pair = returning_func("pair", vec![], vec![t1.clone(), t1.clone()], pair_body); + + let body = vec![ + var_decl(false, "a", t2.clone(), l2.clone()), + var_decl(false, "b", t2.clone(), l2.clone()), + + Stmt::VarAssignMulti(MultiAssignment{ + names: vec!["a".to_string(), "b".to_string()], + value: call_expr("pair", vec![]), + span: span() + }) + ]; + let main = void_func("main", vec![], body); + + let mut ast = AST { functions: vec![pair, main], globals: vec![] }; + let result = check_semantics(&mut ast); + + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("Type mismatch for variable `a`")); + // assert!(result.unwrap_err().to_string().contains("Type mismatch for variable `b`")); + + } + } #[test] - fn test_multi_return_assign_type_mismatch_errors() { + fn test_multi_return_assign_to_inited_vars_type_mismatch_errors() { let literals = get_all_literals_no_arr(); let literals_scattered = get_all_literals_no_arr_scattered_order(); @@ -186,8 +364,9 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t1.clone()], pair_body); let body = vec![ - var_decl("a", t2.clone(), l2.clone()), - var_decl("b", t1.clone(), l1.clone()), + var_decl(true, "a", t2.clone(), l2.clone()), + var_decl(true, "b", t1.clone(), l1.clone()), + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -215,8 +394,10 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t1.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -246,8 +427,10 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t1.clone()], pair_body); let body = vec![ - var_decl("a", t2.clone(), l2.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t2.clone(), l2.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -283,8 +466,8 @@ mod multi_return_tests { let pair = void_func("pair", vec![], vec![]); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string()], @@ -319,7 +502,8 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + Stmt::Unlock(vec![var_expr("a")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -347,7 +531,7 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("b", t1.clone(), l1.clone()), + var_decl(true, "b", t1.clone(), l1.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -394,7 +578,7 @@ mod multi_return_tests { #[test] - fn test_multi_assign_multi_return_not_func_call_errors() { + fn test_multi_assign_on_inited_multi_return_not_func_call_errors() { let literals = get_all_literals_no_arr(); let literals_scattered = get_all_literals_no_arr_scattered_order(); @@ -408,10 +592,43 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), + + Stmt::VarAssignMulti(MultiAssignment{ + names: vec!["a".to_string(), "b".to_string()], + value: l1.clone(), + span: span() + }) + ]; + let main = void_func("main", vec![], body); + + let mut ast = AST { functions: vec![pair, main], globals: vec![] }; + let result = check_semantics(&mut ast); + + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("Multi-assignment requires only a single function call on the right-hand side")); + } + } - Stmt::Lock(vec![var_expr("a")]), + #[test] + fn test_multi_assign_on_uninitied_multi_return_not_func_call_errors() { + let literals = get_all_literals_no_arr(); + let literals_scattered = get_all_literals_no_arr_scattered_order(); + + + for (((l1, t1), l2), t2) in literals.iter() + .zip(ALL_TYPES_NO_ARR.iter()) + .zip(literals_scattered.iter()) + .zip(ALL_TYPES_NO_ARR_SCATTERED) + { + let pair_body = vec![return_stmt(vec![l1.clone(), l2.clone()])]; + let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); + + let body = vec![ + var_decl(false, "a", t1.clone(), l1.clone()), + var_decl(false, "b", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -447,7 +664,7 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string()], @@ -477,9 +694,9 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), - var_decl("c", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + var_decl(true, "c", t2.clone(), l2.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string(), "c".to_string()], @@ -562,9 +779,9 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), - Stmt::Lock(vec![var_expr("a")]), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + Stmt::Unlock(vec![var_expr("b")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -593,9 +810,9 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), - Stmt::Lock(vec![var_expr("b")]), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + Stmt::Unlock(vec![var_expr("a")]), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -629,9 +846,8 @@ mod multi_return_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t1.clone(), l1.clone()), - Stmt::Lock(vec![var_expr("a"), var_expr("b")]), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t1.clone(), l1.clone()), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -657,7 +873,7 @@ mod multi_return_tests { let literals = get_all_literals_no_arr(); let literals_scattered = get_all_literals_no_arr_scattered_order(); - // `a` is a `main` argument, aka it is already declared + // `a` is a `foo` argument, aka it is already declared for (((l1, t1), l2), t2) in literals.iter() .zip(ALL_TYPES_NO_ARR.iter()) .zip(literals_scattered.iter()) @@ -673,9 +889,9 @@ mod multi_return_tests { let body = vec![ Stmt::VarDeclMulti(vars, call_expr("pair", vec![])) ]; - let main = void_func("main", vec![param("a", t1.clone())], body); + let foo = void_func("foo", vec![param("a", t1.clone())], body); - let mut ast = AST { functions: vec![pair, main], globals: vec![] }; + let mut ast = AST { functions: vec![pair, foo], globals: vec![] }; let result = check_semantics(&mut ast); assert!(result.is_err()); @@ -699,9 +915,9 @@ mod multi_return_tests { let body = vec![ Stmt::VarDeclMulti(vars, call_expr("pair", vec![])) ]; - let main = void_func("main", vec![param("b", t2.clone())], body); + let foo = void_func("foo", vec![param("b", t2.clone())], body); - let mut ast = AST { functions: vec![pair, main], globals: vec![] }; + let mut ast = AST { functions: vec![pair, foo], globals: vec![] }; let result = check_semantics(&mut ast); assert!(result.is_err()); @@ -715,7 +931,7 @@ mod multi_return_tests { let literals = get_all_literals_no_arr(); let literals_scattered = get_all_literals_no_arr_scattered_order(); - // `a` is a `main` argument, aka it is already declared + // `a` is a `foo` argument, aka it is already declared for (((l1, t1), l2), t2) in literals.iter() .zip(ALL_TYPES_NO_ARR.iter()) .zip(literals_scattered.iter()) @@ -731,9 +947,9 @@ mod multi_return_tests { let body = vec![ Stmt::VarDeclMulti(vars, call_expr("pair", vec![])) ]; - let main = void_func("main", vec![param("a", t1.clone()), param("b", t2.clone())], body); + let foo = void_func("foo", vec![param("a", t1.clone()), param("b", t2.clone())], body); - let mut ast = AST { functions: vec![pair, main], globals: vec![] }; + let mut ast = AST { functions: vec![pair, foo], globals: vec![] }; let result = check_semantics(&mut ast); assert!(result.is_err()); diff --git a/src/semantic/blackbox_tests/ownership_tests.rs b/src/semantic/blackbox_tests/ownership_tests.rs index 122dadb1..877fed39 100644 --- a/src/semantic/blackbox_tests/ownership_tests.rs +++ b/src/semantic/blackbox_tests/ownership_tests.rs @@ -16,7 +16,7 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let callee = void_func("bar", vec![param("a", t.clone())], vec![]); let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Expr(call_expr("bar", vec![var_expr("x")])) ]; let caller = void_func("main", vec![], body); @@ -74,9 +74,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let callee = void_func("bar", vec![param("a", t.clone())], vec![]); let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Expr(call_expr("bar", vec![var_expr("x")])), - var_decl("y", t.clone(), var_expr("x")), + var_decl(true, "y", t.clone(), var_expr("x")), ]; let caller = void_func("main", vec![], body); let mut ast = AST { functions: vec![callee, caller] , globals: vec![] }; @@ -94,8 +94,8 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -133,8 +133,8 @@ mod ownership_tests { Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ - var_decl("y", t.clone(), var_expr("x")), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "h", t.clone(), var_expr("x")) ], elif_branches: vec![], else_branch: None, @@ -190,12 +190,12 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], elif_branches: vec![], else_branch: None, @@ -244,13 +244,13 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ - var_decl("y", t.clone(), var_expr("x")), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "h", t.clone(), var_expr("x")) ], elif_branches: vec![], else_branch: None, @@ -276,19 +276,19 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], elif_branches: vec![], else_branch: None, span: span(), }), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "h", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); @@ -311,17 +311,17 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ // dummy - var_decl("z", t.clone(), l.clone()) + var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: Some(vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ]), span: span(), }) @@ -375,18 +375,18 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ // dummy - var_decl("z", t.clone(), l.clone()) + var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: Some(vec![ - var_decl("y", t.clone(), var_expr("x")), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "h", t.clone(), var_expr("x")) ]), span: span(), }), @@ -410,22 +410,22 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ // dummy - var_decl("z", t.clone(), l.clone()) + var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: Some(vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ]), span: span(), }), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "h", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); @@ -449,16 +449,16 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ // dummy - var_decl("z", t.clone(), l.clone()) + var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![ (bl.clone(), vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ]) ], else_branch: None, span: span(), @@ -512,17 +512,17 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ // dummy - var_decl("z", t.clone(), l.clone()) + var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![ (bl.clone(), vec![ - var_decl("y", t.clone(), var_expr("x")), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "h", t.clone(), var_expr("x")) ]) ], else_branch: None, span: span(), @@ -547,22 +547,22 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ // dummy - var_decl("z", t.clone(), l.clone()) + var_decl(true, "z", t.clone(), l.clone()) ], elif_branches: vec![ (bl.clone(), vec![ - var_decl("y", t.clone(), var_expr("x")), + var_decl(true, "y", t.clone(), var_expr("x")), ]) ], else_branch: None, span: span(), }), - var_decl("h", t.clone(), var_expr("x")) + var_decl(true, "h", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); @@ -587,9 +587,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")), - var_decl("z", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "z", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -608,8 +608,8 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ const_define_locally("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")), - var_decl("z", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "z", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -646,8 +646,8 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("y", t.clone(), var_expr("x")), - var_decl("z", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "z", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = AST { functions: vec![func], globals: vec![ const_define_globally("x", t.clone(), l.clone()) ]}; @@ -692,9 +692,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("a", t.clone(), l.clone()), - var_decl("b", t.clone(), var_expr("a")), - var_decl("c", t.clone(), var_expr("a")), + var_decl(true, "a", t.clone(), l.clone()), + var_decl(true, "b", t.clone(), var_expr("a")), + var_decl(true, "c", t.clone(), var_expr("a")), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -714,9 +714,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("a", t.clone(), l.clone()), - var_decl("b", t.clone(), var_expr("a")), - var_decl("c", t.clone(), var_expr("a")), + var_decl(true, "a", t.clone(), l.clone()), + var_decl(true, "b", t.clone(), var_expr("a")), + var_decl(true, "c", t.clone(), var_expr("a")), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -727,13 +727,56 @@ mod ownership_tests { } #[test] - fn varassign_moves_var() { + fn inited_vars_assign_moves_var() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("y")]), + var_assign("y", var_expr("x")) + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + check_semantics(&mut ast).unwrap(); + + assert_eq!(ast.functions.len(), 1); + assert_eq!(ast.functions[0].body.len(), 4); + assert_eq!(ast.globals.len(), 0); + + if let Stmt::VarDecl(v) = &ast.functions[0].body[0] { + assert_eq!(v.name, "x"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, l.clone()); + } else { panic!("expected VarDecl, got {:?}", ast); } + + if let Stmt::VarDecl(v) = &ast.functions[0].body[1] { + assert_eq!(v.name, "y"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, l.clone()); + } else { panic!("expected VarDecl, got {:?}", ast); } + + if let Stmt::Unlock(vec) = &ast.functions[0].body[2] { + assert_eq!(vec.len(), 1); + } else { panic!("expected Unlock, got {:?}", ast); } + + if let Stmt::VarAssign(va) = &ast.functions[0].body[3] { + assert_eq!(va.name, "y"); + assert_eq!(va.value, var_expr("x")); + } else { panic!("expected VarAssign, got {:?}", ast); } + + } + } + + #[test] + fn uninited_vars_assign_moves_var() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + var_decl(false, "x", t.clone(), l.clone()), + var_decl(false, "y", t.clone(), l.clone()), var_assign("y", var_expr("x")) ]; let func = void_func("foo", vec![], body); @@ -765,15 +808,66 @@ mod ownership_tests { } #[test] - fn varassign_does_not_move_local_const() { + fn inited_var_assign_does_not_move_local_const() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ const_define_locally("x", t.clone(), l.clone()), - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("y")]), var_assign("y", var_expr("x")), - var_decl("z", t.clone(), var_expr("x")) + var_decl(true, "z", t.clone(), var_expr("x")) + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + check_semantics(&mut ast).unwrap(); + + assert_eq!(ast.globals.len(), 0); + assert_eq!(ast.functions.len(), 1); + assert_eq!(ast.functions[0].body.len(), 5); + + if let Stmt::Const(c) = &ast.functions[0].body[0] { + assert_eq!(c.name, "x"); + assert_eq!(c.type_name, t.clone()); + assert_eq!(c.value, l.clone()); + } else { panic!("expected Const, got {:?}", ast); } + + if let Stmt::VarDecl(v) = &ast.functions[0].body[1] { + assert_eq!(v.name, "y"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, l.clone()); + } else { panic!("expected VarDecl, got {:?}", ast); } + + if let Stmt::Unlock(vec) = &ast.functions[0].body[2] { + assert_eq!(vec.len(), 1); + } else { panic!("expected Unlock, got {:?}", ast); } + + if let Stmt::VarAssign(va) = &ast.functions[0].body[3] { + assert_eq!(va.name, "y"); + assert_eq!(va.value, var_expr("x")); + } else { panic!("expected VarAssign, got {:?}", ast); } + + + if let Stmt::VarDecl(v) = &ast.functions[0].body[4] { + assert_eq!(v.name, "z"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, var_expr("x")); + } else { panic!("expected VarDecl, got {:?}", ast); } + + } + } + + #[test] + fn uninited_var_assign_does_not_move_local_const() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + const_define_locally("x", t.clone(), l.clone()), + var_decl(false, "y", t.clone(), l.clone()), + var_assign("y", var_expr("x")), + var_decl(false, "z", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -811,14 +905,65 @@ mod ownership_tests { } #[test] - fn varassign_does_not_move_global_const() { + fn inited_var_assign_does_not_move_global_const() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("y")]), var_assign("y", var_expr("x")), - var_decl("z", t.clone(), var_expr("x")) + var_decl(true, "z", t.clone(), var_expr("x")) + ]; + let func = void_func("foo", vec![], body); + let mut ast = AST { functions: vec![func], globals: vec![ const_define_globally("x", t.clone(), l.clone()) ]}; + check_semantics(&mut ast).unwrap(); + + assert_eq!(ast.globals.len(), 1); + assert_eq!(ast.functions.len(), 1); + assert_eq!(ast.functions[0].body.len(), 4); + + if let GlobalStmt::Const(c) = &ast.globals[0] { + assert_eq!(c.name, "x"); + assert_eq!(c.type_name, t.clone()); + assert_eq!(c.value, l.clone()); + } else { panic!("expected Const, got {:?}", ast); } + + if let Stmt::VarDecl(v) = &ast.functions[0].body[0] { + assert_eq!(v.name, "y"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, l.clone()); + } else { panic!("expected VarDecl, got {:?}", ast); } + + if let Stmt::Unlock(vec) = &ast.functions[0].body[1] { + assert_eq!(vec.len(), 1); + } else { panic!("expected Unlock, got {:?}", ast); } + + + + if let Stmt::VarAssign(va) = &ast.functions[0].body[2] { + assert_eq!(va.name, "y"); + assert_eq!(va.value, var_expr("x")); + } else { panic!("expected VarAssign, got {:?}", ast); } + + if let Stmt::VarDecl(v) = &ast.functions[0].body[3] { + assert_eq!(v.name, "z"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, var_expr("x")); + } else { panic!("expected VarDecl, got {:?}", ast); } + + } + } + + #[test] + fn uninited_var_assign_does_not_move_global_const() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + var_decl(false, "y", t.clone(), l.clone()), + var_assign("y", var_expr("x")), + var_decl(false, "z", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = AST { functions: vec![func], globals: vec![ const_define_globally("x", t.clone(), l.clone()) ]}; @@ -855,6 +1000,8 @@ mod ownership_tests { } + + #[test] fn copy_call_allows_reuse() { // own a T = EXPRESSION @@ -865,9 +1012,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let copy_a = Expr::CopyCall { expr: Box::new(var_expr("a")), span: span() }; let body = vec![ - var_decl("a", t.clone(), l.clone()), - var_decl("b", t.clone(), copy_a), - var_decl("c", t.clone(), var_expr("a")), + var_decl(true, "a", t.clone(), l.clone()), + var_decl(true, "b", t.clone(), copy_a), + var_decl(true, "c", t.clone(), var_expr("a")), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -886,9 +1033,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let bar = void_func("bar", vec![param("p", t.clone())], vec![]); let body = vec![ - var_decl("a", t.clone(), l.clone()), + var_decl(true, "a", t.clone(), l.clone()), Stmt::Expr(call_expr("bar", vec![var_expr("a")])), - var_decl("b", t.clone(), var_expr("a")), + var_decl(true, "b", t.clone(), var_expr("a")), ]; let caller = void_func("main", vec![], body); let mut ast = AST { functions: vec![bar, caller], globals: vec![]}; @@ -911,8 +1058,8 @@ mod ownership_tests { Stmt::While(WhileStmt{ condition: bl.clone(), branch: vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -955,8 +1102,8 @@ mod ownership_tests { let body = vec![ Stmt::Infinite(InfiniteStmt{ branch: vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -995,13 +1142,13 @@ mod ownership_tests { let arr_lit = array_lit(vec![], Some(Type::Array(Box::new(t.clone())))); let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "e".to_string(), value: var_expr("a"), branch: vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -1049,13 +1196,13 @@ mod ownership_tests { for i in 0usize..=1000usize { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "e".to_string(), value: Expr::RangeCall{ start: Box::new(usize_lit(0)), end: Box::new(usize_lit(i)), span: span()}, branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -1078,20 +1225,20 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], elif_branches: vec![], else_branch: Some(vec![ - var_decl("h", t.clone(), l.clone()) + var_decl(true, "h", t.clone(), l.clone()) ]), span: span(), }), - var_decl("q", t.clone(), var_expr("x")) + var_decl(true, "q", t.clone(), var_expr("x")) ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -1115,8 +1262,8 @@ mod ownership_tests { Stmt::If(IfStmt{ condition: bl.clone(), if_branch: vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ], elif_branches: vec![], else_branch: None, @@ -1167,12 +1314,12 @@ mod ownership_tests { condition: bl.clone(), if_branch: vec![ // Dummy - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: Some(vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ]), span: span(), }), @@ -1223,12 +1370,12 @@ mod ownership_tests { condition: bl.clone(), if_branch: vec![ // Dummy - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![ (bl.clone(), vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")) ]), ], else_branch: None, @@ -1282,11 +1429,11 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { for bl in &boolean_conditions { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: bl.clone(), branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -1308,10 +1455,10 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Infinite(InfiniteStmt{ branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -1333,13 +1480,13 @@ mod ownership_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "e".to_string(), value: var_expr("a"), branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -1362,13 +1509,13 @@ mod ownership_tests { for i in 0usize..=1000usize { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), Stmt::For(ForStmt{ holder_name: "e".to_string(), value: Expr::RangeCall{ start: Box::new(usize_lit(0)), end: Box::new(usize_lit(i)), span: span()}, branch: vec![ - var_decl("y", t.clone(), var_expr("x")) + var_decl(true, "y", t.clone(), var_expr("x")) ], span: span(), }), @@ -1389,8 +1536,8 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")), var_assign("x", l.clone()) ]; @@ -1405,12 +1552,36 @@ mod ownership_tests { } #[test] - fn test_varassign_assign_to_self_doesnt_move() { + fn test_initied_var_assign_to_self_doesnt_move() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + + Stmt::Unlock(vec![var_expr("x")]), + + var_assign("x", var_expr("x")), + var_assign("x", l.clone()), + + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + + let result = check_semantics(&mut ast); + + assert!(result.is_ok()); + } + } + + #[test] + fn test_uninitied_var_assign_to_self_doesnt_move() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + var_decl(false, "x", t.clone(), l.clone()), + var_assign("x", var_expr("x")), var_assign("x", l.clone()), @@ -1441,10 +1612,10 @@ mod ownership_tests { span: span(), }; let body = vec![ - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit.clone()), // move a to x - var_decl("x", Type::Array(Box::new(t.clone())), var_expr("a")), - var_decl("y", t.clone(), access), + var_decl(true, "x", Type::Array(Box::new(t.clone())), var_expr("a")), + var_decl(true, "y", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -1473,10 +1644,10 @@ mod ownership_tests { span: span(), }; let body = vec![ - var_decl("a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), + var_decl(true, "a", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), arr_lit.clone()), // move a to x - var_decl("x", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), var_expr("a")), - var_decl("y", t.clone(), access), + var_decl(true, "x", Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i + 1)), var_expr("a")), + var_decl(true, "y", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -1498,9 +1669,9 @@ mod ownership_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), var_expr("x")), - var_decl("z", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), var_expr("x")), + var_decl(true, "z", t.clone(), l.clone()), var_assign("z", var_expr("x")) ]; let func = void_func("foo", vec![], body); @@ -1518,15 +1689,40 @@ mod ownership_tests { // #[test] - fn test_varassign_moving_upstream_var_in_infinite_loop_errors() { + fn test_initied_var_assign_moving_upstream_var_in_infinite_loop_errors() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + var_decl(true, "x", t.clone(), l.clone()), + Stmt::Infinite(InfiniteStmt{ + branch: vec![ + var_decl(true, "y", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("y")]), + var_assign("y", var_expr("x")) + ], + span: span(), + }), + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + + let result = check_semantics(&mut ast); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("variable `x` is potentially moved multiple times")); + } + } + + #[test] + fn test_uninitied_var_assign_moving_upstream_var_in_infinite_loop_errors() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Infinite(InfiniteStmt{ branch: vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(false, "y", t.clone(), l.clone()), var_assign("y", var_expr("x")) ], span: span(), @@ -1542,16 +1738,42 @@ mod ownership_tests { } #[test] - fn test_varassign_moving_upstream_var_in_while_loop_errors() { + fn test_initied_var_assign_moving_upstream_var_in_while_loop_errors() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: bool_lit(false), branch: vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("y")]), + var_assign("y", var_expr("x")) + ], + span: span(), + }), + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + + let result = check_semantics(&mut ast); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("variable `x` is potentially moved multiple times")); + } + } + + #[test] + fn test_uninitied_var_assign_moving_upstream_var_in_while_loop_errors() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let body = vec![ + var_decl(true, "x", t.clone(), l.clone()), + Stmt::While(WhileStmt{ + condition: bool_lit(false), + branch: vec![ + var_decl(false, "y", t.clone(), l.clone()), var_assign("y", var_expr("x")) ], span: span(), @@ -1568,20 +1790,21 @@ mod ownership_tests { #[test] - fn test_varassign_moving_upstream_var_in_for_loop_errors() { + fn test_inited_vars_assign_moving_upstream_var_in_for_loop_errors() { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "e".to_string(), value: var_expr("a"), branch: vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("y")]), var_assign("y", var_expr("x")) ], span: span(), @@ -1597,7 +1820,36 @@ mod ownership_tests { } #[test] - fn test_multi_assign_use_of_moved_vars_errors() { + fn test_uninited_vars_assign_moving_upstream_var_in_for_loop_errors() { + let literals = get_all_literals_no_arr(); + + for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { + let arr_lit = array_lit(vec![], Some(t.clone())); + + let body = vec![ + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), + Stmt::For(ForStmt{ + holder_name: "e".to_string(), + value: var_expr("a"), + branch: vec![ + var_decl(false, "y", t.clone(), l.clone()), + var_assign("y", var_expr("x")) + ], + span: span(), + }), + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + + let result = check_semantics(&mut ast); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("variable `x` is potentially moved multiple times")); + } + } + + #[test] + fn test_multi_assign_to_initied_vars_use_of_moved_vars_errors() { let literals = get_all_literals_no_arr(); let literals_scattered = get_all_literals_no_arr_scattered_order(); @@ -1611,10 +1863,12 @@ mod ownership_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), - var_decl("c", t1.clone(), var_expr("a")), + var_decl(true, "c", t1.clone(), var_expr("a")), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -1642,10 +1896,11 @@ mod ownership_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), - var_decl("c", t2.clone(), var_expr("b")), + var_decl(true, "c", t2.clone(), var_expr("b")), Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], @@ -1673,12 +1928,14 @@ mod ownership_tests { let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); let body = vec![ - var_decl("a", t1.clone(), l1.clone()), - var_decl("b", t2.clone(), l2.clone()), + var_decl(true, "a", t1.clone(), l1.clone()), + var_decl(true, "b", t2.clone(), l2.clone()), - var_decl("c", t1.clone(), var_expr("a")), - var_decl("d", t2.clone(), var_expr("b")), + Stmt::Unlock(vec![var_expr("a"), var_expr("b")]), + var_decl(true, "c", t1.clone(), var_expr("a")), + var_decl(true, "d", t2.clone(), var_expr("b")), + Stmt::VarAssignMulti(MultiAssignment{ names: vec!["a".to_string(), "b".to_string()], value: call_expr("pair", vec![]), @@ -1714,10 +1971,10 @@ mod ownership_tests { span: span(), }; let body = vec![ - var_decl("arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), + var_decl(true, "arr", Type::Array(Box::new(t.clone())), arr_lit.clone()), // move arr to x - var_decl("x", Type::Array(Box::new(t.clone())), var_expr("arr")), - var_decl("y", t.clone(), access), + var_decl(true, "x", Type::Array(Box::new(t.clone())), var_expr("arr")), + var_decl(true, "y", t.clone(), access), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/return_tests.rs b/src/semantic/blackbox_tests/return_tests.rs index 94257e63..26ce5a8d 100644 --- a/src/semantic/blackbox_tests/return_tests.rs +++ b/src/semantic/blackbox_tests/return_tests.rs @@ -15,7 +15,7 @@ mod return_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ return_stmt(vec![l.clone()]), - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), ]; let func = returning_func("foo", vec![], vec![t.clone()], body); let mut ast = ast_one(func); @@ -35,7 +35,7 @@ mod return_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { - let body = vec![var_decl("x", t.clone(), l.clone())]; + let body = vec![var_decl(true, "x", t.clone(), l.clone())]; let func = returning_func("foo", vec![], vec![t.clone()], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -67,7 +67,7 @@ mod return_tests { for t in ALL_TYPES_NO_ARR { let callee = void_func("bar", vec![], vec![]); let body = vec![ - var_decl("x", t.clone(), call_expr("bar", vec![])) + var_decl(true, "x", t.clone(), call_expr("bar", vec![])) ]; let caller = void_func("main", vec![], body); let mut ast = AST { functions: vec![callee, caller], globals: vec![] }; diff --git a/src/semantic/blackbox_tests/unary_op_tests.rs b/src/semantic/blackbox_tests/unary_op_tests.rs index 9d4b9347..30d6e962 100644 --- a/src/semantic/blackbox_tests/unary_op_tests.rs +++ b/src/semantic/blackbox_tests/unary_op_tests.rs @@ -15,7 +15,7 @@ mod unary_op_tests { expr: Box::new(ul.clone()), span: span(), }; - let body = vec![var_decl("x", t.clone(), neg)]; + let body = vec![var_decl(true, "x", t.clone(), neg)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -34,7 +34,7 @@ mod unary_op_tests { expr: Box::new(sl.clone()), span: span(), }; - let body = vec![var_decl("x", t.clone(), neg)]; + let body = vec![var_decl(true, "x", t.clone(), neg)]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); diff --git a/src/semantic/blackbox_tests/var_assign_tests.rs b/src/semantic/blackbox_tests/var_assign_tests.rs index f4bdb341..06430de2 100644 --- a/src/semantic/blackbox_tests/var_assign_tests.rs +++ b/src/semantic/blackbox_tests/var_assign_tests.rs @@ -5,12 +5,47 @@ mod var_assign_tests { use super::*; #[test] - fn test_varassign() { + fn inited_var_assign() { let literals = get_all_literals(); for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + Stmt::Unlock(vec![var_expr("x")]), + var_assign("x", l.clone()) + ]; + let func = void_func("foo", vec![], body); + let mut ast = ast_one(func); + check_semantics(&mut ast).unwrap(); + + assert_eq!(ast.globals.len(), 0); + assert_eq!(ast.functions.len(), 1); + assert_eq!(ast.functions[0].body.len(), 3); + + if let Stmt::VarDecl(v) = &ast.functions[0].body[0] { + assert_eq!(v.name, "x"); + assert_eq!(v.type_name, t.clone()); + assert_eq!(v.value, l.clone()); + } else { panic!("expected VarDecl, got {:?}", ast); } + + if let Stmt::Unlock(vec) = &ast.functions[0].body[1] { + assert_eq!(vec.len(), 1); + } else { panic!("expected Unlock, got {:?}", ast); } + + if let Stmt::VarAssign(va) = &ast.functions[0].body[2] { + assert_eq!(va.name, "x"); + assert_eq!(va.value, l.clone()); + } else { panic!("expected VarAssign, got {:?}", ast); } + } + } + + #[test] + fn uninited_var_assign() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + var_decl(false, "x", t.clone(), l.clone()), var_assign("x", l.clone()) ]; let func = void_func("foo", vec![], body); @@ -76,7 +111,7 @@ mod var_assign_tests { for l in literals_ints { for t in ALL_TYPES_NO_INTS_NO_ARR { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), var_assign("x", l.clone()) ]; let func = void_func("foo", vec![], body); @@ -96,7 +131,7 @@ mod var_assign_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), var_assign("x", var_expr("y")) ]; let func = void_func("foo", vec![], body); @@ -127,7 +162,7 @@ mod var_assign_tests { fn test_assignment_of_undeclared_variable_other_errors() { for t in ALL_TYPES_NO_ARR { let body = vec![ - var_decl("x", t.clone(), var_expr("y")), + var_decl(true, "x", t.clone(), var_expr("y")), ]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); diff --git a/src/semantic/blackbox_tests/var_decl_tests.rs b/src/semantic/blackbox_tests/var_decl_tests.rs index e25fa356..a4b3ff87 100644 --- a/src/semantic/blackbox_tests/var_decl_tests.rs +++ b/src/semantic/blackbox_tests/var_decl_tests.rs @@ -13,7 +13,7 @@ mod var_decl_tests { let literals = get_all_literals_no_arr(); for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { - let body = vec![var_decl("x", t.clone(), l.clone())]; + let body = vec![var_decl(true, "x", t.clone(), l.clone())]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); check_semantics(&mut ast).unwrap(); @@ -31,7 +31,7 @@ mod var_decl_tests { fn var_name_taken_by_same_func_errors() { for t in ALL_TYPES_NO_ARR { let main = void_func("main", vec![], vec![ - var_decl("main", t.clone(), call_expr("foo", vec![])), + var_decl(true, "main", t.clone(), call_expr("foo", vec![])), ]); let mut ast = AST { functions: vec![main], globals: vec![] }; @@ -46,7 +46,7 @@ mod var_decl_tests { fn var_name_taken_by_different_func_errors() { for t in ALL_TYPES_NO_ARR { let main = void_func("main", vec![], vec![ - var_decl("foo", t.clone(), call_expr("foo", vec![])), + var_decl(true, "foo", t.clone(), call_expr("foo", vec![])), ]); let foo = void_func("foo", vec![], vec![]); @@ -62,7 +62,7 @@ mod var_decl_tests { #[test] fn non_declared_var_as_value_errors() { for t in ALL_TYPES_NO_ARR { - let body = vec![var_decl("x", t.clone(), var_expr("y"))]; + let body = vec![var_decl(true, "x", t.clone(), var_expr("y"))]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); @@ -79,7 +79,7 @@ mod var_decl_tests { for t in ALL_INT_TYPES_NO_ARR { for l in &literals_no_ints { - let body = vec![var_decl("x", t.clone(), l.clone())]; + let body = vec![var_decl(true, "x", t.clone(), l.clone())]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -103,15 +103,15 @@ mod var_decl_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "x".to_string(), value: var_expr("a"), branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -135,13 +135,13 @@ mod var_decl_tests { let arr_lit = array_lit(vec![], Some(t.clone())); let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("a", Type::Array(Box::new(t.clone())), arr_lit), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "a", Type::Array(Box::new(t.clone())), arr_lit), Stmt::For(ForStmt{ holder_name: "e".to_string(), value: var_expr("a"), branch: vec![ - var_decl("x", t.clone(), l.clone()) + var_decl(true, "x", t.clone(), l.clone()) ], span: span(), }), @@ -163,11 +163,11 @@ mod var_decl_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: bool_lit(false), branch: vec![ - var_decl("x", t.clone(), l.clone()) + var_decl(true, "x", t.clone(), l.clone()) ], span: span(), }), @@ -187,10 +187,10 @@ mod var_decl_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::Infinite(InfiniteStmt{ branch: vec![ - var_decl("x", t.clone(), l.clone()) + var_decl(true, "x", t.clone(), l.clone()) ], span: span(), }), @@ -212,11 +212,11 @@ mod var_decl_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bool_lit(false), if_branch: vec![ - var_decl("x", t.clone(), l.clone()) + var_decl(true, "x", t.clone(), l.clone()) ], elif_branches: vec![], else_branch: None, @@ -239,18 +239,18 @@ mod var_decl_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bool_lit(false), if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![], else_branch: Some(vec![ - var_decl("x", t.clone(), l.clone()) + var_decl(true, "x", t.clone(), l.clone()) ]), span: span(), }), @@ -271,17 +271,17 @@ mod var_decl_tests { for (l, t) in literals.iter().zip(ALL_TYPES_NO_ARR.iter()) { let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::If(IfStmt{ condition: bool_lit(false), if_branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], elif_branches: vec![ (bool_lit(false), vec![ - var_decl("x", t.clone(), l.clone()) + var_decl(true, "x", t.clone(), l.clone()) ]) ], else_branch: None, @@ -305,7 +305,7 @@ mod var_decl_tests { for l in &literals_ints_floats { // Variables declared with explicit type of bool, but given an non-bool literal is a type mismatch - let body = vec![var_decl("x", Type::Bool, l.clone())]; + let body = vec![var_decl(true, "x", Type::Bool, l.clone())]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -316,7 +316,7 @@ mod var_decl_tests { for l in literals_ints_floats { // Variables declared with explicit type of string, but given an non-string literal is a type mismatch - let body = vec![var_decl("x", Type::String, l.clone())]; + let body = vec![var_decl(true, "x", Type::String, l.clone())]; let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -331,7 +331,7 @@ mod var_decl_tests { fn test_use_of_undeclared_variable_other_errors() { // Try referencing non-existent variable "y" for t in ALL_TYPES_NO_ARR { - let body = vec![var_decl("x", t.clone(), var_expr("y"))]; // y not declared + let body = vec![var_decl(true, "x", t.clone(), var_expr("y"))]; // y not declared let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); @@ -344,7 +344,7 @@ mod var_decl_tests { fn test_use_of_undeclared_variable_ourself_errors() { // Try referencing non-existent variable "x" aka ourselves. for t in ALL_TYPES_NO_ARR { - let body = vec![var_decl("x", t.clone(), var_expr("x"))]; // x not declared + let body = vec![var_decl(true, "x", t.clone(), var_expr("x"))]; // x not declared let func = void_func("foo", vec![], body); let mut ast = ast_one(func); let result = check_semantics(&mut ast); diff --git a/src/semantic/blackbox_tests/while_stmt_tests.rs b/src/semantic/blackbox_tests/while_stmt_tests.rs index 9942ef4a..2bdcbd96 100644 --- a/src/semantic/blackbox_tests/while_stmt_tests.rs +++ b/src/semantic/blackbox_tests/while_stmt_tests.rs @@ -53,7 +53,7 @@ mod while_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -92,7 +92,7 @@ mod while_stmt_tests { branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -120,15 +120,15 @@ mod while_stmt_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), - var_decl("y", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: condition, branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -157,14 +157,14 @@ mod while_stmt_tests { }; let body = vec![ - var_decl("x", t.clone(), l.clone()), + var_decl(true, "x", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: condition, branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), @@ -186,14 +186,14 @@ mod while_stmt_tests { }; let body = vec![ - var_decl("y", t.clone(), l.clone()), + var_decl(true, "y", t.clone(), l.clone()), Stmt::While(WhileStmt{ condition: condition, branch: vec![ // Just dummy declaration, so we don't get flagged by dead code because // of empty branch. - var_decl("z", t.clone(), l.clone()), + var_decl(true, "z", t.clone(), l.clone()), ], span: span(), }), diff --git a/src/transpiler.rs b/src/transpiler.rs index b6be2a96..0c54ee22 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -4,11 +4,16 @@ use crate::ast::{ ArraySliceRange }; +#[cfg(test)] +mod reflective_tests; + /// Takes a reference to a Abstract Syntax Tree, and returns equvilent code in Rust as a string /// pub fn transpile(ast: &AST) -> String { let mut rcode: String = String::new(); + rcode.push_str(&import_internals()); + for global_stmt in &ast.globals { let global_stmt_rcode = transpile_global_stmt(global_stmt); @@ -25,6 +30,11 @@ pub fn transpile(ast: &AST) -> String { } +fn import_internals() -> String { + let content = include_str!("transpiler/internal.rs"); + return content.to_string() +} + /// Transpiles a function and its inner statements into equvilent Rust code /// @@ -92,14 +102,18 @@ fn transpile_stmt(stmt: &Stmt) -> String { let var_type = holy_type_to_rust_type_str(&var.type_name); let var_value = holy_expr_to_rust_expr(&var.value); - return format!("let mut {}: {} = {};", var.name, var_type, var_value); + if var.explicitly_initialized { + return format!("let {}: {} = {};", var.name, var_type, var_value); + } else { + return format!("let mut {}: {} = {};", var.name, var_type, var_value); + } }, + Stmt::VarDeclMulti(multi_var, expr) => { let mut multi_decl_stmt_str: String = "let (".to_string(); for var in multi_var { - multi_decl_stmt_str.push_str("mut "); multi_decl_stmt_str.push_str(&var.name); multi_decl_stmt_str.push_str(", "); } @@ -387,17 +401,17 @@ fn holy_expr_to_rust_expr(expr: &Expr) -> String { match op { // Arithemtic // - BinOpKind::Add => format!("{}.checked_add({}).unwrap_or_else(|| panic!(\"arithemtic addition overflow\"))", left_str, right_str), - BinOpKind::Subtract => format!("{}.checked_sub({}).unwrap_or_else(|| panic!(\"arithemtic subtraction overflow\"))", left_str, right_str), - BinOpKind::Multiply => format!("{}.checked_mul({}).unwrap_or_else(|| panic!(\"arithemtic multiplication overflow\"))", left_str, right_str), - BinOpKind::Divide => format!("{}.checked_div({}).unwrap_or_else(|| panic!(\"arithemtic divison overflow\"))", left_str, right_str), + BinOpKind::Add => format!("{}.checked_add({}).unwrap_or_else(|| panic!(\"arithmetic addition overflow\"))", left_str, right_str), + BinOpKind::Subtract => format!("{}.checked_sub({}).unwrap_or_else(|| panic!(\"arithmetic subtraction overflow\"))", left_str, right_str), + BinOpKind::Multiply => format!("{}.checked_mul({}).unwrap_or_else(|| panic!(\"arithmetic multiplication overflow\"))", left_str, right_str), + BinOpKind::Divide => format!("{}.checked_div({}).unwrap_or_else(|| panic!(\"arithmetic divison overflow\"))", left_str, right_str), // Logical // BinOpKind::Equal => format!("({} == {})", left_str, right_str), BinOpKind::NotEqual => format!("({} != {})", left_str, right_str), BinOpKind::Greater => format!("({} > {})", left_str, right_str), - BinOpKind::Less => format!("({} > {})", left_str, right_str), + BinOpKind::Less => format!("({} < {})", left_str, right_str), BinOpKind::GreaterEqual => format!("({} >= {})", left_str, right_str), BinOpKind::LessEqual => format!("({} <= {})", left_str, right_str), diff --git a/src/transpiler/internal.rs b/src/transpiler/internal.rs new file mode 100644 index 00000000..293671f4 --- /dev/null +++ b/src/transpiler/internal.rs @@ -0,0 +1,34 @@ +/// This file content will be included directly in all transpiled holylang programs source code +/// It implements things like checked arthiemtic on floating point64 +/// + + +trait _CheckedOpsF64 { + fn checked_add(self, rhs: f64) -> Option; + fn checked_sub(self, rhs: f64) -> Option; + fn checked_mul(self, rhs: f64) -> Option; + fn checked_div(self, rhs: f64) -> Option; +} + +impl _CheckedOpsF64 for f64 { + fn checked_add(self, rhs: f64) -> Option { + let result = self + rhs; + if result.is_finite() { Some(result) } else { None } + } + + fn checked_sub(self, rhs: f64) -> Option { + let result = self - rhs; + if result.is_finite() { Some(result) } else { None } + } + + fn checked_mul(self, rhs: f64) -> Option { + let result = self * rhs; + if result.is_finite() { Some(result) } else { None } + } + + fn checked_div(self, rhs: f64) -> Option { + if rhs == 0.0 { return None; } + let result = self / rhs; + if result.is_finite() { Some(result) } else { None } + } +} diff --git a/src/transpiler/reflective_tests.rs b/src/transpiler/reflective_tests.rs new file mode 100644 index 00000000..af8bbb79 --- /dev/null +++ b/src/transpiler/reflective_tests.rs @@ -0,0 +1,312 @@ +use super::*; +use std::sync::LazyLock; +use crate::tests_consts::{ + // ALL_TYPES_NO_ARR, + ALL_BIN_OP_KIND, ALL_BIN_OP_KIND_COMP, ALL_BIN_OP_KIND_COMP_EQ +}; + +use crate::ast::{ + Type, Span, Stmt, Expr, Param, + IntLiteralValue, + VariableDeclaration, MultiVariableDeclaration, + VariableAssignment, MultiAssignment, + + WhileStmt, InfiniteStmt, ForStmt, IfStmt, + BreakStmt +}; + +mod const_tests; +mod var_decl_tests; +mod var_assign_tests; +mod multi_return_tests; +mod lock_tests; +mod unlock_tests; + +mod break_stmt_tests; + +// With dynamic array types +static ALL_TYPES_WITH_DYN_ARR: LazyLock> = LazyLock::new(|| { + vec![ + Type::Int8, + Type::Int16, + Type::Int32, + Type::Int64, + Type::Int128, + Type::Byte, + Type::Uint16, + Type::Uint32, + Type::Uint64, + Type::Uint128, + Type::Usize, + Type::Float64, + Type::Bool, + Type::String, + + Type::Array(Box::new(Type::Int8)), + Type::Array(Box::new(Type::Int16)), + Type::Array(Box::new(Type::Int32)), + Type::Array(Box::new(Type::Int64)), + Type::Array(Box::new(Type::Int128)), + + Type::Array(Box::new(Type::Byte)), + Type::Array(Box::new(Type::Uint16)), + Type::Array(Box::new(Type::Uint32)), + Type::Array(Box::new(Type::Uint64)), + Type::Array(Box::new(Type::Uint128)), + Type::Array(Box::new(Type::Usize)), + + Type::Array(Box::new(Type::Float64)), + Type::Array(Box::new(Type::Bool)), + Type::Array(Box::new(Type::String)), + ] +}); + +fn span() -> Span { + Span { line: 1, column: 0 } +} + +/// Build an AST that contains exactly one function. +fn ast_one(func: Function) -> AST { + AST { functions: vec![func], globals: vec![] } +} + +/// Build a void function (no return type) with the given body. +fn void_func(name: &str, params: Vec, body: Vec) -> Function { + Function { + name: name.to_string(), + params, + return_type: None, + body, + span: span(), + } +} + +/// Build a function that returns a single type. +fn returning_func(name: &str, params: Vec, ret: Vec, body: Vec) -> Function { + Function { + name: name.to_string(), + params, + return_type: Some(ret), + body, + span: span(), + } +} + +fn call_expr(name: &str, args: Vec) -> Expr { + Expr::Call { name: name.to_string(), args, span: span() } +} + +fn return_stmt(exprs: Vec) -> Stmt { + Stmt::Return(exprs) +} + +fn param(name: &str, ty: Type) -> Param { + Param { name: name.to_string(), type_name: ty, span: span() } +} + +fn const_define_locally(name: &str, ty: Type, value: Expr) -> Stmt { + Stmt::Const(Constant { + name: name.to_string(), + type_name: ty, + value, + span: span(), + }) +} + +fn const_define_globally(name: &str, ty: Type, value: Expr) -> GlobalStmt { + GlobalStmt::Const(Constant { + name: name.to_string(), + type_name: ty, + value, + span: span(), + }) +} + +fn var_expr(name: &str) -> Expr { + Expr::Var { name: name.to_string(), span: span() } +} + +fn var_decl(name: &str, ty: Type, value: Expr, explicitly_initialized: bool) -> Stmt { + Stmt::VarDecl(VariableDeclaration { + name: name.to_string(), + type_name: ty, + value, + explicitly_initialized, + span: span(), + }) +} + +fn var_assign(name: &str, value: Expr) -> Stmt { + Stmt::VarAssign(VariableAssignment { + name: name.to_string(), + value, + span: span(), + }) +} + +fn int8_lit(n: i8) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Int8(n), span: span() } +} + +fn int16_lit(n: i16) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Int16(n), span: span() } +} + +fn int32_lit(n: i32) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Int32(n), span: span() } +} + +fn int64_lit(n: i64) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Int64(n), span: span() } +} + +fn int128_lit(n: i128) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Int128(n), span: span() } +} + + + +fn byte_lit(b: u8) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Byte(b), span: span() } +} + +fn uint16_lit(n: u16) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Uint16(n), span: span() } +} + +fn uint32_lit(n: u32) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Uint32(n), span: span() } +} + +fn uint64_lit(n: u64) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Uint64(n), span: span() } +} + +fn uint128_lit(n: u128) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Uint128(n), span: span() } +} + + +fn usize_lit(n: usize) -> Expr { + Expr::IntLiteral { value: IntLiteralValue::Usize(n), span: span() } +} + +fn float64_lit(f: f64) -> Expr { + Expr::Float64Literal { value: f, span: span() } +} + + +fn bool_lit(b: bool) -> Expr { + Expr::BoolLiteral { value: b, span: span() } +} + +fn str_lit(s: &str) -> Expr { + Expr::StringLiteral { value: s.to_string(), span: span() } +} + +fn array_lit(exprs: Vec, type_name: Option) -> Expr { + Expr::ArrayLiteral { elements: exprs, type_name, span: span() } +} + +fn get_many_boolean_conditions() -> Vec { + let literals = get_all_literals(); + + let mut boolean_conds = vec![ + bool_lit(true), + bool_lit(false), + ]; + + for l in literals { + for b in ALL_BIN_OP_KIND_COMP { + // So that >= > <= < doesnt get performed on non integer/floats. + if !ALL_BIN_OP_KIND_COMP_EQ.contains(&b) { + match l { + Expr::StringLiteral { .. } | Expr::BoolLiteral { .. } | Expr::ArrayLiteral { .. } => { + continue + }, + _ => {} + } + } + + let bin = Expr::BinOp { + left: Box::new(l.clone()), + right: Box::new(l.clone()), + op: b, + span: span(), + }; + + boolean_conds.push(bin); + } + } + + return boolean_conds; +} + + +/* +fn get_all_literals_no_arr() -> [Expr; 14] { + let literals = [ + int8_lit(1), + int16_lit(1), + int32_lit(1), + int64_lit(1), + int128_lit(1), + + byte_lit(1), + uint16_lit(1), + uint32_lit(1), + uint64_lit(1), + uint128_lit(1), + + usize_lit(1), + + float64_lit(1.0), + + bool_lit(false), + str_lit("Hi") + ]; + + return literals; +} +*/ + +fn get_all_literals() -> [Expr; 28] { + return [ + int8_lit(1), + int16_lit(1), + int32_lit(1), + int64_lit(1), + int128_lit(1), + + byte_lit(1), + uint16_lit(1), + uint32_lit(1), + uint64_lit(1), + uint128_lit(1), + + usize_lit(1), + + float64_lit(1.0), + + bool_lit(false), + str_lit("Hi"), + + array_lit(vec![int8_lit(1), int8_lit(i8::MIN), int8_lit(i8::MAX) ], Some(Type::Array(Box::new(Type::Int8)))), + array_lit(vec![int16_lit(1), int16_lit(i16::MIN), int16_lit(i16::MAX) ], Some(Type::Array(Box::new(Type::Int16)))), + array_lit(vec![int32_lit(1), int32_lit(i32::MIN), int32_lit(i32::MAX) ], Some(Type::Array(Box::new(Type::Int32)))), + array_lit(vec![int64_lit(1), int64_lit(i64::MIN), int64_lit(i64::MAX) ], Some(Type::Array(Box::new(Type::Int64)))), + array_lit(vec![int128_lit(1), int128_lit(i128::MIN), int128_lit(i128::MAX) ], Some(Type::Array(Box::new(Type::Int128)))), + + array_lit(vec![byte_lit(1), byte_lit(u8::MIN), byte_lit(u8::MAX) ], Some(Type::Array(Box::new(Type::Byte)))), + array_lit(vec![uint16_lit(1), uint16_lit(u16::MIN), uint16_lit(u16::MAX) ], Some(Type::Array(Box::new(Type::Uint16)))), + array_lit(vec![uint32_lit(1), uint32_lit(u32::MIN), uint32_lit(u32::MAX) ], Some(Type::Array(Box::new(Type::Uint32)))), + array_lit(vec![uint64_lit(1), uint64_lit(u64::MIN), uint64_lit(u64::MAX) ], Some(Type::Array(Box::new(Type::Uint64)))), + array_lit(vec![uint128_lit(1), uint128_lit(u128::MIN), uint128_lit(u128::MAX) ], Some(Type::Array(Box::new(Type::Uint128)))), + array_lit(vec![usize_lit(1), usize_lit(usize::MIN), usize_lit(usize::MAX) ], Some(Type::Array(Box::new(Type::Usize)))), + + array_lit(vec![float64_lit(1.0), float64_lit(f64::MIN), float64_lit(f64::MAX) ], Some(Type::Array(Box::new(Type::Float64)))), + array_lit(vec![bool_lit(false), bool_lit(true)], Some(Type::Array(Box::new(Type::Bool)))), + array_lit(vec![str_lit(""), str_lit("Hi"), str_lit(" !")], Some(Type::Array(Box::new(Type::String)))) + ]; +} + diff --git a/src/transpiler/reflective_tests/break_stmt_tests.rs b/src/transpiler/reflective_tests/break_stmt_tests.rs new file mode 100644 index 00000000..63a2fdee --- /dev/null +++ b/src/transpiler/reflective_tests/break_stmt_tests.rs @@ -0,0 +1,1415 @@ +use super::*; + +#[cfg(test)] +mod break_stmt_in_void_func_tests { + use super::*; + + #[test] + fn break_stmt() { + let body = vec![ + Stmt::Break(BreakStmt { span: span() }) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, "fn foo() { break;}"); + } + + + #[test] + fn break_stmt_in_infinite_loop() { + let body = vec![ + Stmt::Infinite(InfiniteStmt{ + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, "fn foo() { loop {break;}}"); + } + + + #[test] + fn break_stmt_in_while_loop_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::While(WhileStmt{ + condition: l.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ while {} {{break;}}}}", l_str)); + } + } + + #[test] + fn break_stmt_in_while_loop_all_binops() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::While(WhileStmt{ + condition: bin.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ while {} {{break;}}}}", bin_str)); + } + } + } + + #[test] + fn break_stmt_in_for_loop_with_var() { + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: var_expr("arr"), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, "fn foo() { for x in arr {break;}}"); + } + + #[test] + fn break_stmt_in_for_loop_with_literal() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: l.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ for x in {} {{break;}}}}", l_str)); + } + } + + #[test] + fn break_stmt_in_for_loop_with_binop() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: bin.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ for x in {} {{break;}}}}", bin_str)); + } + } + } + + #[test] + fn break_stmt_in_if_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: None, + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ if {} {{break;}}}}", l_str)); + } + } + + #[test] + fn break_stmt_in_if_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: None, + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ if {} {{break;}}}}", bin_str)); + } + } + } + + + #[test] + fn break_stmt_in_if_else_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ if {} {{break;}} else {{break;}}}}", l_str)); + } + } + + #[test] + fn break_stmt_in_if_else_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ if {} {{break;}} else {{break;}}}}", bin_str)); + } + } + } + + #[test] + fn break_stmt_in_if_elif_else_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![(l.clone(), vec![ + Stmt::Break(BreakStmt { span: span() }) + ])], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ if {} {{break;}} else if {} {{break;}} else {{break;}}}}", l_str, l_str)); + } + } + + #[test] + fn break_stmt_in_if_elif_else_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![(bin.clone(), vec![ + Stmt::Break(BreakStmt { span: span() }) + ])], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ if {} {{break;}} else if {} {{break;}} else {{break;}}}}", bin_str, bin_str)); + } + } + } +} + + +#[cfg(test)] +mod break_stmt_in_void_func_with_params_tests { + use super::*; + + #[test] + fn break_stmt() { + let body = vec![ + Stmt::Break(BreakStmt { span: span() }) + ]; + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ break;}}", t_str, t_str)); + } + } + + + #[test] + fn break_stmt_in_infinite_loop() { + let body = vec![ + Stmt::Infinite(InfiniteStmt{ + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ loop {{break;}}}}", t_str, t_str)); + } + } + + + #[test] + fn break_stmt_in_while_loop_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::While(WhileStmt{ + condition: l.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ while {} {{break;}}}}", t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_while_loop_all_binops() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::While(WhileStmt{ + condition: bin.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ while {} {{break;}}}}", t_str, t_str, bin_str)); + } + } + } + } + + #[test] + fn break_stmt_in_for_loop_with_var() { + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: var_expr("arr"), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ for x in arr {{break;}}}}", t_str, t_str)); + } + } + + #[test] + fn break_stmt_in_for_loop_with_literal() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: l.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ for x in {} {{break;}}}}", t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_for_loop_with_binop() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: bin.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ for x in {} {{break;}}}}", t_str, t_str, bin_str)); + } + } + } + } + + #[test] + fn break_stmt_in_if_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: None, + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ if {} {{break;}}}}", t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_if_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: None, + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ if {} {{break;}}}}", t_str, t_str, bin_str)); + } + } + } + } + + + #[test] + fn break_stmt_in_if_else_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ if {} {{break;}} else {{break;}}}}", t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_if_else_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + let bin_str = holy_expr_to_rust_expr(&bin); + + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ if {} {{break;}} else {{break;}}}}", t_str, t_str, bin_str)); + } + } + } + } + + #[test] + fn break_stmt_in_if_elif_else_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![(l.clone(), vec![ + Stmt::Break(BreakStmt { span: span() }) + ])], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ if {} {{break;}} else if {} {{break;}} else {{break;}}}}", t_str, t_str, l_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_if_elif_else_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![(bin.clone(), vec![ + Stmt::Break(BreakStmt { span: span() }) + ])], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ if {} {{break;}} else if {} {{break;}} else {{break;}}}}", t_str, t_str, bin_str, bin_str)); + } + } + } + } +} + + +#[cfg(test)] +mod break_stmt_in_returning_func_with_params_tests { + use super::*; + + #[test] + fn break_stmt() { + let body = vec![ + Stmt::Break(BreakStmt { span: span() }) + ]; + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ break;}}", t_str, t_str, t_str)); + } + } + + + #[test] + fn break_stmt_in_infinite_loop() { + let body = vec![ + Stmt::Infinite(InfiniteStmt{ + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ loop {{break;}}}}", t_str, t_str, t_str)); + } + } + + + #[test] + fn break_stmt_in_while_loop_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::While(WhileStmt{ + condition: l.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ while {} {{break;}}}}", t_str, t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_while_loop_all_binops() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::While(WhileStmt{ + condition: bin.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ while {} {{break;}}}}", t_str, t_str, t_str, bin_str)); + } + } + } + } + + #[test] + fn break_stmt_in_for_loop_with_var() { + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: var_expr("arr"), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ for x in arr {{break;}}}}", t_str, t_str, t_str)); + } + } + + #[test] + fn break_stmt_in_for_loop_with_literal() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: l.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ for x in {} {{break;}}}}", t_str, t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_for_loop_with_binop() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::For(ForStmt{ + holder_name: "x".to_string(), + value: bin.clone(), + branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ for x in {} {{break;}}}}", t_str, t_str, t_str, bin_str)); + } + } + } + } + + #[test] + fn break_stmt_in_if_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: None, + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ if {} {{break;}}}}", t_str, t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_if_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: None, + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ if {} {{break;}}}}", t_str, t_str, t_str, bin_str)); + } + } + } + } + + + #[test] + fn break_stmt_in_if_else_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ if {} {{break;}} else {{break;}}}}", t_str, t_str, t_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_if_else_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + let bin_str = holy_expr_to_rust_expr(&bin); + + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ if {} {{break;}} else {{break;}}}}", t_str, t_str, t_str, bin_str)); + } + } + } + } + + #[test] + fn break_stmt_in_if_elif_else_stmt_literal_condition() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + Stmt::If(IfStmt{ + condition: l.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![(l.clone(), vec![ + Stmt::Break(BreakStmt { span: span() }) + ])], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let l_str = holy_expr_to_rust_expr(&l); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ if {} {{break;}} else if {} {{break;}} else {{break;}}}}", t_str, t_str, t_str, l_str, l_str)); + } + } + } + + #[test] + fn break_stmt_in_if_elif_else_stmt_binop_condition() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + + let body = vec![ + Stmt::If(IfStmt{ + condition: bin.clone(), + if_branch: vec![ + Stmt::Break(BreakStmt { span: span() }) + ], + elif_branches: vec![(bin.clone(), vec![ + Stmt::Break(BreakStmt { span: span() }) + ])], + else_branch: Some(vec![ + Stmt::Break(BreakStmt { span: span() }) + ]), + span: span(), + }), + ]; + + let bin_str = holy_expr_to_rust_expr(&bin); + + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ if {} {{break;}} else if {} {{break;}} else {{break;}}}}", t_str, t_str, t_str, bin_str, bin_str)); + } + } + } + } +} + + diff --git a/src/transpiler/reflective_tests/const_tests.rs b/src/transpiler/reflective_tests/const_tests.rs new file mode 100644 index 00000000..939128c2 --- /dev/null +++ b/src/transpiler/reflective_tests/const_tests.rs @@ -0,0 +1,584 @@ +use super::*; + +#[cfg(test)] +mod const_in_globals_tests { + use super::*; + + #[test] + fn bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let globals = vec![ + const_define_globally("x", t.clone(), bl.clone()) + ]; + + let ast = &AST { functions: vec![], globals}; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("const x: {} = {};", t_str, bl_str)); + } + } + + #[test] + fn literals_and_dynamic_arrays() { + // Dynamic arrays are illegal for consts, but transpiler shouldnt care. its not its + // responsiblity + // + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let globals = vec![ + const_define_globally("x", t.clone(), l.clone()) + ]; + + let ast = &AST { functions: vec![], globals}; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("const x: {} = {};", t_str, l_str)); + } + } + + #[test] + fn fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let globals = vec![ + const_define_globally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + + let ast = &AST { functions: vec![], globals}; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("const x: {} = {};", fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let globals = vec![ + const_define_globally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + + let ast = &AST { functions: vec![], globals}; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("const x: {} = {};", fixed_arr_ty_str, l_arr_str)); + } + } + } +} + +#[cfg(test)] +mod const_in_void_func_tests { + use super::*; + + #[test] + fn bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let body = vec![ + const_define_locally("x", t.clone(), bl.clone()) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("fn foo() {{ const x: {} = {};}}", t_str, bl_str)); + } + } + + + #[test] + fn literals_and_dynamic_arrays() { + // Dynamic arrays are illegal for consts, but transpiler shouldnt care. its not its + // responsiblity + // + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + const_define_locally("x", t.clone(), l.clone()) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ const x: {} = {};}}", t_str, l_str)); + } + } + + #[test] + fn fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo() {{ const x: {} = {};}}", fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo() {{ const x: {} = {};}}", fixed_arr_ty_str, l_arr_str)); + } + } + } + + + +} + +#[cfg(test)] +mod const_in_void_func_with_params_tests { + use super::*; + + #[test] + fn bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let body = vec![ + const_define_locally("x", t.clone(), bl.clone()) + ]; + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ const x: {} = {};}}", t_str, t_str, t_str, bl_str)); + } + } + + #[test] + fn literals_and_dynamic_arrays() { + // Dynamic arrays are illegal for consts, but transpiler shouldnt care. its not its + // responsiblity + // + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + const_define_locally("x", t.clone(), l.clone()) + ]; + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ const x: {} = {};}}", t_str, t_str, t_str, l_str)); + } + } + + #[test] + fn fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = void_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ const x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = void_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ const x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + + +} + +#[cfg(test)] +mod const_in_single_returning_func_with_params_tests { + use super::*; + + #[test] + fn bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let body = vec![ + const_define_locally("x", t.clone(), bl.clone()) + ]; + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ const x: {} = {};}}", t_str, t_str, t_str, t_str, bl_str)); + } + } + + + #[test] + fn literals_and_dynamic_arrays() { + // Dynamic arrays are illegal for consts, but transpiler shouldnt care. its not its + // responsiblity + // + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + const_define_locally("x", t.clone(), l.clone()) + ]; + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ const x: {} = {};}}", t_str, t_str, t_str, t_str, l_str)); + } + } + + #[test] + fn fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ const x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + + #[test] + fn fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ const x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } +} + +#[cfg(test)] +mod const_in_multi_returning_func_with_params_tests { + use super::*; + + #[test] + fn bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let body = vec![ + const_define_locally("x", t.clone(), bl.clone()) + ]; + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone(); 3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ const x: {} = {};}}", t_str, t_str, t_str, t_str, t_str, t_str, bl_str)); + } + } + + + + #[test] + fn literals_and_dynamic_arrays() { + // Dynamic arrays are illegal for consts, but transpiler shouldnt care. its not its + // responsiblity + // + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + const_define_locally("x", t.clone(), l.clone()) + ]; + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone(); 3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ const x: {} = {};}}", t_str, t_str, t_str, t_str, t_str, t_str, l_str)); + } + } + + #[test] + fn fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone();3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!( + rcode, + format!( + "fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ const x: {} = {};}}", + fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str + ) + ); + } + } + } + + #[test] + fn fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + const_define_locally("x", fixed_arr_ty.clone(), l_arr.clone()) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone();3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!( + rcode, + format!( + "fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ const x: {} = {};}}", + fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str + ) + ); + } + } + } +} diff --git a/src/transpiler/reflective_tests/lock_tests.rs b/src/transpiler/reflective_tests/lock_tests.rs new file mode 100644 index 00000000..a167cb6b --- /dev/null +++ b/src/transpiler/reflective_tests/lock_tests.rs @@ -0,0 +1,270 @@ +use super::*; + +#[cfg(test)] +mod lock_in_void_func_tests { + use super::*; + + #[test] + fn lock_literals_expr_panics() { + let literals = get_all_literals(); + + for l in literals { + for i in 1..100 { + let body = vec![ + Stmt::Lock(vec![l.clone(); i]), + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + #[test] + fn lock_binop_expr_panics() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::Lock(vec![bin]), + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + + #[test] + fn lock_single_char_var() { + let letters: Vec = ('a'..='z') + .chain('A'..='Z') + .collect(); + + for l in letters { + for i in 1..100 { + let body = vec![ + Stmt::Lock(vec![var_expr(&l.to_string()); i]), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..] + .replace('\n', "") + .replace("// Lock statement started", "") + .replace("// Lock statement ended", ""); + + let expected_rcode = format!("let {} = {};", l, l); + let expected_rcode = expected_rcode.repeat(i); + + assert_eq!(rcode, format!("fn foo() {{ {}}}", expected_rcode)); + } + } + } +} + +#[cfg(test)] +mod lock_in_void_func_with_params_tests { + use super::*; + + #[test] + fn lock_literals_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 1..100 { + let body = vec![ + Stmt::Lock(vec![l.clone(); i]), + ]; + + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + #[test] + fn lock_binop_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::Lock(vec![bin]), + ]; + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + + #[test] + fn lock_single_char_var() { + let letters: Vec = ('a'..='z') + .chain('A'..='Z') + .collect(); + + for l in letters { + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + for i in 1..10 { + let body = vec![ + Stmt::Lock(vec![var_expr(&l.to_string()); i]), + ]; + + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..] + .replace('\n', "") + .replace("// Lock statement started", "") + .replace("// Lock statement ended", ""); + + let expected_rcode = format!("let {} = {};", l, l); + let expected_rcode = expected_rcode.repeat(i); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ {}}}", t_str, t_str, expected_rcode)); + } + } + } + } +} + + +#[cfg(test)] +mod lock_in_returning_func_tests { + use super::*; + + #[test] + fn lock_literals_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 1..100 { + let body = vec![ + Stmt::Lock(vec![l.clone(); i]), + ]; + + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + #[test] + fn lock_binop_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::Lock(vec![bin]), + ]; + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + + #[test] + fn lock_single_char_var() { + let letters: Vec = ('a'..='z') + .chain('A'..='Z') + .collect(); + + for l in letters { + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + for i in 1..10 { + let body = vec![ + Stmt::Lock(vec![var_expr(&l.to_string()); i]), + ]; + + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..] + .replace('\n', "") + .replace("// Lock statement started", "") + .replace("// Lock statement ended", ""); + + let expected_rcode = format!("let {} = {};", l, l); + let expected_rcode = expected_rcode.repeat(i); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ {}}}", t_str, t_str, t_str, expected_rcode)); + } + } + } + } +} diff --git a/src/transpiler/reflective_tests/multi_return_tests.rs b/src/transpiler/reflective_tests/multi_return_tests.rs new file mode 100644 index 00000000..d19e4490 --- /dev/null +++ b/src/transpiler/reflective_tests/multi_return_tests.rs @@ -0,0 +1,179 @@ +use super::*; + +#[cfg(test)] +mod multi_return_tests { + use super::*; + + #[test] + fn multi_decl() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + let l1_str = holy_expr_to_rust_expr(&l1); + + for (l2, t2) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let pair_body = vec![return_stmt(vec![l1.clone(), l2.clone()])]; + let pair = returning_func("pair", vec![], vec![t1.clone(), t2.clone()], pair_body); + + let vars = vec![ + MultiVariableDeclaration { name: "a".to_string(), type_name: t1.clone(), span: span() }, + MultiVariableDeclaration { name: "b".to_string(), type_name: t2.clone(), span: span() }, + ]; + let body = vec![Stmt::VarDeclMulti(vars, call_expr("pair", vec![]))]; + let main = void_func("main", vec![], body); + + let ast = &AST{ functions: vec![pair, main], globals: vec![] }; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let l2_str = holy_expr_to_rust_expr(&l2); + + assert_eq!( + rcode, + format!( + "fn pair() -> ({}, {}) {{ return ({}, {})}}fn main() {{ let (a, b): ({}, {}) = pair();}}", + t1_str, t2_str, l1_str, l2_str, t1_str, t2_str, + ) + ); + } + } + } + + #[test] + fn multi_decl_bincop_condition() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let bl_str = holy_expr_to_rust_expr(&bl); + + let pair_body = vec![return_stmt(vec![bl.clone();3])]; + let pair = returning_func("pair", vec![], vec![t.clone(); 3], pair_body); + + let vars = vec![ + MultiVariableDeclaration { name: "a".to_string(), type_name: t.clone(), span: span() }, + MultiVariableDeclaration { name: "b".to_string(), type_name: t.clone(), span: span() }, + MultiVariableDeclaration { name: "c".to_string(), type_name: t.clone(), span: span() }, + ]; + let body = vec![Stmt::VarDeclMulti(vars, call_expr("pair", vec![]))]; + let main = void_func("main", vec![], body); + + let ast = &AST{ functions: vec![pair, main], globals: vec![] }; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + + assert_eq!( + rcode, + format!( + "fn pair() -> ({}, {}, {}) {{ return ({}, {}, {})}}fn main() {{ let (a, b, c): ({}, {}, {}) = pair();}}", + t_str, t_str, t_str, bl_str, bl_str, bl_str, t_str, t_str, t_str + ) + ); + } + } + + #[test] + fn multi_decl_all_bin_op() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t_str = holy_type_to_rust_type_str(&t); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let pair_body = vec![return_stmt(vec![bin.clone();3])]; + let pair = returning_func("pair", vec![], vec![t.clone(); 3], pair_body); + + let vars = vec![ + MultiVariableDeclaration { name: "a".to_string(), type_name: t.clone(), span: span() }, + MultiVariableDeclaration { name: "b".to_string(), type_name: t.clone(), span: span() }, + MultiVariableDeclaration { name: "c".to_string(), type_name: t.clone(), span: span() }, + ]; + let body = vec![Stmt::VarDeclMulti(vars, call_expr("pair", vec![]))]; + let main = void_func("main", vec![], body); + + let ast = &AST{ functions: vec![pair, main], globals: vec![] }; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!( + rcode, + format!( + "fn pair() -> ({}, {}, {}) {{ return ({}, {}, {})}}fn main() {{ let (a, b, c): ({}, {}, {}) = pair();}}", + t_str, t_str, t_str, bin_str, bin_str, bin_str, t_str, t_str, t_str + ) + ); + } + } + } + + #[test] + fn multi_assignment_all_bin_op() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t_str = holy_type_to_rust_type_str(&t); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let pair_body = vec![return_stmt(vec![bin.clone();3])]; + let pair = returning_func("pair", vec![], vec![t.clone(); 3], pair_body); + + let body = vec![ + Stmt::VarAssignMulti(MultiAssignment{ + names: vec!["a".to_string(), "b".to_string(), "c".to_string()], + value: call_expr("pair", vec![]), + span: span() + }) + ]; + let main = void_func("main", vec![], body); + + let ast = &AST{ functions: vec![pair, main], globals: vec![] }; + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!( + rcode, + format!( + "fn pair() -> ({}, {}, {}) {{ return ({}, {}, {})}}fn main() {{ (a, b, c) = pair();}}", + t_str, t_str, t_str, bin_str, bin_str, bin_str + ) + ); + } + } + } + +} diff --git a/src/transpiler/reflective_tests/unlock_tests.rs b/src/transpiler/reflective_tests/unlock_tests.rs new file mode 100644 index 00000000..5b0f7f27 --- /dev/null +++ b/src/transpiler/reflective_tests/unlock_tests.rs @@ -0,0 +1,270 @@ +use super::*; + +#[cfg(test)] +mod unlock_in_void_func_tests { + use super::*; + + #[test] + fn unlock_literals_expr_panics() { + let literals = get_all_literals(); + + for l in literals { + for i in 1..100 { + let body = vec![ + Stmt::Unlock(vec![l.clone(); i]), + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + #[test] + fn unlock_binop_expr_panics() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::Unlock(vec![bin]), + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + + #[test] + fn unlock_single_char_var() { + let letters: Vec = ('a'..='z') + .chain('A'..='Z') + .collect(); + + for l in letters { + for i in 1..100 { + let body = vec![ + Stmt::Unlock(vec![var_expr(&l.to_string()); i]), + ]; + + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..] + .replace('\n', "") + .replace("// Unlock statement started", "") + .replace("// Unlock statement ended", ""); + + let expected_rcode = format!("let mut {} = {};", l, l); + let expected_rcode = expected_rcode.repeat(i); + + assert_eq!(rcode, format!("fn foo() {{ {}}}", expected_rcode)); + } + } + } +} + +#[cfg(test)] +mod unlock_in_void_func_with_params_tests { + use super::*; + + #[test] + fn unlock_literals_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 1..100 { + let body = vec![ + Stmt::Unlock(vec![l.clone(); i]), + ]; + + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + #[test] + fn unlock_binop_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::Unlock(vec![bin]), + ]; + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + + #[test] + fn unlock_single_char_var() { + let letters: Vec = ('a'..='z') + .chain('A'..='Z') + .collect(); + + for l in letters { + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + for i in 1..10 { + let body = vec![ + Stmt::Unlock(vec![var_expr(&l.to_string()); i]), + ]; + + let func = void_func("foo", vec![param("a", t.clone()), param("b", t.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..] + .replace('\n', "") + .replace("// Unlock statement started", "") + .replace("// Unlock statement ended", ""); + + let expected_rcode = format!("let mut {} = {};", l, l); + let expected_rcode = expected_rcode.repeat(i); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ {}}}", t_str, t_str, expected_rcode)); + } + } + } + } +} + + +#[cfg(test)] +mod unlock_in_returning_func_tests { + use super::*; + + #[test] + fn unlock_literals_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 1..100 { + let body = vec![ + Stmt::Unlock(vec![l.clone(); i]), + ]; + + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + #[test] + fn unlock_binop_expr_panics() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + Stmt::Unlock(vec![bin]), + ]; + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let result = std::panic::catch_unwind(|| { + let _ = transpile(ast); + }); + + assert!(result.is_err(), "Expected panic for: {:?}", ast); + } + } + } + + + #[test] + fn unlock_single_char_var() { + let letters: Vec = ('a'..='z') + .chain('A'..='Z') + .collect(); + + for l in letters { + for t in ALL_TYPES_WITH_DYN_ARR.iter() { + for i in 1..10 { + let body = vec![ + Stmt::Unlock(vec![var_expr(&l.to_string()); i]), + ]; + + let func = returning_func("foo", vec![param("a", t.clone()), param("b", t.clone())], vec![t.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..] + .replace('\n', "") + .replace("// Unlock statement started", "") + .replace("// Unlock statement ended", ""); + + let expected_rcode = format!("let mut {} = {};", l, l); + let expected_rcode = expected_rcode.repeat(i); + + let t_str = holy_type_to_rust_type_str(&t); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ {}}}", t_str, t_str, t_str, expected_rcode)); + } + } + } + } +} diff --git a/src/transpiler/reflective_tests/var_assign_tests.rs b/src/transpiler/reflective_tests/var_assign_tests.rs new file mode 100644 index 00000000..2e949249 --- /dev/null +++ b/src/transpiler/reflective_tests/var_assign_tests.rs @@ -0,0 +1,60 @@ +use super::*; + +#[cfg(test)] +mod var_assign_in_void_func_tests { + use super::*; + + #[test] + fn assign_all_bin_op() { + let literals = get_all_literals(); + + for l in literals { + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_assign("x", bin.clone()) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ x = {};}}", bin_str)); + } + } + } + + #[test] + fn assign_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for l in literals { + let body = vec![ + var_assign("x", l.clone()) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ x = {};}}", l_str)); + } + } + +} diff --git a/src/transpiler/reflective_tests/var_decl_tests.rs b/src/transpiler/reflective_tests/var_decl_tests.rs new file mode 100644 index 00000000..057d09c1 --- /dev/null +++ b/src/transpiler/reflective_tests/var_decl_tests.rs @@ -0,0 +1,1238 @@ +use super::*; + +#[cfg(test)] +mod var_decl_in_void_func_tests { + use super::*; + + #[test] + fn inited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t_str = holy_type_to_rust_type_str(&t); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![var_decl("x", t.clone(), bin.clone(), true)]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ let x: {} = {};}}", t_str, bin_str)); + } + } + } + + #[test] + fn uninited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t_str = holy_type_to_rust_type_str(&t); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![var_decl("x", t.clone(), bin.clone(), false)]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo() {{ let mut x: {} = {};}}", t_str, bin_str)); + } + } + } + + #[test] + fn inited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t.clone(), bl.clone(), true) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("fn foo() {{ let x: {} = {};}}", t_str, bl_str)); + } + } + + #[test] + fn uninited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t = Type::Bool; + let t_str = holy_type_to_rust_type_str(&t); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t.clone(), bl.clone(), false) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let bl_str = holy_expr_to_rust_expr(&bl); + + assert_eq!(rcode, format!("fn foo() {{ let mut x: {} = {};}}", t_str, bl_str)); + } + } + + #[test] + fn inited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + var_decl("x", t.clone(), l.clone(), true) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ let x: {} = {};}}", t_str, l_str)); + } + } + + #[test] + fn uninited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let body = vec![ + var_decl("x", t.clone(), l.clone(), false) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t_str = holy_type_to_rust_type_str(&t); + let l_str = holy_expr_to_rust_expr(&l); + + assert_eq!(rcode, format!("fn foo() {{ let mut x: {} = {};}}", t_str, l_str)); + } + } + + #[test] + fn inited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo() {{ let x: {} = {};}}", fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo() {{ let mut x: {} = {};}}", fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn inited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo() {{ let x: {} = {};}}", fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = void_func("foo", vec![], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + assert_eq!(rcode, format!("fn foo() {{ let mut x: {} = {};}}", fixed_arr_ty_str, l_arr_str)); + } + } + } +} + +#[cfg(test)] +mod var_decl_in_void_func_with_params_tests { + use super::*; + + #[test] + fn inited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_decl("x", t1.clone(), bin.clone(), true) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t1.clone()), param("b", t2.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let x: {} = {};}}", t1_str, t2_str, t1_str, bin_str)); + } + } + } + } + + #[test] + fn uninited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_decl("x", t1.clone(), bin.clone(), false) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t1.clone()), param("b", t2.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let mut x: {} = {};}}", t1_str, t2_str, t1_str, bin_str)); + } + } + } + } + + #[test] + fn inited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t1 = Type::Bool; + let t1_str = holy_type_to_rust_type_str(&t1); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t1.clone(), bl.clone(), true) + ]; + + let bl_str = holy_expr_to_rust_expr(&bl); + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let x: {} = {};}}", t2_str, t2_str, t1_str, bl_str)); + } + } + } + + + #[test] + fn uninited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t1 = Type::Bool; + let t1_str = holy_type_to_rust_type_str(&t1); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t1.clone(), bl.clone(), false) + ]; + + let bl_str = holy_expr_to_rust_expr(&bl); + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, bl_str)); + } + } + } + + #[test] + fn inited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let l1_str = holy_expr_to_rust_expr(&l1); + let t1_str = holy_type_to_rust_type_str(&t1); + + let body = vec![ + var_decl("x", t1.clone(), l1.clone(), true) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let x: {} = {};}}", t2_str, t2_str, t1_str, l1_str)); + } + } + } + + #[test] + fn uninited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let l1_str = holy_expr_to_rust_expr(&l1); + let t1_str = holy_type_to_rust_type_str(&t1); + + let body = vec![ + var_decl("x", t1.clone(), l1.clone(), false) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = void_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, l1_str)); + } + } + } + + #[test] + fn inited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = void_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = void_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let mut x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn inited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = void_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = void_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) {{ let mut x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + +} + + +// Same tests as above, except its now in a returning single type function. +// +#[cfg(test)] +mod var_decl_in_single_returning_func_with_params_tests { + use super::*; + + #[test] + fn inited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_decl("x", t1.clone(), bin.clone(), true) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, bin_str)); + } + } + } + } + + #[test] + fn uninited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_decl("x", t1.clone(), bin.clone(), false) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, bin_str)); + } + } + } + } + + #[test] + fn inited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t1 = Type::Bool; + let t1_str = holy_type_to_rust_type_str(&t1); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t1.clone(), bl.clone(), true) + ]; + + let bl_str = holy_expr_to_rust_expr(&bl); + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, bl_str)); + } + } + } + + + #[test] + fn uninited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t1 = Type::Bool; + let t1_str = holy_type_to_rust_type_str(&t1); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t1.clone(), bl.clone(), false) + ]; + + let bl_str = holy_expr_to_rust_expr(&bl); + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, bl_str)); + } + } + } + + + + #[test] + fn inited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let l1_str = holy_expr_to_rust_expr(&l1); + let t1_str = holy_type_to_rust_type_str(&t1); + + let body = vec![ + var_decl("x", t1.clone(), l1.clone(), true) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, l1_str)); + } + } + } + + #[test] + fn uninited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let l1_str = holy_expr_to_rust_expr(&l1); + let t1_str = holy_type_to_rust_type_str(&t1); + + let body = vec![ + var_decl("x", t1.clone(), l1.clone(), false) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone()], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, l1_str)); + } + } + } + + #[test] + fn inited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!( + rcode, + format!("fn foo(a: {}, b: {}) -> {} {{ let mut x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str) + ); + } + } + } + + #[test] + fn inited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> {} {{ let x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone()], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!( + rcode, + format!("fn foo(a: {}, b: {}) -> {} {{ let mut x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str) + ); + } + } + } + + + +} + + + + +// Same tests as above, except its now in a multi returning function. +// +#[cfg(test)] +mod var_decl_in_multi_returning_func_with_params_tests { + use super::*; + + #[test] + fn inited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_decl("x", t1.clone(), bin.clone(), true) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone(); 3], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, t1_str, t1_str, bin_str)); + } + } + } + } + + #[test] + fn uninited_var_all_bin_op() { + let literals = get_all_literals(); + + for (l, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let t1_str = holy_type_to_rust_type_str(&t1); + + for b in ALL_BIN_OP_KIND { + let bin = Expr::BinOp { + left: Box::new(l.clone()), + op: b, + right: Box::new(l.clone()), + span: span(), + }; + + let body = vec![ + var_decl("x", t1.clone(), bin.clone(), false) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone(); 3], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + let bin_str = holy_expr_to_rust_expr(&bin); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, t1_str, t1_str, bin_str)); + } + } + } + } + + #[test] + fn inited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t1 = Type::Bool; + let t1_str = holy_type_to_rust_type_str(&t1); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t1.clone(), bl.clone(), true) + ]; + + let bl_str = holy_expr_to_rust_expr(&bl); + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone(); 3], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, t1_str, t1_str, bl_str)); + } + } + } + + + #[test] + fn uninited_var_bincop_condition_bool() { + let boolean_conds = get_many_boolean_conditions(); + + let t1 = Type::Bool; + let t1_str = holy_type_to_rust_type_str(&t1); + + for bl in boolean_conds { + let body = vec![ + var_decl("x", t1.clone(), bl.clone(), false) + ]; + + let bl_str = holy_expr_to_rust_expr(&bl); + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone(); 3], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, t1_str, t1_str, bl_str)); + } + } + } + + #[test] + fn inited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let l1_str = holy_expr_to_rust_expr(&l1); + let t1_str = holy_type_to_rust_type_str(&t1); + + let body = vec![ + var_decl("x", t1.clone(), l1.clone(), true) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone(); 3], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, t1_str, t1_str, l1_str)); + } + } + } + + #[test] + fn uninited_var_literals_and_dynamic_arrays() { + let literals = get_all_literals(); + + for (l1, t1) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + let l1_str = holy_expr_to_rust_expr(&l1); + let t1_str = holy_type_to_rust_type_str(&t1); + + let body = vec![ + var_decl("x", t1.clone(), l1.clone(), false) + ]; + + for t2 in ALL_TYPES_WITH_DYN_ARR.iter() { + let func = returning_func("foo", vec![param("a", t2.clone()), param("b", t2.clone())], vec![t1.clone(); 3], body.clone()); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + let t2_str = holy_type_to_rust_type_str(&t2); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let mut x: {} = {};}}", t2_str, t2_str, t1_str, t1_str, t1_str, t1_str, l1_str)); + } + } + } + + #[test] + fn inited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone(); 3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_literal_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Literal(i)); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone(); 3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!( + rcode, + format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let mut x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str) + ); + } + } + } + + + #[test] + fn inited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), true) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone(); 3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!(rcode, format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str)); + } + } + } + + #[test] + fn uninited_var_fixed_arrays_with_const_size() { + let literals = get_all_literals(); + + for (l, t) in literals.iter().zip(ALL_TYPES_WITH_DYN_ARR.iter()) { + for i in 0usize..200usize { + let fixed_arr_ty = Type::FixedArray(Box::new(t.clone()), FixedArraySize::Const("s".to_string())); + let l_arr = array_lit(vec![l.clone(); i], Some(fixed_arr_ty.clone())); + + let fixed_arr_ty_str = holy_type_to_rust_type_str(&fixed_arr_ty); + let l_arr_str = holy_expr_to_rust_expr(&l_arr); + + let body = vec![ + var_decl("x", fixed_arr_ty.clone(), l_arr.clone(), false) + ]; + let func = returning_func("foo", vec![param("a", fixed_arr_ty.clone()), param("b", fixed_arr_ty.clone())], vec![fixed_arr_ty.clone(); 3], body); + let ast = &ast_one(func); + + let internals = import_internals(); + let rcode = transpile(ast); + assert!(rcode.starts_with(&internals)); + let rcode = rcode[internals.len()..].replace('\n', ""); + + assert_eq!( + rcode, + format!("fn foo(a: {}, b: {}) -> ({}, {}, {}) {{ let mut x: {} = {};}}", fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, fixed_arr_ty_str, l_arr_str) + ); + } + } + } + +} + + +