style: 自动格式化
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
@@ -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]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user