style: 减少自动格式化换行

This commit is contained in:
爱特每羊队
2026-06-09 00:53:46 +08:00
parent 4713b46d5c
commit 5d1d25074e
86 changed files with 672 additions and 2645 deletions
+1 -4
View File
@@ -37,10 +37,7 @@ fn eval_val(source: &str) -> (Vm, Result<JsValue, String>) {
fn to_str(vm: &Vm, val: JsValue) -> String {
if val.is_string() {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
} else {
format!("{}", val)
}
+1 -5
View File
@@ -24,11 +24,7 @@ fn bench_1m_property_reads() {
}
let elapsed = start.elapsed();
let ns_per = elapsed.as_nanos() as f64 / N as f64;
println!(
"1M IC property reads: {:.2}ms ({:.0} ns/read)",
elapsed.as_secs_f64() * 1000.0,
ns_per
);
println!("1M IC property reads: {:.2}ms ({:.0} ns/read)", elapsed.as_secs_f64() * 1000.0, ns_per);
if cfg!(debug_assertions) {
println!(" (debug build -- skipping timing assertion)");
} else {
@@ -5,11 +5,8 @@ use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<(Vm, JsValue), String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
let mut vm = Vm::new();
let result = vm.run(&module)?;
Ok((vm, result))
@@ -1,28 +1,20 @@
use oxide_compiler::compiler::Compiler;
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use oxide_vm::builtins::boolean::{
boolean_constructor, boolean_prototype_to_string, boolean_prototype_value_of,
};
use oxide_vm::builtins::boolean::{boolean_constructor, boolean_prototype_to_string, boolean_prototype_value_of};
use oxide_vm::vm::Vm;
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn str_val(vm: &Vm, val: JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
// -- direct native fn tests --
+4 -14
View File
@@ -3,19 +3,13 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<oxide_types::value::JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn str_val(vm: &Vm, val: oxide_types::value::JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
// -- static methods --
@@ -92,11 +86,7 @@ fn date_set_time() {
#[test]
fn date_set_full_year() {
let mut vm = Vm::new();
let r = eval(
&mut vm,
"var d = new Date(2020, 0, 1); d.setFullYear(2025); d.getFullYear()",
)
.unwrap();
let r = eval(&mut vm, "var d = new Date(2020, 0, 1); d.setFullYear(2025); d.getFullYear()").unwrap();
assert_eq!(r.as_double(), 2025.0);
}
+4 -21
View File
@@ -10,9 +10,7 @@ fn make_vm() -> Vm {
fn eval(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile: {}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
let mut vm = make_vm();
vm.run(&module)
}
@@ -140,22 +138,7 @@ fn reference_error_is_defined() {
#[test]
fn error_subtype_constructors_produce_named_objects() {
assert_eq!(
format!("{}", eval("new Error('boom').name == 'Error'").unwrap()),
"true"
);
assert_eq!(
format!(
"{}",
eval("new TypeError('boom').name == 'TypeError'").unwrap()
),
"true"
);
assert_eq!(
format!(
"{}",
eval("new SyntaxError('boom').name == 'SyntaxError'").unwrap()
),
"true"
);
assert_eq!(format!("{}", eval("new Error('boom').name == 'Error'").unwrap()), "true");
assert_eq!(format!("{}", eval("new TypeError('boom').name == 'TypeError'").unwrap()), "true");
assert_eq!(format!("{}", eval("new SyntaxError('boom').name == 'SyntaxError'").unwrap()), "true");
}
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
@@ -38,11 +35,7 @@ fn function_to_string_includes_function() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.max.toString()").unwrap();
assert!(result.is_string());
let rendered = vm
.kernel()
.string_forge()
.lookup(result.as_string_index())
.unwrap_or_default();
let rendered = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
assert!(rendered.contains("function"), "got: {}", rendered);
}
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<oxide_types::value::JsValue, String> {
let allocator = Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
let mut vm = Vm::new();
vm.run(&module)
}
+5 -17
View File
@@ -1,25 +1,17 @@
use oxide_compiler::compiler::Compiler;
use oxide_types::value::JsValue;
use oxide_vm::builtins::map::{
map_clear, map_constructor as new_map, map_delete, map_get, map_has, map_set, map_size,
};
use oxide_vm::builtins::map::{map_clear, map_constructor as new_map, map_delete, map_get, map_has, map_set, map_size};
use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn str_val(vm: &Vm, val: JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
// -- direct native fn tests --
@@ -101,10 +93,6 @@ fn map_new_has() {
#[test]
fn map_new_delete() {
let mut vm = Vm::new();
let r = eval(
&mut vm,
"var m = new Map(); m.set('x', 10); m.delete('x'); m.has('x')",
)
.unwrap();
let r = eval(&mut vm, "var m = new Map(); m.set('x', 10); m.delete('x'); m.has('x')").unwrap();
assert!(!r.as_bool());
}
+2 -5
View File
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
+7 -29
View File
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
@@ -79,11 +76,7 @@ fn number_constructor() {
fn to_string_of_number() {
let mut vm = Vm::new();
let result = eval(&mut vm, "var n = 42; n.toString()").unwrap();
let s = vm
.kernel()
.string_forge()
.lookup(result.as_string_index())
.unwrap_or_default();
let s = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
assert_eq!(s, "42");
}
@@ -91,11 +84,7 @@ fn to_string_of_number() {
fn to_fixed_of_number() {
let mut vm = Vm::new();
let result = eval(&mut vm, "var n = 3.14159; n.toFixed(2)").unwrap();
let s = vm
.kernel()
.string_forge()
.lookup(result.as_string_index())
.unwrap_or_default();
let s = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
assert_eq!(s, "3.14");
}
@@ -124,24 +113,13 @@ fn number_epsilon_is_positive() {
fn number_to_exponential() {
let mut vm = Vm::new();
let result = eval(&mut vm, "var n = 123.456; n.toExponential(2)").unwrap();
let s = vm
.kernel()
.string_forge()
.lookup(result.as_string_index())
.unwrap_or_default();
let s = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
assert_eq!(s, "1.23e2");
}
#[test]
fn number_static_constants_remain_bound() {
let mut vm = Vm::new();
assert_eq!(
eval(&mut vm, "Number.MAX_SAFE_INTEGER")
.unwrap()
.as_double(),
9007199254740991f64
);
assert!(eval(&mut vm, "Number.POSITIVE_INFINITY > 0")
.unwrap()
.as_bool());
assert_eq!(eval(&mut vm, "Number.MAX_SAFE_INTEGER").unwrap().as_double(), 9007199254740991f64);
assert!(eval(&mut vm, "Number.POSITIVE_INFINITY > 0").unwrap().as_bool());
}
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<(Vm, JsValue), String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
let mut vm = Vm::new();
let result = vm.run(&module)?;
Ok((vm, result))
+4 -14
View File
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn to_str(vm: &Vm, val: JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
// --- RegExp constructor ---
@@ -154,11 +148,7 @@ fn regexp_exec_global_last_index_advances() {
#[test]
fn regexp_exec_global_resets_on_exhaustion() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var re = /a/g; re.exec('a'); re.exec('a') === null",
)
.unwrap();
let result = eval(&mut vm, "var re = /a/g; re.exec('a'); re.exec('a') === null").unwrap();
assert!(result.as_bool());
}
+4 -13
View File
@@ -1,17 +1,12 @@
use oxide_compiler::compiler::Compiler;
use oxide_types::value::JsValue;
use oxide_vm::builtins::set::{
set_add, set_clear, set_constructor as new_set, set_delete, set_has, set_size,
};
use oxide_vm::builtins::set::{set_add, set_clear, set_constructor as new_set, set_delete, set_has, set_size};
use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
@@ -119,10 +114,6 @@ fn set_new_has_missing() {
#[test]
fn set_new_delete() {
let mut vm = Vm::new();
let r = eval(
&mut vm,
"var s = new Set(); s.add(1); s.add(2); s.delete(1); s.has(1)",
)
.unwrap();
let r = eval(&mut vm, "var s = new Set(); s.add(1); s.add(2); s.delete(1); s.has(1)").unwrap();
assert!(!r.as_bool());
}
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn to_str(vm: &Vm, val: JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
#[test]
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn to_str(vm: &Vm, val: JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
// --- Symbol constructor ---
+8 -32
View File
@@ -38,26 +38,17 @@ fn eval_not_falsy() {
#[test]
fn test_same_value_signed_zero() {
assert!(!coercion::same_value(
JsValue::float(0.0),
JsValue::float(-0.0)
));
assert!(!coercion::same_value(JsValue::float(0.0), JsValue::float(-0.0)));
}
#[test]
fn test_strict_equality_signed_zero() {
assert!(coercion::strict_equality(
JsValue::float(0.0),
JsValue::float(-0.0)
));
assert!(coercion::strict_equality(JsValue::float(0.0), JsValue::float(-0.0)));
}
#[test]
fn test_same_value_nan() {
assert!(coercion::same_value(
JsValue::float(f64::NAN),
JsValue::float(f64::NAN)
));
assert!(coercion::same_value(JsValue::float(f64::NAN), JsValue::float(f64::NAN)));
}
#[test]
@@ -73,36 +64,21 @@ fn test_same_value_int_float_equal() {
#[test]
fn test_strict_equality_nan() {
assert!(!coercion::strict_equality(
JsValue::float(f64::NAN),
JsValue::float(f64::NAN)
));
assert!(!coercion::strict_equality(JsValue::float(f64::NAN), JsValue::float(f64::NAN)));
}
#[test]
fn test_strict_equality_type_mismatch() {
assert!(!coercion::strict_equality(
JsValue::int(1),
JsValue::bool(true)
));
assert!(!coercion::strict_equality(JsValue::int(1), JsValue::bool(true)));
}
#[test]
fn test_strict_equality_int_float_equal() {
assert!(coercion::strict_equality(
JsValue::int(1),
JsValue::float(1.0)
));
assert!(!coercion::strict_equality(
JsValue::int(1),
JsValue::float(2.0)
));
assert!(coercion::strict_equality(JsValue::int(1), JsValue::float(1.0)));
assert!(!coercion::strict_equality(JsValue::int(1), JsValue::float(2.0)));
}
#[test]
fn test_strict_equality_null_undefined() {
assert!(!coercion::strict_equality(
JsValue::null(),
JsValue::undefined()
));
assert!(!coercion::strict_equality(JsValue::null(), JsValue::undefined()));
}
+11 -44
View File
@@ -61,18 +61,12 @@ fn eval_while_result_undefined() {
#[test]
fn eval_for_basic() {
assert_eq!(
eval("var r = 0; for (i = 0; i < 3; i = i + 1) { r = r + i; } r"),
"3"
);
assert_eq!(eval("var r = 0; for (i = 0; i < 3; i = i + 1) { r = r + i; } r"), "3");
}
#[test]
fn eval_for_no_test() {
assert_eq!(
eval("var r = 0; for (i = 0; ; i = i + 1) { if (i >= 3) { break; } r = r + i; } r"),
"3"
);
assert_eq!(eval("var r = 0; for (i = 0; ; i = i + 1) { if (i >= 3) { break; } r = r + i; } r"), "3");
}
#[test]
@@ -97,10 +91,7 @@ fn eval_ternary_nested() {
#[test]
fn eval_break_in_while() {
assert_eq!(
eval("var i = 0; while (true) { i = i + 1; if (i >= 3) { break; } } i"),
"3"
);
assert_eq!(eval("var i = 0; while (true) { i = i + 1; if (i >= 3) { break; } } i"), "3");
}
#[test]
@@ -155,10 +146,7 @@ fn eval_do_while_multi_iteration() {
#[test]
fn eval_do_while_break() {
assert_eq!(
eval("var i = 0; do { i = i + 1; if (i >= 3) break; } while (true); i"),
"3"
);
assert_eq!(eval("var i = 0; do { i = i + 1; if (i >= 3) break; } while (true); i"), "3");
}
#[test]
@@ -182,34 +170,22 @@ fn eval_for_in_empty_object() {
#[test]
fn eval_for_in_non_object_throws() {
let result = eval("for (k in 42) {}");
assert!(
result.contains("TypeError"),
"expected TypeError, got: {result}"
);
assert!(result.contains("TypeError"), "expected TypeError, got: {result}");
}
#[test]
fn eval_for_in_nested() {
assert_eq!(
eval("var r=0; for (k in {a:{x:1}}) { for (j in {y:2}) { r=r+1; } } r"),
"2"
);
assert_eq!(eval("var r=0; for (k in {a:{x:1}}) { for (j in {y:2}) { r=r+1; } } r"), "2");
}
#[test]
fn eval_for_in_break() {
assert_eq!(
eval("var r=0; for (k in {a:1,b:2,c:3}) { if (k=='b') break; r=r+1; } r"),
"1"
);
assert_eq!(eval("var r=0; for (k in {a:1,b:2,c:3}) { if (k=='b') break; r=r+1; } r"), "1");
}
#[test]
fn eval_for_in_continue() {
assert_eq!(
eval("var r=0; for (k in {a:1,b:2}) { if (k=='a') continue; r=r+1; } r"),
"2"
);
assert_eq!(eval("var r=0; for (k in {a:1,b:2}) { if (k=='a') continue; r=r+1; } r"), "2");
}
#[test]
@@ -220,10 +196,7 @@ fn eval_for_in_let_scoping() {
#[test]
fn eval_switch_basic_match() {
assert_eq!(
eval("var x=0;switch(2){case 1:x=10;case 2:x=20;break;default:x=30;}x"),
"20"
);
assert_eq!(eval("var x=0;switch(2){case 1:x=10;case 2:x=20;break;default:x=30;}x"), "20");
}
#[test]
@@ -243,18 +216,12 @@ fn eval_switch_no_match_no_default() {
#[test]
fn eval_switch_break() {
assert_eq!(
eval("var x=0;switch(1){case 1:x=10;break;case 2:x=20;}x"),
"10"
);
assert_eq!(eval("var x=0;switch(1){case 1:x=10;break;case 2:x=20;}x"), "10");
}
#[test]
fn eval_break_in_switch_in_loop() {
assert_eq!(
eval("var r=0;while(true){switch(1){case 1:r=1;break;}r=2;break;}r"),
"2"
);
assert_eq!(eval("var r=0;while(true){switch(1){case 1:r=1;break;}r=2;break;}r"), "2");
}
#[test]
+8 -35
View File
@@ -4,11 +4,8 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
@@ -61,11 +58,7 @@ fn fe_basic() {
#[test]
fn fe_with_params() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var mul = function(x,y) { return x * y; }; mul(6, 7)",
)
.unwrap();
let result = eval(&mut vm, "var mul = function(x,y) { return x * y; }; mul(6, 7)").unwrap();
assert!((result.as_double() - 42.0).abs() < 0.0001);
}
@@ -74,22 +67,14 @@ fn fe_with_params() {
#[test]
fn cross_func_call() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function a() { return 1; } function b() { return a() + 2; } b()",
)
.unwrap();
let result = eval(&mut vm, "function a() { return 1; } function b() { return a() + 2; } b()").unwrap();
assert!((result.as_double() - 3.0).abs() < 0.0001);
}
#[test]
fn two_funcs_called_from_global() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function a() { return 1; } function b() { return 2; } a() + b()",
)
.unwrap();
let result = eval(&mut vm, "function a() { return 1; } function b() { return 2; } a() + b()").unwrap();
assert!(result.is_double(), "expected double, got: {:?}", result);
assert!((result.as_double() - 3.0).abs() < 0.0001);
}
@@ -147,11 +132,7 @@ fn fd_calls_builtin_two_args() {
#[test]
fn fd_chain_call() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function a() { return 10; } function b() { return a(); } b()",
)
.unwrap();
let result = eval(&mut vm, "function a() { return 10; } function b() { return a(); } b()").unwrap();
assert_eq!(result.as_int(), 10);
}
@@ -177,11 +158,7 @@ fn fd_returns_new_array() {
fn this_in_function_reads_value() {
let mut vm = Vm::new();
let result = eval(&mut vm, "function f() { return this; } f()").unwrap();
assert!(
result.is_object(),
"expected object (function as this), got: {:?}",
result
);
assert!(result.is_object(), "expected object (function as this), got: {:?}", result);
}
#[test]
@@ -201,10 +178,6 @@ fn this_member_access() {
#[test]
fn this_in_constructor_sets_proto() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function Ctor(m) { this.message = m; } Ctor.prototype = new Object(); 1",
)
.unwrap();
let result = eval(&mut vm, "function Ctor(m) { this.message = m; } Ctor.prototype = new Object(); 1").unwrap();
assert_eq!(result.as_int(), 1);
}
+5 -19
View File
@@ -4,19 +4,13 @@ use oxide_vm::vm::Vm;
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program =
oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile error: {}", e))?;
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
vm.run(&module)
}
fn string_value(vm: &Vm, val: JsValue) -> String {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
}
// -- JSON.parse --
@@ -90,11 +84,7 @@ fn json_parse_null() {
#[test]
fn json_parse_nested() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"JSON.parse('{\"a\":1,\"b\":[1,2],\"c\":{\"d\":\"hello\"}}')",
)
.unwrap();
let result = eval(&mut vm, "JSON.parse('{\"a\":1,\"b\":[1,2],\"c\":{\"d\":\"hello\"}}')").unwrap();
assert!(result.is_object());
}
@@ -200,11 +190,7 @@ fn json_parse_stringify_roundtrip() {
#[test]
fn json_roundtrip_array() {
let mut vm = Vm::new();
let _ = eval(
&mut vm,
"var arr = JSON.parse(JSON.stringify([1,2,3])); arr",
)
.unwrap();
let _ = eval(&mut vm, "var arr = JSON.parse(JSON.stringify([1,2,3])); arr").unwrap();
}
// -- Edge cases --
+1 -4
View File
@@ -43,10 +43,7 @@ fn epoch_benchmark_1m_allocations() {
let elapsed = start.elapsed();
if cfg!(debug_assertions) {
println!(
"1M allocations took {}ms (debug build - skipping timing assertion)",
elapsed.as_millis()
);
println!("1M allocations took {}ms (debug build - skipping timing assertion)", elapsed.as_millis());
} else {
assert!(
elapsed.as_millis() < 200,
+26 -131
View File
@@ -5,9 +5,7 @@ use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile: {}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
let mut vm = Vm::new();
vm.run(&module)
}
@@ -15,36 +13,21 @@ fn eval(source: &str) -> Result<JsValue, String> {
macro_rules! assert_bool {
($expr:expr, $expected:expr, $msg:expr) => {
let r = $expr.unwrap();
assert!(
r.is_bool() && r.as_bool() == $expected,
"{}: expected {}, got {:?}",
$msg,
$expected,
r
);
assert!(r.is_bool() && r.as_bool() == $expected, "{}: expected {}, got {:?}", $msg, $expected, r);
};
}
macro_rules! assert_undefined {
($expr:expr, $msg:expr) => {
let r = $expr.unwrap();
assert!(
r.is_undefined(),
"{}: expected undefined, got {:?}",
$msg,
r
);
assert!(r.is_undefined(), "{}: expected undefined, got {:?}", $msg, r);
};
}
// -- Proto chains: every (non-Object) constructor.prototype should inherit from Object.prototype --
#[test]
fn array_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Array.prototype) === Object.prototype"),
true,
"Array proto"
);
assert_bool!(eval("Object.getPrototypeOf(Array.prototype) === Object.prototype"), true, "Array proto");
}
#[test]
@@ -57,20 +40,12 @@ fn function_proto_chain() {
#[test]
fn string_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(String.prototype) === Object.prototype"),
true,
"String proto"
);
assert_bool!(eval("Object.getPrototypeOf(String.prototype) === Object.prototype"), true, "String proto");
}
#[test]
fn number_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Number.prototype) === Object.prototype"),
true,
"Number proto"
);
assert_bool!(eval("Object.getPrototypeOf(Number.prototype) === Object.prototype"), true, "Number proto");
}
#[test]
@@ -84,56 +59,32 @@ fn boolean_proto_chain() {
#[test]
fn error_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Error.prototype) === Object.prototype"),
true,
"Error proto"
);
assert_bool!(eval("Object.getPrototypeOf(Error.prototype) === Object.prototype"), true, "Error proto");
}
#[test]
fn symbol_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Symbol.prototype) === Object.prototype"),
true,
"Symbol proto"
);
assert_bool!(eval("Object.getPrototypeOf(Symbol.prototype) === Object.prototype"), true, "Symbol proto");
}
#[test]
fn date_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Date.prototype) === Object.prototype"),
true,
"Date proto"
);
assert_bool!(eval("Object.getPrototypeOf(Date.prototype) === Object.prototype"), true, "Date proto");
}
#[test]
fn set_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Set.prototype) === Object.prototype"),
true,
"Set proto"
);
assert_bool!(eval("Object.getPrototypeOf(Set.prototype) === Object.prototype"), true, "Set proto");
}
#[test]
fn map_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(Map.prototype) === Object.prototype"),
true,
"Map proto"
);
assert_bool!(eval("Object.getPrototypeOf(Map.prototype) === Object.prototype"), true, "Map proto");
}
#[test]
fn regexp_proto_chain() {
assert_bool!(
eval("Object.getPrototypeOf(RegExp.prototype) === Object.prototype"),
true,
"RegExp proto"
);
assert_bool!(eval("Object.getPrototypeOf(RegExp.prototype) === Object.prototype"), true, "RegExp proto");
}
// -- Object.prototype is the root, its __proto__ is null --
@@ -147,20 +98,12 @@ fn object_proto_is_root() {
#[test]
fn array_instanceof_object() {
assert_bool!(eval("[] instanceof Object"), true, "[] instanceof Object");
assert_bool!(
eval("new Array() instanceof Object"),
true,
"new Array instanceof Object"
);
assert_bool!(eval("new Array() instanceof Object"), true, "new Array instanceof Object");
}
#[test]
fn function_instanceof_object() {
assert_bool!(
eval("(function() {}) instanceof Object"),
true,
"function instanceof Object"
);
assert_bool!(eval("(function() {}) instanceof Object"), true, "function instanceof Object");
}
#[test]
@@ -179,110 +122,62 @@ fn boolean_not_instanceof_function() {
#[test]
fn number_instanceof_object() {
assert_bool!(
eval("new Number(1) instanceof Object"),
true,
"new Number instanceof Object"
);
assert_bool!(eval("new Number(1) instanceof Object"), true, "new Number instanceof Object");
}
#[test]
fn boolean_instanceof_object() {
assert_bool!(
eval("new Boolean(true) instanceof Object"),
true,
"new Boolean instanceof Object"
);
assert_bool!(eval("new Boolean(true) instanceof Object"), true, "new Boolean instanceof Object");
}
#[test]
fn error_instanceof_object() {
assert_bool!(
eval("new Error() instanceof Object"),
true,
"new Error instanceof Object"
);
assert_bool!(eval("new Error() instanceof Object"), true, "new Error instanceof Object");
}
#[test]
fn date_instanceof_object() {
assert_bool!(
eval("new Date() instanceof Object"),
true,
"new Date instanceof Object"
);
assert_bool!(eval("new Date() instanceof Object"), true, "new Date instanceof Object");
}
#[test]
fn set_instanceof_object() {
assert_bool!(
eval("new Set() instanceof Object"),
true,
"new Set instanceof Object"
);
assert_bool!(eval("new Set() instanceof Object"), true, "new Set instanceof Object");
}
#[test]
fn map_instanceof_object() {
assert_bool!(
eval("new Map() instanceof Object"),
true,
"new Map instanceof Object"
);
assert_bool!(eval("new Map() instanceof Object"), true, "new Map instanceof Object");
}
#[test]
fn regexp_instanceof_object() {
assert_bool!(eval("/a/ instanceof Object"), true, "/a/ instanceof Object");
assert_bool!(
eval("new RegExp('a') instanceof Object"),
true,
"new RegExp instanceof Object"
);
assert_bool!(eval("new RegExp('a') instanceof Object"), true, "new RegExp instanceof Object");
}
#[test]
fn object_instanceof_object() {
assert_bool!(
eval("({}) instanceof Object"),
true,
"({}) instanceof Object"
);
assert_bool!(eval("({}) instanceof Object"), true, "({}) instanceof Object");
}
// -- instanceof for native types should NOT respond to their own false positives --
#[test]
fn number_not_instanceof_array() {
assert_bool!(
eval("new Number(1) instanceof Array"),
false,
"Number instanceof Array"
);
assert_bool!(eval("new Number(1) instanceof Array"), false, "Number instanceof Array");
}
#[test]
fn object_not_instanceof_regexp() {
assert_bool!(
eval("({}) instanceof RegExp"),
false,
"({}) instanceof RegExp"
);
assert_bool!(eval("({}) instanceof RegExp"), false, "({}) instanceof RegExp");
}
// -- Primitives should NOT be instanceof their wrapper constructors (no autoboxing) --
#[test]
fn primitives_not_instanceof() {
assert_bool!(eval("1 instanceof Number"), false, "1 instanceof Number");
assert_bool!(
eval("'hi' instanceof String"),
false,
"'hi' instanceof String"
);
assert_bool!(
eval("true instanceof Boolean"),
false,
"true instanceof Boolean"
);
assert_bool!(eval("'hi' instanceof String"), false, "'hi' instanceof String");
assert_bool!(eval("true instanceof Boolean"), false, "true instanceof Boolean");
}
// -- VOID regression --
+10 -41
View File
@@ -42,11 +42,7 @@ fn eval_with_kernel(source: &str, kernel: Arc<OxideKernel>) -> String {
#[test]
fn regression_to_boolean_empty_string() {
assert_eq!(eval("!''"), "true", "NOT empty string should be true");
assert_eq!(
eval("if ('') { 1 } else { 2 }"),
"2",
"empty string should be falsy"
);
assert_eq!(eval("if ('') { 1 } else { 2 }"), "2", "empty string should be falsy");
}
#[test]
@@ -71,19 +67,13 @@ fn regression_rerun_clears_ic_cache() {
#[test]
fn regression_recursion_depth_limit() {
assert_eq!(
eval("function f(){f()} f()"),
"vm error: RangeError: Maximum call stack size exceeded"
);
assert_eq!(eval("function f(){f()} f()"), "vm error: RangeError: Maximum call stack size exceeded");
}
#[test]
fn regression_throw_statement_errors() {
let result = eval("throw 'error'");
assert!(
result.contains("uncaught"),
"expected uncaught, got: {result}"
);
assert!(result.contains("uncaught"), "expected uncaught, got: {result}");
assert!(
result.contains("uncaught Error"),
"expected string throw to default to Error, got: {result}"
@@ -92,14 +82,8 @@ fn regression_throw_statement_errors() {
#[test]
fn regression_throw_statement_preserves_type_error_kind() {
assert_eq!(
eval("try { throw new TypeError('boom') } catch (e) { e.name == 'TypeError' }"),
"true"
);
assert_eq!(
eval("throw new TypeError('boom')"),
"vm error: uncaught TypeError: {object}"
);
assert_eq!(eval("try { throw new TypeError('boom') } catch (e) { e.name == 'TypeError' }"), "true");
assert_eq!(eval("throw new TypeError('boom')"), "vm error: uncaught TypeError: {object}");
}
#[test]
@@ -108,10 +92,7 @@ fn regression_throw_statement_preserves_syntax_error_kind() {
eval("try { throw new SyntaxError('boom') } catch (e) { e.name == 'SyntaxError' }"),
"true"
);
assert_eq!(
eval("throw new SyntaxError('boom')"),
"vm error: uncaught SyntaxError: {object}"
);
assert_eq!(eval("throw new SyntaxError('boom')"), "vm error: uncaught SyntaxError: {object}");
}
#[test]
@@ -155,24 +136,12 @@ fn regression_new_expression_bytecode_constructor_error_is_catchable() {
#[test]
fn regression_delete_static_property_throws_type_error() {
assert_eq!(
eval("try { var o={x:1}; delete o.x; 0 } catch (e) { e.name == 'TypeError' }"),
"true"
);
assert_eq!(
eval("var o={x:1}; delete o.x"),
"vm error: uncaught TypeError: {object}"
);
assert_eq!(eval("try { var o={x:1}; delete o.x; 0 } catch (e) { e.name == 'TypeError' }"), "true");
assert_eq!(eval("var o={x:1}; delete o.x"), "vm error: uncaught TypeError: {object}");
}
#[test]
fn regression_delete_dynamic_property_throws_type_error() {
assert_eq!(
eval("try { var o={x:1}; delete o['x']; 0 } catch (e) { e.name == 'TypeError' }"),
"true"
);
assert_eq!(
eval("var o={x:1}; var k='x'; delete o[k]"),
"vm error: uncaught TypeError: {object}"
);
assert_eq!(eval("try { var o={x:1}; delete o['x']; 0 } catch (e) { e.name == 'TypeError' }"), "true");
assert_eq!(eval("var o={x:1}; var k='x'; delete o[k]"), "vm error: uncaught TypeError: {object}");
}
+2 -8
View File
@@ -5,9 +5,7 @@ use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
let module = Compiler::new()
.compile(&program)
.map_err(|e| format!("Compile: {}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
let mut vm = Vm::new();
vm.run(&module)
}
@@ -23,11 +21,7 @@ fn const_reassignment_throws() {
let result = eval("const x = 1; x = 2");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.contains("TypeError") || err.contains("constant"),
"got: {}",
err
);
assert!(err.contains("TypeError") || err.contains("constant"), "got: {}", err);
}
#[test]
+3 -13
View File
@@ -37,10 +37,7 @@ fn eval_val(source: &str) -> (Vm, Result<JsValue, String>) {
fn to_str(vm: &Vm, val: JsValue) -> String {
if val.is_string() {
vm.kernel()
.string_forge()
.lookup(val.as_string_index())
.unwrap_or_default()
vm.kernel().string_forge().lookup(val.as_string_index()).unwrap_or_default()
} else {
format!("{}", val)
}
@@ -99,11 +96,7 @@ fn tagged_template_basic() {
// This avoids bytecode function call complexity.
let result = eval("Math.max`hello ${42} world`");
// Math.max on the args should work - just verify it doesn't crash
assert!(
!result.starts_with("vm error:"),
"Tagged template should not crash, got: {}",
result
);
assert!(!result.starts_with("vm error:"), "Tagged template should not crash, got: {}", result);
}
#[test]
@@ -111,8 +104,5 @@ fn tagged_template_compiles_no_error() {
// Verify that tagged templates compile without error (even if the tag
// function behavior isn't fully tested)
let result = eval("function t(s,v){ return s[0]+v; } t`x${1}`");
assert!(
!result.starts_with("compile error:"),
"Tagged template should compile"
);
assert!(!result.starts_with("compile error:"), "Tagged template should compile");
}
+1 -3
View File
@@ -121,9 +121,7 @@ fn as_js_object_ptr_non_object_returns_null() {
assert!(JsValue::null().as_js_object_ptr().is_null());
assert!(JsValue::undefined().as_js_object_ptr().is_null());
let x = 42u8;
assert!(!JsValue::object(&x as *const u8)
.as_js_object_ptr()
.is_null());
assert!(!JsValue::object(&x as *const u8).as_js_object_ptr().is_null());
}
#[test]
+6 -24
View File
@@ -27,10 +27,7 @@ fn test_throw_caught_by_catch() {
#[test]
fn test_throw_without_catch() {
let result = eval("throw 'err';");
assert!(
result.contains("uncaught"),
"expected uncaught, got: {result}"
);
assert!(result.contains("uncaught"), "expected uncaught, got: {result}");
}
#[test]
@@ -41,34 +38,22 @@ fn test_try_finally_normal_path() {
#[test]
fn test_try_finally_exception_path() {
let result = eval("var x = 0; try { throw 1; } finally { x = 2; }");
assert!(
result.contains("uncaught"),
"expected uncaught, got: {result}"
);
assert!(result.contains("uncaught"), "expected uncaught, got: {result}");
}
#[test]
fn test_nested_try_inner_catches() {
assert_eq!(
eval("try { try { throw 1; } catch(e) { e; } } catch(e) { 2; }"),
"1"
);
assert_eq!(eval("try { try { throw 1; } catch(e) { e; } } catch(e) { 2; }"), "1");
}
#[test]
fn test_nested_try_outer_catches() {
assert_eq!(
eval("try { try { throw 1; } catch(e) { throw 2; } } catch(e) { e; }"),
"2"
);
assert_eq!(eval("try { try { throw 1; } catch(e) { throw 2; } } catch(e) { e; }"), "2");
}
#[test]
fn test_try_catch_finally() {
assert_eq!(
eval("var x = 0; try { x = 1; } catch(e) { x = 2; } finally { x = 3; } x;"),
"3"
);
assert_eq!(eval("var x = 0; try { x = 1; } catch(e) { x = 2; } finally { x = 3; } x;"), "3");
}
#[test]
@@ -92,8 +77,5 @@ fn test_throw_err_type_error_is_object() {
#[test]
fn test_uncaught_type_error_message() {
let result = eval("null.prop;");
assert!(
result.contains("TypeError"),
"expected TypeError in message, got: {result}"
);
assert!(result.contains("TypeError"), "expected TypeError in message, got: {result}");
}