164 lines
5.8 KiB
Rust
164 lines
5.8 KiB
Rust
/*!
|
|
* WASM String Constants Test - Validates Issue #65 implementation
|
|
*
|
|
* Tests string constant support in WASM backend:
|
|
* - ConstValue::String handling in generate_const
|
|
* - Data segment generation for string literals
|
|
* - StringBox creation with proper layout
|
|
* - WAT generation includes data segments and string allocation
|
|
*/
|
|
|
|
use nyash_rust::mir::{
|
|
MirModule, MirFunction, FunctionSignature, MirType, EffectMask,
|
|
BasicBlock, BasicBlockId, ValueId, MirInstruction, ConstValue
|
|
};
|
|
use nyash_rust::backend::wasm::WasmBackend;
|
|
|
|
#[test]
|
|
fn test_wasm_string_constant_basic() {
|
|
// Build MIR equivalent to:
|
|
// function main() {
|
|
// %str = const "Hello, WASM!"
|
|
// return %str // Should return StringBox pointer
|
|
// }
|
|
|
|
let mut backend = WasmBackend::new();
|
|
let mir_module = build_string_const_mir_module();
|
|
|
|
// Generate WAT text for debugging
|
|
let wat_result = backend.compile_to_wat(mir_module.clone());
|
|
assert!(wat_result.is_ok(), "WAT generation should succeed for string constants");
|
|
|
|
let wat_text = wat_result.unwrap();
|
|
|
|
// Verify WAT contains expected elements for string support
|
|
assert!(wat_text.contains("(module"), "Should contain module declaration");
|
|
assert!(wat_text.contains("memory"), "Should contain memory declaration");
|
|
assert!(wat_text.contains("data"), "Should contain data segment for string literal");
|
|
assert!(wat_text.contains("\\48\\65\\6c\\6c\\6f"), "Should contain UTF-8 bytes for 'Hello'");
|
|
assert!(wat_text.contains("$alloc_stringbox"), "Should contain StringBox allocator");
|
|
assert!(wat_text.contains("print_str"), "Should contain print_str import");
|
|
|
|
// Verify string literal is properly embedded
|
|
// (The assertion for UTF-8 bytes is above)
|
|
|
|
// Compile to WASM binary
|
|
let wasm_result = backend.compile_module(mir_module);
|
|
if let Err(e) = &wasm_result {
|
|
println!("WASM compilation error: {}", e);
|
|
println!("Generated WAT:\n{}", wat_text);
|
|
}
|
|
assert!(wasm_result.is_ok(), "WASM compilation should succeed for string constants");
|
|
}
|
|
|
|
#[test]
|
|
fn test_wasm_string_constant_multiple() {
|
|
// Test multiple string constants to verify data segment management
|
|
// function main() {
|
|
// %str1 = const "First"
|
|
// %str2 = const "Second"
|
|
// %str3 = const "First" // Duplicate should reuse data segment
|
|
// return %str1
|
|
// }
|
|
|
|
let mut backend = WasmBackend::new();
|
|
let mir_module = build_multiple_string_const_mir_module();
|
|
|
|
let wat_result = backend.compile_to_wat(mir_module.clone());
|
|
assert!(wat_result.is_ok(), "WAT generation should succeed for multiple strings");
|
|
|
|
let wat_text = wat_result.unwrap();
|
|
|
|
// Should contain both unique strings (in hex format)
|
|
assert!(wat_text.contains("\\46\\69\\72\\73\\74"), "Should contain 'First' string in hex");
|
|
assert!(wat_text.contains("\\53\\65\\63\\6f\\6e\\64"), "Should contain 'Second' string in hex");
|
|
|
|
// Should have 2 data segments (First and Second, duplicate First reused)
|
|
let data_count = wat_text.matches("(data").count();
|
|
assert_eq!(data_count, 2, "Should have exactly 2 data segments for 2 unique strings");
|
|
|
|
let wasm_result = backend.compile_module(mir_module);
|
|
assert!(wasm_result.is_ok(), "WASM compilation should succeed for multiple strings");
|
|
}
|
|
|
|
/// Build a MIR module with a single string constant
|
|
fn build_string_const_mir_module() -> MirModule {
|
|
let mut module = MirModule::new("test_string_const".to_string());
|
|
|
|
// Create main function signature
|
|
let main_signature = FunctionSignature {
|
|
name: "main".to_string(),
|
|
params: vec![],
|
|
return_type: MirType::Integer, // StringBox pointer as i32
|
|
effects: EffectMask::PURE,
|
|
};
|
|
|
|
// Create basic block
|
|
let entry_block = BasicBlockId::new(0);
|
|
let mut main_function = MirFunction::new(main_signature, entry_block);
|
|
let mut block = BasicBlock::new(entry_block);
|
|
|
|
// %str = const "Hello, WASM!"
|
|
let str_value = ValueId::new(0);
|
|
block.instructions.push(MirInstruction::Const {
|
|
dst: str_value,
|
|
value: ConstValue::String("Hello, WASM!".to_string()),
|
|
});
|
|
|
|
// return %str
|
|
block.terminator = Some(MirInstruction::Return {
|
|
value: Some(str_value),
|
|
});
|
|
|
|
main_function.blocks.insert(entry_block, block);
|
|
|
|
module.functions.insert("main".to_string(), main_function);
|
|
module
|
|
}
|
|
|
|
/// Build a MIR module with multiple string constants
|
|
fn build_multiple_string_const_mir_module() -> MirModule {
|
|
let mut module = MirModule::new("test_multiple_strings".to_string());
|
|
|
|
let main_signature = FunctionSignature {
|
|
name: "main".to_string(),
|
|
params: vec![],
|
|
return_type: MirType::Integer,
|
|
effects: EffectMask::PURE,
|
|
};
|
|
|
|
let entry_block = BasicBlockId::new(0);
|
|
let mut main_function = MirFunction::new(main_signature, entry_block);
|
|
let mut block = BasicBlock::new(entry_block);
|
|
|
|
// %str1 = const "First"
|
|
let str1_value = ValueId::new(0);
|
|
block.instructions.push(MirInstruction::Const {
|
|
dst: str1_value,
|
|
value: ConstValue::String("First".to_string()),
|
|
});
|
|
|
|
// %str2 = const "Second"
|
|
let str2_value = ValueId::new(1);
|
|
block.instructions.push(MirInstruction::Const {
|
|
dst: str2_value,
|
|
value: ConstValue::String("Second".to_string()),
|
|
});
|
|
|
|
// %str3 = const "First" (duplicate)
|
|
let str3_value = ValueId::new(2);
|
|
block.instructions.push(MirInstruction::Const {
|
|
dst: str3_value,
|
|
value: ConstValue::String("First".to_string()),
|
|
});
|
|
|
|
// return %str1
|
|
block.terminator = Some(MirInstruction::Return {
|
|
value: Some(str1_value),
|
|
});
|
|
|
|
main_function.blocks.insert(entry_block, block);
|
|
|
|
module.functions.insert("main".to_string(), main_function);
|
|
module
|
|
} |