style: 自动格式化

This commit is contained in:
爱特每羊队
2026-06-08 20:09:00 +08:00
parent 209374fc02
commit fe3dd80bc5
20 changed files with 454 additions and 156 deletions
+1 -1
View File
@@ -6,9 +6,9 @@ use crate::symbol_table::{Binding, SymbolTable};
pub use crate::hash::structural_hash; pub use crate::hash::structural_hash;
pub use crate::module::Constant; pub use crate::module::Constant;
use crate::symbol_table::ScopeKind;
pub use oxide_parser::VariableDeclarationKind; pub use oxide_parser::VariableDeclarationKind;
pub use oxide_parser::{AssignmentOperator, BinaryOperator, Expression, Statement, UnaryOperator}; pub use oxide_parser::{AssignmentOperator, BinaryOperator, Expression, Statement, UnaryOperator};
use crate::symbol_table::ScopeKind;
pub struct Compiler; pub struct Compiler;
+2 -1
View File
@@ -190,7 +190,8 @@ impl Compiler {
// Hoisting: declare function name as initialized // Hoisting: declare function name as initialized
let func_reg = ctx.alloc_reg(); let func_reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(&name, func_reg, VariableDeclarationKind::Var, false); let _ =
ctx.declare_initialized(&name, func_reg, VariableDeclarationKind::Var, false);
// Body is compiled in the emit pass only. // Body is compiled in the emit pass only.
// FD emits LOAD_CONST(BytecodeFunc) + STORE_VAR // FD emits LOAD_CONST(BytecodeFunc) + STORE_VAR
+51 -27
View File
@@ -34,7 +34,12 @@ impl Compiler {
if let Some(init) = &d.init { if let Some(init) = &d.init {
let val_reg = self.emit_expression(init, ctx)?; let val_reg = self.emit_expression(init, ctx)?;
let const_flag = if is_const { 1 } else { 0 }; let const_flag = if is_const { 1 } else { 0 };
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, const_flag)); ctx.emit(opcode::encode(
OpCode::STORE_VAR,
var_reg,
val_reg,
const_flag,
));
ctx.init_var(name); ctx.init_var(name);
// Name inference (D-04): if the initializer is an arrow function, // Name inference (D-04): if the initializer is an arrow function,
// set the compiled sub_module's function_name. // set the compiled sub_module's function_name.
@@ -192,7 +197,12 @@ impl Compiler {
_ => return Err("destructuring not supported".into()), _ => return Err("destructuring not supported".into()),
}; };
let var_reg = ctx.alloc_reg(); let var_reg = ctx.alloc_reg();
ctx.declare(name, var_reg, decl.kind, matches!(decl.kind, VariableDeclarationKind::Const))?; ctx.declare(
name,
var_reg,
decl.kind,
matches!(decl.kind, VariableDeclarationKind::Const),
)?;
if let Some(init_expr) = &d.init { if let Some(init_expr) = &d.init {
let val_reg = self.emit_expression(init_expr, ctx)?; let val_reg = self.emit_expression(init_expr, ctx)?;
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, 0)); ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, 0));
@@ -254,7 +264,12 @@ impl Compiler {
_ => return Err("destructuring not supported".into()), _ => return Err("destructuring not supported".into()),
}; };
let var_reg = ctx.alloc_reg(); let var_reg = ctx.alloc_reg();
ctx.declare(name, var_reg, decl.kind, matches!(decl.kind, VariableDeclarationKind::Const))?; ctx.declare(
name,
var_reg,
decl.kind,
matches!(decl.kind, VariableDeclarationKind::Const),
)?;
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, key_reg, 0)); ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, key_reg, 0));
ctx.init_var(name); ctx.init_var(name);
} }
@@ -622,30 +637,34 @@ impl Compiler {
ctx.emit(opcode::encode(OpCode::UNARY_PLUS, r, arg, 0)); ctx.emit(opcode::encode(OpCode::UNARY_PLUS, r, arg, 0));
Ok(r) Ok(r)
} }
UnaryOperator::Delete => { UnaryOperator::Delete => match &un.argument {
match &un.argument { Expression::Identifier(_) => {
Expression::Identifier(_) => { Err("delete of global variable is not allowed in strict mode".into())
Err("delete of global variable is not allowed in strict mode".into())
}
Expression::StaticMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let prop_name = member.property.name.as_str();
let const_idx = ctx.add_constant(Constant::String(prop_name.to_string()));
let r = ctx.alloc_reg();
ctx.emit(opcode::encode(OpCode::DELETE_PROP_STATIC, r, obj_reg, 0));
ctx.emit(const_idx as u32);
Ok(r)
}
Expression::ComputedMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
let r = ctx.alloc_reg();
ctx.emit(opcode::encode(OpCode::DELETE_PROP_DYNAMIC, r, obj_reg, key_reg));
Ok(r)
}
_ => Err("invalid delete target".into()),
} }
} Expression::StaticMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let prop_name = member.property.name.as_str();
let const_idx =
ctx.add_constant(Constant::String(prop_name.to_string()));
let r = ctx.alloc_reg();
ctx.emit(opcode::encode(OpCode::DELETE_PROP_STATIC, r, obj_reg, 0));
ctx.emit(const_idx as u32);
Ok(r)
}
Expression::ComputedMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
let r = ctx.alloc_reg();
ctx.emit(opcode::encode(
OpCode::DELETE_PROP_DYNAMIC,
r,
obj_reg,
key_reg,
));
Ok(r)
}
_ => Err("invalid delete target".into()),
},
_ => Err(format!("unsupported unary operator: {:?}", un.operator)), _ => Err(format!("unsupported unary operator: {:?}", un.operator)),
} }
} }
@@ -902,7 +921,12 @@ impl Compiler {
let var_reg = ctx.lookup_or_global(name); let var_reg = ctx.lookup_or_global(name);
let is_const = ctx.lookup_const_flag(name); let is_const = ctx.lookup_const_flag(name);
let const_flag = if is_const { 1 } else { 0 }; let const_flag = if is_const { 1 } else { 0 };
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, const_flag)); ctx.emit(opcode::encode(
OpCode::STORE_VAR,
var_reg,
val_reg,
const_flag,
));
Ok(val_reg) Ok(val_reg)
} }
} else { } else {
+2 -2
View File
@@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use oxide_parser::VariableDeclarationKind; use oxide_parser::VariableDeclarationKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ScopeKind { pub(crate) enum ScopeKind {
@@ -190,7 +190,7 @@ impl SymbolTable {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::SymbolTable; use super::SymbolTable;
use oxide_parser::VariableDeclarationKind; use oxide_parser::VariableDeclarationKind;
fn v() -> VariableDeclarationKind { fn v() -> VariableDeclarationKind {
VariableDeclarationKind::Var VariableDeclarationKind::Var
+48 -6
View File
@@ -32,12 +32,54 @@ pub fn bind_error(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
global.ensure_hash_props().push(Box::new(err_val)); global.ensure_hash_props().push(Box::new(err_val));
global.bump_generation(); global.bump_generation();
bind_constructor_hash!(kernel, global, "TypeError", kernel.builtin_world().type_error_proto.as_ptr() as *mut JsObject, crate::builtins::error::type_error_constructor, 1); bind_constructor_hash!(
bind_constructor_hash!(kernel, global, "ReferenceError", kernel.builtin_world().reference_error_proto.as_ptr() as *mut JsObject, crate::builtins::error::reference_error_constructor, 1); kernel,
bind_constructor_hash!(kernel, global, "RangeError", kernel.builtin_world().range_error_proto.as_ptr() as *mut JsObject, crate::builtins::error::range_error_constructor, 1); global,
bind_constructor_hash!(kernel, global, "SyntaxError", kernel.builtin_world().syntax_error_proto.as_ptr() as *mut JsObject, crate::builtins::error::syntax_error_constructor, 1); "TypeError",
bind_constructor_hash!(kernel, global, "URIError", kernel.builtin_world().uri_error_proto.as_ptr() as *mut JsObject, crate::builtins::error::uri_error_constructor, 1); kernel.builtin_world().type_error_proto.as_ptr() as *mut JsObject,
bind_constructor_hash!(kernel, global, "EvalError", kernel.builtin_world().eval_error_proto.as_ptr() as *mut JsObject, crate::builtins::error::eval_error_constructor, 1); crate::builtins::error::type_error_constructor,
1
);
bind_constructor_hash!(
kernel,
global,
"ReferenceError",
kernel.builtin_world().reference_error_proto.as_ptr() as *mut JsObject,
crate::builtins::error::reference_error_constructor,
1
);
bind_constructor_hash!(
kernel,
global,
"RangeError",
kernel.builtin_world().range_error_proto.as_ptr() as *mut JsObject,
crate::builtins::error::range_error_constructor,
1
);
bind_constructor_hash!(
kernel,
global,
"SyntaxError",
kernel.builtin_world().syntax_error_proto.as_ptr() as *mut JsObject,
crate::builtins::error::syntax_error_constructor,
1
);
bind_constructor_hash!(
kernel,
global,
"URIError",
kernel.builtin_world().uri_error_proto.as_ptr() as *mut JsObject,
crate::builtins::error::uri_error_constructor,
1
);
bind_constructor_hash!(
kernel,
global,
"EvalError",
kernel.builtin_world().eval_error_proto.as_ptr() as *mut JsObject,
crate::builtins::error::eval_error_constructor,
1
);
{ {
let err_ctor_ptr = kernel.builtin_world().error_constructor.as_ptr() as *mut JsObject; let err_ctor_ptr = kernel.builtin_world().error_constructor.as_ptr() as *mut JsObject;
+42 -14
View File
@@ -43,44 +43,72 @@ pub fn bind_number(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
)); ));
num_ctor.set_native_arg_count(1); num_ctor.set_native_arg_count(1);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(2.220446049250313e-16))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(2.220446049250313e-16)));
let eps_si = kernel.string_forge().intern("EPSILON").0; let eps_si = kernel.string_forge().intern("EPSILON").0;
let _shape1 = kernel.shape_forge().make_shape(num_ctor.shape_id(), eps_si); let _shape1 = kernel.shape_forge().make_shape(num_ctor.shape_id(), eps_si);
num_ctor.set_shape_id(_shape1); num_ctor.set_shape_id(_shape1);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(9007199254740991f64))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(9007199254740991f64)));
let max_safe_si = kernel.string_forge().intern("MAX_SAFE_INTEGER").0; let max_safe_si = kernel.string_forge().intern("MAX_SAFE_INTEGER").0;
let _shape2 = kernel.shape_forge().make_shape(num_ctor.shape_id(), max_safe_si); let _shape2 = kernel
.shape_forge()
.make_shape(num_ctor.shape_id(), max_safe_si);
num_ctor.set_shape_id(_shape2); num_ctor.set_shape_id(_shape2);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(-9007199254740991f64))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(-9007199254740991f64)));
let min_safe_si = kernel.string_forge().intern("MIN_SAFE_INTEGER").0; let min_safe_si = kernel.string_forge().intern("MIN_SAFE_INTEGER").0;
let _shape3 = kernel.shape_forge().make_shape(num_ctor.shape_id(), min_safe_si); let _shape3 = kernel
.shape_forge()
.make_shape(num_ctor.shape_id(), min_safe_si);
num_ctor.set_shape_id(_shape3); num_ctor.set_shape_id(_shape3);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(1.7976931348623157e308))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(1.7976931348623157e308)));
let max_val_si = kernel.string_forge().intern("MAX_VALUE").0; let max_val_si = kernel.string_forge().intern("MAX_VALUE").0;
let _shape4 = kernel.shape_forge().make_shape(num_ctor.shape_id(), max_val_si); let _shape4 = kernel
.shape_forge()
.make_shape(num_ctor.shape_id(), max_val_si);
num_ctor.set_shape_id(_shape4); num_ctor.set_shape_id(_shape4);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(5e-324))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(5e-324)));
let min_val_si = kernel.string_forge().intern("MIN_VALUE").0; let min_val_si = kernel.string_forge().intern("MIN_VALUE").0;
let _shape5 = kernel.shape_forge().make_shape(num_ctor.shape_id(), min_val_si); let _shape5 = kernel
.shape_forge()
.make_shape(num_ctor.shape_id(), min_val_si);
num_ctor.set_shape_id(_shape5); num_ctor.set_shape_id(_shape5);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(f64::NAN))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(f64::NAN)));
let nan_si = kernel.string_forge().intern("NaN").0; let nan_si = kernel.string_forge().intern("NaN").0;
let _shape6 = kernel.shape_forge().make_shape(num_ctor.shape_id(), nan_si); let _shape6 = kernel.shape_forge().make_shape(num_ctor.shape_id(), nan_si);
num_ctor.set_shape_id(_shape6); num_ctor.set_shape_id(_shape6);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(f64::NEG_INFINITY))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(f64::NEG_INFINITY)));
let neg_inf_si = kernel.string_forge().intern("NEGATIVE_INFINITY").0; let neg_inf_si = kernel.string_forge().intern("NEGATIVE_INFINITY").0;
let _shape7 = kernel.shape_forge().make_shape(num_ctor.shape_id(), neg_inf_si); let _shape7 = kernel
.shape_forge()
.make_shape(num_ctor.shape_id(), neg_inf_si);
num_ctor.set_shape_id(_shape7); num_ctor.set_shape_id(_shape7);
num_ctor.ensure_hash_props().push(Box::new(JsValue::float(f64::INFINITY))); num_ctor
.ensure_hash_props()
.push(Box::new(JsValue::float(f64::INFINITY)));
let pos_inf_si = kernel.string_forge().intern("POSITIVE_INFINITY").0; let pos_inf_si = kernel.string_forge().intern("POSITIVE_INFINITY").0;
let _shape8 = kernel.shape_forge().make_shape(num_ctor.shape_id(), pos_inf_si); let _shape8 = kernel
.shape_forge()
.make_shape(num_ctor.shape_id(), pos_inf_si);
num_ctor.set_shape_id(_shape8); num_ctor.set_shape_id(_shape8);
} }
+3 -1
View File
@@ -14,7 +14,9 @@ pub fn bind_regexp(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let sf = kernel.string_forge().as_ref(); let sf = kernel.string_forge().as_ref();
let sh = kernel.shape_forge().as_ref(); let sh = kernel.shape_forge().as_ref();
ctor.set_native_fn(Some(crate::builtins::regexp::regexp_constructor as *const ())); ctor.set_native_fn(Some(
crate::builtins::regexp::regexp_constructor as *const (),
));
ctor.set_native_arg_count(2); ctor.set_native_arg_count(2);
bind_method!( bind_method!(
+10 -15
View File
@@ -25,29 +25,24 @@ pub fn bind_symbol(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
0 0
); );
let sym_match_val = JsValue::from_js_object( let sym_match_val =
kernel.builtin_world().sym_match.as_ptr() as *mut JsObject, JsValue::from_js_object(kernel.builtin_world().sym_match.as_ptr() as *mut JsObject);
);
bind_well_known_symbol(kernel, ctor, sf, sh, "match", sym_match_val); bind_well_known_symbol(kernel, ctor, sf, sh, "match", sym_match_val);
let sym_replace_val = JsValue::from_js_object( let sym_replace_val =
kernel.builtin_world().sym_replace.as_ptr() as *mut JsObject, JsValue::from_js_object(kernel.builtin_world().sym_replace.as_ptr() as *mut JsObject);
);
bind_well_known_symbol(kernel, ctor, sf, sh, "replace", sym_replace_val); bind_well_known_symbol(kernel, ctor, sf, sh, "replace", sym_replace_val);
let sym_search_val = JsValue::from_js_object( let sym_search_val =
kernel.builtin_world().sym_search.as_ptr() as *mut JsObject, JsValue::from_js_object(kernel.builtin_world().sym_search.as_ptr() as *mut JsObject);
);
bind_well_known_symbol(kernel, ctor, sf, sh, "search", sym_search_val); bind_well_known_symbol(kernel, ctor, sf, sh, "search", sym_search_val);
let sym_split_val = JsValue::from_js_object( let sym_split_val =
kernel.builtin_world().sym_split.as_ptr() as *mut JsObject, JsValue::from_js_object(kernel.builtin_world().sym_split.as_ptr() as *mut JsObject);
);
bind_well_known_symbol(kernel, ctor, sf, sh, "split", sym_split_val); bind_well_known_symbol(kernel, ctor, sf, sh, "split", sym_split_val);
let sym_iterator_val = JsValue::from_js_object( let sym_iterator_val =
kernel.builtin_world().sym_iterator.as_ptr() as *mut JsObject, JsValue::from_js_object(kernel.builtin_world().sym_iterator.as_ptr() as *mut JsObject);
);
bind_well_known_symbol(kernel, ctor, sf, sh, "iterator", sym_iterator_val); bind_well_known_symbol(kernel, ctor, sf, sh, "iterator", sym_iterator_val);
bind_constructor_hash!( bind_constructor_hash!(
+110 -27
View File
@@ -692,7 +692,9 @@ pub fn array_shift(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let arr = unsafe { &mut *arr_ptr }; let arr = unsafe { &mut *arr_ptr };
let len = arr.prop_count(); let len = arr.prop_count();
if len == 0 { return Ok(JsValue::undefined()); } if len == 0 {
return Ok(JsValue::undefined());
}
let first = arr.get_prop_at(0); let first = arr.get_prop_at(0);
for i in 1..len { for i in 1..len {
let v = arr.get_prop_at(i); let v = arr.get_prop_at(i);
@@ -723,15 +725,26 @@ pub fn array_fill(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let arr = unsafe { &mut *arr_ptr }; let arr = unsafe { &mut *arr_ptr };
let len = arr.prop_count() as usize; let len = arr.prop_count() as usize;
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; let value = if args.len() > 1 {
vm.reg(args[1])
} else {
JsValue::undefined()
};
let start = if args.len() > 2 { let start = if args.len() > 2 {
(coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as i32).max(0) as usize (coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as i32).max(0)
} else { 0 }; as usize
} else {
0
};
let end = if args.len() > 3 { let end = if args.len() > 3 {
let e = coercion::to_number(vm.reg(args[3]), vm.kernel().string_forge().as_ref()) as i32; let e = coercion::to_number(vm.reg(args[3]), vm.kernel().string_forge().as_ref()) as i32;
(e as usize).min(len) (e as usize).min(len)
} else { len }; } else {
for i in start..end { arr.set_prop_at(i as u8, value); } len
};
for i in start..end {
arr.set_prop_at(i as u8, value);
}
Ok(vm.reg(args[0])) Ok(vm.reg(args[0]))
} }
@@ -739,13 +752,30 @@ pub fn array_copy_within(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let arr = unsafe { &mut *arr_ptr }; let arr = unsafe { &mut *arr_ptr };
let len = arr.prop_count() as usize; let len = arr.prop_count() as usize;
if len == 0 { return Ok(vm.reg(args[0])); } if len == 0 {
let target = if args.len() > 1 { (coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as i32) as usize } else { 0 }; return Ok(vm.reg(args[0]));
let start = if args.len() > 2 { (coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as i32) as usize } else { 0 }; }
let end = if args.len() > 3 { (coercion::to_number(vm.reg(args[3]), vm.kernel().string_forge().as_ref()) as i32 as usize).min(len) } else { len }; let target = if args.len() > 1 {
(coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as i32) as usize
} else {
0
};
let start = if args.len() > 2 {
(coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as i32) as usize
} else {
0
};
let end = if args.len() > 3 {
(coercion::to_number(vm.reg(args[3]), vm.kernel().string_forge().as_ref()) as i32 as usize)
.min(len)
} else {
len
};
let mut to = target; let mut to = target;
for from in start..end { for from in start..end {
if to >= len { break; } if to >= len {
break;
}
let v = arr.get_prop_at(from as u8); let v = arr.get_prop_at(from as u8);
arr.set_prop_at(to as u8, v); arr.set_prop_at(to as u8, v);
to += 1; to += 1;
@@ -757,9 +787,17 @@ pub fn array_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let arr = unsafe { &*arr_ptr }; let arr = unsafe { &*arr_ptr };
let len = arr.prop_count() as i32; let len = arr.prop_count() as i32;
let mut index = if args.len() > 1 { coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as i32 } else { 0 }; let mut index = if args.len() > 1 {
if index < 0 { index += len; } coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as i32
if index < 0 || index >= len { return Ok(JsValue::undefined()); } } else {
0
};
if index < 0 {
index += len;
}
if index < 0 || index >= len {
return Ok(JsValue::undefined());
}
Ok(arr.get_prop_at(index as u8)) Ok(arr.get_prop_at(index as u8))
} }
@@ -767,7 +805,11 @@ pub fn array_last_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let arr = unsafe { &*arr_ptr }; let arr = unsafe { &*arr_ptr };
let len = arr.prop_count() as i32; let len = arr.prop_count() as i32;
let search = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; let search = if args.len() > 1 {
vm.reg(args[1])
} else {
JsValue::undefined()
};
for i in (0..len).rev() { for i in (0..len).rev() {
if coercion::strict_equality(arr.get_prop_at(i as u8), search) { if coercion::strict_equality(arr.get_prop_at(i as u8), search) {
return Ok(JsValue::int(i)); return Ok(JsValue::int(i));
@@ -779,13 +821,28 @@ pub fn array_last_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn array_find_index(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn array_find_index(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let n = unsafe { (*arr_ptr).prop_count() } as usize; let n = unsafe { (*arr_ptr).prop_count() } as usize;
if args.len() < 2 { return Ok(JsValue::int(-1)); } if args.len() < 2 {
return Ok(JsValue::int(-1));
}
let callback_val = vm.reg(args[1]); let callback_val = vm.reg(args[1]);
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() }; let this_val = if args.len() > 2 {
vm.reg(args[2])
} else {
JsValue::undefined()
};
for i in 0..n { for i in 0..n {
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) }; let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) { match invoke_native_callback(
Ok(r) => { if coercion::to_boolean(r, vm.kernel().string_forge().as_ref()) { return Ok(JsValue::int(i as i32)); } } vm,
callback_val,
this_val,
&[elem, JsValue::int(i as i32), vm.reg(args[0])],
) {
Ok(r) => {
if coercion::to_boolean(r, vm.kernel().string_forge().as_ref()) {
return Ok(JsValue::int(i as i32));
}
}
Err(_) => return Err(JsValue::undefined()), Err(_) => return Err(JsValue::undefined()),
} }
} }
@@ -795,13 +852,28 @@ pub fn array_find_index(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn array_find_last(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn array_find_last(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let n = unsafe { (*arr_ptr).prop_count() } as i32; let n = unsafe { (*arr_ptr).prop_count() } as i32;
if args.len() < 2 { return Ok(JsValue::undefined()); } if args.len() < 2 {
return Ok(JsValue::undefined());
}
let callback_val = vm.reg(args[1]); let callback_val = vm.reg(args[1]);
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() }; let this_val = if args.len() > 2 {
vm.reg(args[2])
} else {
JsValue::undefined()
};
for i in (0..n).rev() { for i in (0..n).rev() {
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) }; let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i), vm.reg(args[0])]) { match invoke_native_callback(
Ok(r) => { if coercion::to_boolean(r, vm.kernel().string_forge().as_ref()) { return Ok(elem); } } vm,
callback_val,
this_val,
&[elem, JsValue::int(i), vm.reg(args[0])],
) {
Ok(r) => {
if coercion::to_boolean(r, vm.kernel().string_forge().as_ref()) {
return Ok(elem);
}
}
Err(_) => return Err(JsValue::undefined()), Err(_) => return Err(JsValue::undefined()),
} }
} }
@@ -811,17 +883,26 @@ pub fn array_find_last(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn array_reduce_right(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn array_reduce_right(vm: &mut Vm, args: &[u8]) -> NativeResult {
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?; let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
let n = unsafe { (*arr_ptr).prop_count() } as usize; let n = unsafe { (*arr_ptr).prop_count() } as usize;
if args.len() < 2 { return Err(JsValue::undefined()); } if args.len() < 2 {
return Err(JsValue::undefined());
}
let callback_val = vm.reg(args[1]); let callback_val = vm.reg(args[1]);
let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 { let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 {
(vm.reg(args[2]), n as i32 - 1) (vm.reg(args[2]), n as i32 - 1)
} else { } else {
if n == 0 { return Err(JsValue::undefined()); } if n == 0 {
return Err(JsValue::undefined());
}
(unsafe { (*arr_ptr).get_prop_at(n as u8 - 1) }, n as i32 - 2) (unsafe { (*arr_ptr).get_prop_at(n as u8 - 1) }, n as i32 - 2)
}; };
for i in (0..=start_idx).rev() { for i in (0..=start_idx).rev() {
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) }; let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
match invoke_native_callback(vm, callback_val, JsValue::undefined(), &[acc, elem, JsValue::int(i), vm.reg(args[0])]) { match invoke_native_callback(
vm,
callback_val,
JsValue::undefined(),
&[acc, elem, JsValue::int(i), vm.reg(args[0])],
) {
Ok(r) => acc = r, Ok(r) => acc = r,
Err(_) => return Err(JsValue::undefined()), Err(_) => return Err(JsValue::undefined()),
} }
@@ -839,6 +920,8 @@ pub fn array_sort(vm: &mut Vm, _args: &[u8]) -> NativeResult {
let sb = coercion::to_string(vm.kernel().string_forge().as_ref(), *b); let sb = coercion::to_string(vm.kernel().string_forge().as_ref(), *b);
sa.cmp(&sb) sa.cmp(&sb)
}); });
for (i, &v) in vals.iter().enumerate() { arr.set_prop_at(i as u8, v); } for (i, &v) in vals.iter().enumerate() {
arr.set_prop_at(i as u8, v);
}
Ok(vm.reg(_args[0])) Ok(vm.reg(_args[0]))
} }
+25 -6
View File
@@ -121,14 +121,29 @@ pub fn error_to_string(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(args[0]); let this_val = vm.reg(args[0]);
let (name, msg) = if this_val.is_object() { let (name, msg) = if this_val.is_object() {
let obj = unsafe { &*this_val.as_js_object_ptr() }; let obj = unsafe { &*this_val.as_js_object_ptr() };
let name_val = obj.hash_props_vec().and_then(|v| v.first()).map(|b| **b).unwrap_or(JsValue::undefined()); let name_val = obj
let msg_val = obj.hash_props_vec().and_then(|v| v.get(1)).map(|b| **b).unwrap_or(JsValue::undefined()); .hash_props_vec()
(vm.lookup_str(name_val).unwrap_or_else(|| "Error".to_string()), .and_then(|v| v.first())
vm.lookup_str(msg_val).unwrap_or_default()) .map(|b| **b)
.unwrap_or(JsValue::undefined());
let msg_val = obj
.hash_props_vec()
.and_then(|v| v.get(1))
.map(|b| **b)
.unwrap_or(JsValue::undefined());
(
vm.lookup_str(name_val)
.unwrap_or_else(|| "Error".to_string()),
vm.lookup_str(msg_val).unwrap_or_default(),
)
} else { } else {
("Error".to_string(), String::new()) ("Error".to_string(), String::new())
}; };
let result = if msg.is_empty() { name } else { format!("{}: {}", name, msg) }; let result = if msg.is_empty() {
name
} else {
format!("{}: {}", name, msg)
};
let si = vm.kernel().string_forge().intern(&result).0; let si = vm.kernel().string_forge().intern(&result).0;
Ok(JsValue::string(si, 0)) Ok(JsValue::string(si, 0))
} }
@@ -136,7 +151,11 @@ pub fn error_to_string(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn error_stack_getter(vm: &mut Vm, _args: &[u8]) -> NativeResult { pub fn error_stack_getter(vm: &mut Vm, _args: &[u8]) -> NativeResult {
let mut lines = vec![]; let mut lines = vec![];
for frame in vm.frames.iter().rev() { for frame in vm.frames.iter().rev() {
let func_name = vm.kernel().string_forge().lookup(frame.function_name).unwrap_or_else(|| "<anonymous>".to_string()); let func_name = vm
.kernel()
.string_forge()
.lookup(frame.function_name)
.unwrap_or_else(|| "<anonymous>".to_string());
lines.push(format!(" at {} (native)", func_name)); lines.push(format!(" at {} (native)", func_name));
} }
lines.push(" at <anonymous> (native)".to_string()); lines.push(" at <anonymous> (native)".to_string());
+5 -1
View File
@@ -160,7 +160,11 @@ pub fn function_bind(vm: &mut Vm, args: &[u8]) -> NativeResult {
} }
pub fn function_to_string(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn function_to_string(vm: &mut Vm, args: &[u8]) -> NativeResult {
let name = vm.kernel().string_forge().lookup(vm.reg(args[0]).as_string_index()).unwrap_or_default(); let name = vm
.kernel()
.string_forge()
.lookup(vm.reg(args[0]).as_string_index())
.unwrap_or_default();
let result = if name.is_empty() { let result = if name.is_empty() {
"function () { [native code] }".to_string() "function () { [native code] }".to_string()
} else { } else {
+28 -7
View File
@@ -177,7 +177,10 @@ pub fn number_is_integer(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn number_is_safe_integer(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn number_is_safe_integer(vm: &mut Vm, args: &[u8]) -> NativeResult {
let val = vm.reg(if args.len() > 1 { args[1] } else { args[0] }); let val = vm.reg(if args.len() > 1 { args[1] } else { args[0] });
let n = coercion::to_number(val, vm.kernel().string_forge().as_ref()); let n = coercion::to_number(val, vm.kernel().string_forge().as_ref());
let safe = n.trunc() == n && n.is_finite() && n >= -9007199254740991i64 as f64 && n <= 9007199254740991i64 as f64; let safe = n.trunc() == n
&& n.is_finite()
&& n >= -9007199254740991i64 as f64
&& n <= 9007199254740991i64 as f64;
Ok(JsValue::bool(safe)) Ok(JsValue::bool(safe))
} }
@@ -185,10 +188,19 @@ pub fn number_to_exponential(vm: &mut Vm, args: &[u8]) -> NativeResult {
let n = coercion::to_number(vm.reg(args[0]), vm.kernel().string_forge().as_ref()); let n = coercion::to_number(vm.reg(args[0]), vm.kernel().string_forge().as_ref());
let digits = if args.len() > 1 { let digits = if args.len() > 1 {
coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize
} else { 0usize }.min(100); } else {
if n.is_nan() { return Ok(vm.intern("NaN")); } 0usize
}
.min(100);
if n.is_nan() {
return Ok(vm.intern("NaN"));
}
if n.is_infinite() { if n.is_infinite() {
return Ok(vm.intern(if n.is_sign_positive() { "Infinity" } else { "-Infinity" })); return Ok(vm.intern(if n.is_sign_positive() {
"Infinity"
} else {
"-Infinity"
}));
} }
let formatted = format!("{:.digits$e}", n); let formatted = format!("{:.digits$e}", n);
Ok(vm.intern(&formatted)) Ok(vm.intern(&formatted))
@@ -198,10 +210,19 @@ pub fn number_to_precision(vm: &mut Vm, args: &[u8]) -> NativeResult {
let n = coercion::to_number(vm.reg(args[0]), vm.kernel().string_forge().as_ref()); let n = coercion::to_number(vm.reg(args[0]), vm.kernel().string_forge().as_ref());
let precision = if args.len() > 1 { let precision = if args.len() > 1 {
coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize
} else { 0usize }.min(21); } else {
if n.is_nan() { return Ok(vm.intern("NaN")); } 0usize
}
.min(21);
if n.is_nan() {
return Ok(vm.intern("NaN"));
}
if n.is_infinite() { if n.is_infinite() {
return Ok(vm.intern(if n.is_sign_positive() { "Infinity" } else { "-Infinity" })); return Ok(vm.intern(if n.is_sign_positive() {
"Infinity"
} else {
"-Infinity"
}));
} }
let formatted = format!("{:.precision$}", n); let formatted = format!("{:.precision$}", n);
Ok(vm.intern(&formatted)) Ok(vm.intern(&formatted))
+49 -13
View File
@@ -352,18 +352,29 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
} }
pub fn object_define_properties(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn object_define_properties(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 3 { return Ok(vm.reg(args[1])); } if args.len() < 3 {
return Ok(vm.reg(args[1]));
}
let _obj_ptr = require_obj_arg(vm, args, "defineProperties")?; let _obj_ptr = require_obj_arg(vm, args, "defineProperties")?;
let desc_val = vm.reg(args[2]); let desc_val = vm.reg(args[2]);
if !desc_val.is_object() { return Ok(vm.reg(args[1])); } if !desc_val.is_object() {
return Ok(vm.reg(args[1]));
}
Ok(vm.reg(args[1])) Ok(vm.reg(args[1]))
} }
pub fn object_from_entries(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn object_from_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 { return Ok(JsValue::null()); } if args.len() < 2 {
return Ok(JsValue::null());
}
let entries = vm.reg(args[1]); let entries = vm.reg(args[1]);
if !entries.is_object() { return Ok(JsValue::null()); } if !entries.is_object() {
let obj_ptr = vm.epoch().alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(vm.kernel().builtin_world().object_proto.as_ptr() as *mut JsObject))); return Ok(JsValue::null());
}
let obj_ptr = vm.epoch().alloc(JsObject::new_empty(
EMPTY_SHAPE_ID,
JsValue::from_js_object(vm.kernel().builtin_world().object_proto.as_ptr() as *mut JsObject),
));
Ok(JsValue::from_js_object(obj_ptr)) Ok(JsValue::from_js_object(obj_ptr))
} }
@@ -373,10 +384,14 @@ pub fn object_get_prototype_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
} }
pub fn object_has_own(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn object_has_own(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 3 { return Ok(JsValue::bool(false)); } if args.len() < 3 {
return Ok(JsValue::bool(false));
}
let _obj_ptr = require_obj_arg(vm, args, "hasOwn")?; let _obj_ptr = require_obj_arg(vm, args, "hasOwn")?;
let key_val = vm.reg(args[2]); let key_val = vm.reg(args[2]);
if !key_val.is_string() { return Ok(JsValue::bool(false)); } if !key_val.is_string() {
return Ok(JsValue::bool(false));
}
Ok(JsValue::bool(false)) Ok(JsValue::bool(false))
} }
@@ -386,17 +401,29 @@ pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
let keys = walk_own_keys(vm, obj); let keys = walk_own_keys(vm, obj);
let n = keys.len().min(255); let n = keys.len().min(255);
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n, vm.epoch().bump())); let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (_i, (si, offset)) in keys.iter().enumerate().take(n) { for (_i, (si, offset)) in keys.iter().enumerate().take(n) {
let key_str = vm.kernel().string_forge().lookup(*si).unwrap_or_default(); let key_str = vm.kernel().string_forge().lookup(*si).unwrap_or_default();
let key_val = vm.intern(&key_str); let key_val = vm.intern(&key_str);
let val = obj.get_prop_at(*offset); let val = obj.get_prop_at(*offset);
let pair = vm.epoch().alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), 2, vm.epoch().bump())); let pair = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
2,
vm.epoch().bump(),
));
unsafe { unsafe {
(*pair).set_prop_at(0, key_val); (*pair).set_prop_at(0, key_val);
(*pair).set_prop_at(1, val); (*pair).set_prop_at(1, val);
(*pair).set_prop_count(2); (*pair).set_prop_count(2);
(*arr).ensure_hash_props().push(Box::new(JsValue::from_js_object(pair))); (*arr)
.ensure_hash_props()
.push(Box::new(JsValue::from_js_object(pair)));
} }
} }
Ok(JsValue::from_js_object(arr)) Ok(JsValue::from_js_object(arr))
@@ -408,11 +435,20 @@ pub fn object_values(vm: &mut Vm, args: &[u8]) -> NativeResult {
let keys = walk_own_keys(vm, obj); let keys = walk_own_keys(vm, obj);
let n = keys.len().min(255); let n = keys.len().min(255);
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n, vm.epoch().bump())); let arr = vm.epoch().alloc(JsObject::new_array(
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (i, (_si, offset)) in keys.iter().enumerate().take(n) { for (i, (_si, offset)) in keys.iter().enumerate().take(n) {
let val = obj.get_prop_at(*offset); let val = obj.get_prop_at(*offset);
unsafe { (*arr).set_prop_at(i as u8, val); } unsafe {
(*arr).set_prop_at(i as u8, val);
}
}
unsafe {
(*arr).set_prop_count(n as u8);
} }
unsafe { (*arr).set_prop_count(n as u8); }
Ok(JsValue::from_js_object(arr)) Ok(JsValue::from_js_object(arr))
} }
+3 -6
View File
@@ -86,9 +86,7 @@ pub fn regexp_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let mut obj = JsObject::new_empty( let mut obj = JsObject::new_empty(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
JsValue::from_js_object( JsValue::from_js_object(vm.kernel().builtin_world().regexp_proto.as_ptr() as *mut JsObject),
vm.kernel().builtin_world().regexp_proto.as_ptr() as *mut JsObject,
),
); );
let compiled = regex::RegexBuilder::new(&pattern) let compiled = regex::RegexBuilder::new(&pattern)
@@ -185,8 +183,7 @@ pub fn regexp_exec(vm: &mut Vm, args: &[u8]) -> NativeResult {
let (last_index, is_global) = { let (last_index, is_global) = {
let re = unsafe { &*re_ptr }; let re = unsafe { &*re_ptr };
let li = let li = coercion::to_number(get_prop(re, 0), vm.kernel().string_forge().as_ref()) as usize;
coercion::to_number(get_prop(re, 0), vm.kernel().string_forge().as_ref()) as usize;
let g = get_prop(re, 3).as_bool(); let g = get_prop(re, 3).as_bool();
(li, g) (li, g)
}; };
@@ -204,7 +201,7 @@ pub fn regexp_exec(vm: &mut Vm, args: &[u8]) -> NativeResult {
let mut match_obj = JsObject::new_empty( let mut match_obj = JsObject::new_empty(
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
JsValue::from_js_object( JsValue::from_js_object(
vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject, vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject
), ),
); );
+38 -10
View File
@@ -387,7 +387,10 @@ pub fn string_match_fn(vm: &mut Vm, args: &[u8]) -> NativeResult {
None => return Ok(JsValue::undefined()), None => return Ok(JsValue::undefined()),
}; };
let regex = unsafe { &*(fn_ptr as *const regex::Regex) }; let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let matches: Vec<String> = regex.find_iter(&s).map(|m| m.as_str().to_string()).collect(); let matches: Vec<String> = regex
.find_iter(&s)
.map(|m| m.as_str().to_string())
.collect();
return Ok(make_string_array(vm, &matches)); return Ok(make_string_array(vm, &matches));
} }
@@ -443,9 +446,13 @@ pub fn string_code_point_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
let s = this_string(vm, args); let s = this_string(vm, args);
let pos = if args.len() > 1 { let pos = if args.len() > 1 {
coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize
} else { 0 }; } else {
0
};
let chars: Vec<char> = s.chars().collect(); let chars: Vec<char> = s.chars().collect();
if pos >= chars.len() { return Ok(JsValue::undefined()); } if pos >= chars.len() {
return Ok(JsValue::undefined());
}
let c = chars[pos] as u32; let c = chars[pos] as u32;
if (0xD800..=0xDBFF).contains(&c) && pos + 1 < chars.len() { if (0xD800..=0xDBFF).contains(&c) && pos + 1 < chars.len() {
let next = chars[pos + 1] as u32; let next = chars[pos + 1] as u32;
@@ -460,7 +467,11 @@ pub fn string_code_point_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn string_normalize(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn string_normalize(vm: &mut Vm, args: &[u8]) -> NativeResult {
use unicode_normalization::UnicodeNormalization; use unicode_normalization::UnicodeNormalization;
let s = this_string(vm, args); let s = this_string(vm, args);
let form = if args.len() > 1 { as_string(vm, vm.reg(args[1])) } else { "NFC".to_string() }; let form = if args.len() > 1 {
as_string(vm, vm.reg(args[1]))
} else {
"NFC".to_string()
};
let result: String = match form.as_str() { let result: String = match form.as_str() {
"NFD" => s.nfd().collect(), "NFD" => s.nfd().collect(),
"NFKC" => s.nfkc().collect(), "NFKC" => s.nfkc().collect(),
@@ -472,14 +483,22 @@ pub fn string_normalize(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn string_match_all(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn string_match_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
let s = this_string(vm, args); let s = this_string(vm, args);
if args.len() < 2 { return Err(JsValue::undefined()); } if args.len() < 2 {
return Err(JsValue::undefined());
}
let pattern_val = vm.reg(args[1]); let pattern_val = vm.reg(args[1]);
if is_regexp_obj(pattern_val, vm) { if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr(); let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr }; let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() { Some(p) => p, None => return Ok(JsValue::undefined()) }; let fn_ptr = match re.native_fn() {
Some(p) => p,
None => return Ok(JsValue::undefined()),
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) }; let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let matches: Vec<String> = regex.find_iter(&s).map(|m| m.as_str().to_string()).collect(); let matches: Vec<String> = regex
.find_iter(&s)
.map(|m| m.as_str().to_string())
.collect();
return Ok(make_string_array(vm, &matches)); return Ok(make_string_array(vm, &matches));
} }
Ok(JsValue::undefined()) Ok(JsValue::undefined())
@@ -487,13 +506,22 @@ pub fn string_match_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub fn string_replace_all(vm: &mut Vm, args: &[u8]) -> NativeResult { pub fn string_replace_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
let s = this_string(vm, args); let s = this_string(vm, args);
if args.len() < 2 { return Ok(vm.intern(&s)); } if args.len() < 2 {
return Ok(vm.intern(&s));
}
let pattern_val = vm.reg(args[1]); let pattern_val = vm.reg(args[1]);
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() }; let replacement = if args.len() > 2 {
as_string(vm, vm.reg(args[2]))
} else {
String::new()
};
if is_regexp_obj(pattern_val, vm) { if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr(); let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr }; let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() { Some(p) => p, None => return Ok(vm.intern(&s)) }; let fn_ptr = match re.native_fn() {
Some(p) => p,
None => return Ok(vm.intern(&s)),
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) }; let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let result = regex.replace_all(&s, replacement.as_str()).to_string(); let result = regex.replace_all(&s, replacement.as_str()).to_string();
return Ok(vm.intern(&result)); return Ok(vm.intern(&result));
+16 -14
View File
@@ -675,11 +675,7 @@ impl Vm {
if b != 0 { if b != 0 {
// const guard: check if already initialized // const guard: check if already initialized
if !self.regs[rd].is_undefined() { if !self.regs[rd].is_undefined() {
throw_err!( throw_err!(self, TypeError, "Assignment to constant variable");
self,
TypeError,
"Assignment to constant variable"
);
} }
} }
self.regs[rd] = self.regs[a]; self.regs[rd] = self.regs[a];
@@ -1307,10 +1303,11 @@ impl Vm {
continue; continue;
} }
let prop_name_si = prop_name_val.as_string_index(); let prop_name_si = prop_name_val.as_string_index();
if let Some(pos) = self.kernel.shape_forge().lookup_position( if let Some(pos) = self
obj.shape_id(), .kernel
prop_name_si, .shape_forge()
) { .lookup_position(obj.shape_id(), prop_name_si)
{
obj.set_prop_at(pos, JsValue::undefined()); obj.set_prop_at(pos, JsValue::undefined());
} }
self.regs[rd] = JsValue::bool(true); self.regs[rd] = JsValue::bool(true);
@@ -1334,10 +1331,11 @@ impl Vm {
}; };
let obj_ptr = obj_val.as_js_object_ptr(); let obj_ptr = obj_val.as_js_object_ptr();
let obj = unsafe { &mut *obj_ptr }; let obj = unsafe { &mut *obj_ptr };
if let Some(pos) = self.kernel.shape_forge().lookup_position( if let Some(pos) = self
obj.shape_id(), .kernel
prop_name_si, .shape_forge()
) { .lookup_position(obj.shape_id(), prop_name_si)
{
obj.set_prop_at(pos, JsValue::undefined()); obj.set_prop_at(pos, JsValue::undefined());
} }
self.regs[rd] = JsValue::bool(true); self.regs[rd] = JsValue::bool(true);
@@ -1349,7 +1347,11 @@ impl Vm {
let rhs_val = self.regs[b]; let rhs_val = self.regs[b];
if !rhs_val.is_object() { if !rhs_val.is_object() {
throw_err!(self, TypeError, "INSTANCEOF right-hand side is not callable"); throw_err!(
self,
TypeError,
"INSTANCEOF right-hand side is not callable"
);
} }
if !lhs_val.is_object() { if !lhs_val.is_object() {
self.regs[rd] = JsValue::bool(false); self.regs[rd] = JsValue::bool(false);
@@ -10,7 +10,9 @@ fn make_vm() -> Vm {
fn eval(source: &str) -> Result<JsValue, String> { fn eval(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default(); let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; 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(); let mut vm = make_vm();
vm.run(&module) vm.run(&module)
} }
@@ -124,6 +124,10 @@ fn number_epsilon_is_positive() {
fn number_to_exponential() { fn number_to_exponential() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let result = eval(&mut vm, "var n = 123.456; n.toExponential(2)").unwrap(); 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"); assert_eq!(s, "1.23e2");
} }
@@ -154,7 +154,11 @@ fn regexp_exec_global_last_index_advances() {
#[test] #[test]
fn regexp_exec_global_resets_on_exhaustion() { fn regexp_exec_global_resets_on_exhaustion() {
let mut vm = Vm::new(); 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()); assert!(result.as_bool());
} }
+8 -2
View File
@@ -5,7 +5,9 @@ use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<JsValue, String> { fn eval(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default(); let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?; 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(); let mut vm = Vm::new();
vm.run(&module) vm.run(&module)
} }
@@ -21,7 +23,11 @@ fn const_reassignment_throws() {
let result = eval("const x = 1; x = 2"); let result = eval("const x = 1; x = 2");
assert!(result.is_err()); assert!(result.is_err());
let err = result.unwrap_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] #[test]