#![cfg(any(
not(any(
feature = "parser_tests",
feature = "analyzer_tests",
feature = "codegen_tests",
feature = "interpreter_tests",
feature = "conformance_tests",
feature = "integration_tests",
)),
feature = "analyzer_tests",
))]
use windjammer::analyzer::Analyzer;
use windjammer::codegen::rust::CodeGenerator;
use windjammer::lexer::Lexer;
use windjammer::parser::{Parser, Program};
use windjammer::CompilationTarget;
fn parse_code(code: &str) -> Program<'static> {
let mut lexer = Lexer::new(code);
let tokens = lexer.tokenize_with_locations();
let parser = Box::leak(Box::new(Parser::new(tokens)));
parser.parse().unwrap()
}
#[test]
fn test_string_literal_in_struct_constructor_with_str_param() {
let code = r#"
struct Sound {
handle: int,
}
impl Sound {
pub fn load(path: string) -> Sound {
Sound { handle: 0 }
}
}
struct SoundLibrary {
jump: Sound,
}
impl SoundLibrary {
pub fn new() -> SoundLibrary {
SoundLibrary { jump: Sound::load("assets/jump.ogg") }
}
}
"#;
let program = parse_code(code);
let mut analyzer = Analyzer::new();
let (analyzed_functions, analyzed_structs, _analyzed_trait_methods) =
analyzer.analyze_program(&program).unwrap();
let mut generator = CodeGenerator::new_for_module(analyzed_structs, CompilationTarget::Rust);
let generated = generator.generate_program(&program, &analyzed_functions);
assert!(
!generated.contains("\"assets/jump.ogg\".to_string()"),
"Compiler should NOT add .to_string() when function expects &str!"
);
assert!(
generated.contains("Sound::load(\"assets/jump.ogg\")"),
"Compiler should pass string literals directly as &str!"
);
}
#[test]
fn test_string_literal_in_nested_struct_constructor() {
let code = r#"
struct Sound {
path: string,
}
impl Sound {
pub fn new(path: string) -> Sound {
Sound { path: path.to_string() }
}
}
struct Library {
sounds: Vec<Sound>,
}
impl Library {
pub fn create() -> Library {
Library {
sounds: vec![
Sound::new("jump.ogg"),
Sound::new("land.ogg"),
Sound::new("coin.ogg"),
]
}
}
}
"#;
let program = parse_code(code);
let mut analyzer = Analyzer::new();
let (analyzed_functions, analyzed_structs, _analyzed_trait_methods) =
analyzer.analyze_program(&program).unwrap();
let mut generator = CodeGenerator::new_for_module(analyzed_structs, CompilationTarget::Rust);
let generated = generator.generate_program(&program, &analyzed_functions);
assert!(
generated.contains("Sound::new(\"jump.ogg\")")
&& generated.contains("Sound::new(\"land.ogg\")")
&& generated.contains("Sound::new(\"coin.ogg\")"),
"Compiler should pass string literals directly as &str at call site!\n{}",
generated
);
}
#[test]
fn test_string_owned_parameter_does_add_to_string() {
let code = r#"
struct Config {
name: string,
}
impl Config {
pub fn new(name: string) -> Config {
Config { name }
}
}
struct App {
config: Config,
}
impl App {
pub fn create() -> App {
App { config: Config::new("MyApp") }
}
}
"#;
let program = parse_code(code);
let mut analyzer = Analyzer::new();
let (analyzed_functions, analyzed_structs, _analyzed_trait_methods) =
analyzer.analyze_program(&program).unwrap();
let mut generator = CodeGenerator::new_for_module(analyzed_structs, CompilationTarget::Rust);
let generated = generator.generate_program(&program, &analyzed_functions);
assert!(
generated.contains("Config::new(\"MyApp\")"),
"Compiler should pass string literal directly as &str when stored only in struct literal.\n{}",
generated
);
assert!(
!generated.contains("\"MyApp\".to_string()"),
"Should not add .to_string() at call site for struct-literal-stored &str param"
);
}