feat: 为 Array/String 原型方法添加入口和错误路径结构化日志,编译器添加阶段边界日志
This commit is contained in:
@@ -4,11 +4,17 @@ use oxide_types::value::JsValue;
|
||||
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
macro_rules! array_ptr {
|
||||
($vm:expr, $args:expr) => {{
|
||||
match get_this_array_ref($vm, $vm.reg($args[0])) {
|
||||
Ok(ptr) => ptr,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array method: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
@@ -158,6 +164,7 @@ pub fn array_is_array<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_push<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.push called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let mut len = unsafe { &*arr_ptr }.prop_count();
|
||||
for &arg_reg in args.iter().skip(1) {
|
||||
@@ -170,6 +177,7 @@ pub fn array_push<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_pop<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.pop called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count();
|
||||
@@ -182,6 +190,7 @@ pub fn array_pop<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.slice called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -210,6 +219,7 @@ pub fn array_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_splice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.splice called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -272,6 +282,7 @@ pub fn array_splice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.concat called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -307,6 +318,7 @@ pub fn array_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_join<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.join called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -331,6 +343,7 @@ pub fn array_join<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.indexOf called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -347,6 +360,7 @@ pub fn array_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_includes<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.includes called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -371,6 +385,7 @@ pub fn array_includes<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_reverse<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reverse called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -387,6 +402,7 @@ pub fn array_reverse<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_flat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.flat called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let n = arr.prop_count() as usize;
|
||||
@@ -443,34 +459,50 @@ pub fn array_flat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.forEach called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) {
|
||||
NativeResult::Ok(_) => {}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.forEach: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.map called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.map: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.map: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let new_arr = create_new_array(vm, n);
|
||||
@@ -480,8 +512,14 @@ pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
NativeResult::Ok(mapped) => unsafe {
|
||||
(*new_arr).set_prop_at(i, mapped);
|
||||
},
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.map: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.map: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
@@ -491,13 +529,18 @@ pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.filter called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let mut kept: Vec<JsValue> = Vec::new();
|
||||
@@ -509,8 +552,14 @@ pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
kept.push(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
let new_arr = create_new_array(vm, kept.len());
|
||||
@@ -524,16 +573,22 @@ pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduce called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if n == 0 && args.len() < 3 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let has_initial = args.len() > 2;
|
||||
let mut accumulator;
|
||||
@@ -555,21 +610,32 @@ pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
&[accumulator, elem, JsValue::int(i as i32), vm.reg(args[0])],
|
||||
) {
|
||||
NativeResult::Ok(result) => accumulator = result,
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(accumulator)
|
||||
}
|
||||
|
||||
pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.find called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
@@ -580,21 +646,32 @@ pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Ok(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.some called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
@@ -605,21 +682,32 @@ pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Ok(JsValue::bool(true));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::bool(false))
|
||||
}
|
||||
|
||||
pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.every called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
@@ -630,21 +718,32 @@ pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Ok(JsValue::bool(false));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::bool(true))
|
||||
}
|
||||
|
||||
pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.flatMap called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let mut flat: Vec<JsValue> = Vec::new();
|
||||
@@ -667,8 +766,14 @@ pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
flat.push(result);
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
@@ -682,6 +787,7 @@ pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_shift<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.shift called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count();
|
||||
@@ -698,6 +804,7 @@ pub fn array_shift<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_unshift<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.unshift called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count();
|
||||
@@ -715,6 +822,7 @@ pub fn array_unshift<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_fill<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.fill called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count() as usize;
|
||||
@@ -737,6 +845,7 @@ pub fn array_fill<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_copy_within<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.copyWithin called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count() as usize;
|
||||
@@ -771,6 +880,7 @@ pub fn array_copy_within<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.at called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let len = arr.prop_count() as i32;
|
||||
@@ -789,6 +899,7 @@ pub fn array_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_last_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.lastIndexOf called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let len = arr.prop_count() as i32;
|
||||
@@ -802,13 +913,18 @@ pub fn array_last_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findIndex called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
@@ -819,24 +935,35 @@ pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Ok(JsValue::int(i as i32));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findLast called with {} args", args.len());
|
||||
let (arr_ptr, n) = {
|
||||
let (arr_ptr, len) = array_ptr_len!(vm, args);
|
||||
(arr_ptr, len as i32)
|
||||
};
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in (0..n).rev() {
|
||||
@@ -847,26 +974,38 @@ pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Ok(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduceRight called with {} args", args.len());
|
||||
let (arr_ptr, n) = array_ptr_len!(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 {
|
||||
(vm.reg(args[2]), n as i32 - 1)
|
||||
} else {
|
||||
if n == 0 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
(unsafe { (*arr_ptr).get_prop_at(n - 1) }, n as i32 - 2)
|
||||
@@ -880,14 +1019,21 @@ pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
&[acc, elem, JsValue::int(i), vm.reg(args[0])],
|
||||
) {
|
||||
NativeResult::Ok(r) => acc = r,
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(acc)
|
||||
}
|
||||
|
||||
pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.sort called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let len = unsafe { (*arr_ptr).prop_count() as usize };
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| unsafe { (*arr_ptr).get_prop_at(i) }).collect();
|
||||
@@ -898,7 +1044,10 @@ pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
} else {
|
||||
match require_callback(vm, candidate) {
|
||||
Ok(callback) => Some(callback),
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -937,6 +1086,7 @@ pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
});
|
||||
if let Some(err) = sort_error {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
@@ -947,9 +1097,13 @@ pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn array_values<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.values called with {} args", args.len());
|
||||
let this_val = vm.reg(args[0]);
|
||||
match crate::iterator::make_iterator_for_value(vm, this_val) {
|
||||
Ok(iterator) => NativeResult::Ok(iterator),
|
||||
Err(err) => NativeResult::Err(err),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.values: invalid receiver");
|
||||
NativeResult::Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,15 @@ use oxide_types::value::JsValue;
|
||||
use memchr::memchr;
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
fn this_string<H: VmHost>(vm: &H, args: &[u8]) -> String {
|
||||
oxide_runtime_api::to_string(vm.reg(args[0]))
|
||||
}
|
||||
|
||||
pub fn string_from_char_code<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.fromCharCode called with {} args", args.len());
|
||||
let mut out = String::new();
|
||||
for &arg_reg in args.iter().skip(1) {
|
||||
let code = oxide_runtime_api::to_uint32(vm.reg(arg_reg)) & 0xFFFF;
|
||||
@@ -23,6 +27,7 @@ pub fn string_from_char_code<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
}
|
||||
|
||||
pub fn string_value_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.valueOf called with {} args", args.len());
|
||||
let this_val = vm.reg(args[0]);
|
||||
if this_val.is_string() {
|
||||
return NativeResult::Ok(this_val);
|
||||
@@ -36,6 +41,7 @@ pub fn string_value_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
}
|
||||
}
|
||||
builtins_error!("String.prototype.valueOf: invalid receiver");
|
||||
NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"String.prototype.valueOf called on non-String object",
|
||||
@@ -157,6 +163,7 @@ fn is_regexp_obj<H: VmHost>(val: JsValue, vm: &H) -> bool {
|
||||
}
|
||||
|
||||
pub fn string_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.indexOf called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = char_len(&s);
|
||||
if args.len() < 2 {
|
||||
@@ -188,6 +195,7 @@ pub fn string_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_includes<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.includes called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = char_len(&s);
|
||||
if args.len() < 2 {
|
||||
@@ -213,6 +221,7 @@ pub fn string_includes<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_char_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.charAt called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
if s.is_empty() {
|
||||
@@ -229,6 +238,7 @@ pub fn string_char_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_char_code_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.charCodeAt called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
if s.is_empty() {
|
||||
@@ -244,6 +254,7 @@ pub fn string_char_code_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.concat called with {} args", args.len());
|
||||
let mut result = this_string(vm, args);
|
||||
for &arg_reg in args.iter().skip(1) {
|
||||
result.push_str(&oxide_runtime_api::to_string(vm.reg(arg_reg)));
|
||||
@@ -252,6 +263,7 @@ pub fn string_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.slice called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = char_len(&s) as i32;
|
||||
let start = if args.len() > 1 {
|
||||
@@ -281,6 +293,7 @@ pub fn string_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_substring<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.substring called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = char_len(&s) as i32;
|
||||
let mut start = if args.len() > 1 {
|
||||
@@ -301,21 +314,25 @@ pub fn string_substring<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_to_upper_case<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.toUpperCase called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
NativeResult::Ok(vm.new_string(&s.to_uppercase()))
|
||||
}
|
||||
|
||||
pub fn string_to_lower_case<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.toLowerCase called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
NativeResult::Ok(vm.new_string(&s.to_lowercase()))
|
||||
}
|
||||
|
||||
pub fn string_trim<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.trim called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
NativeResult::Ok(vm.new_string(s.trim()))
|
||||
}
|
||||
|
||||
pub fn string_repeat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.repeat called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = if args.len() > 1 {
|
||||
(oxide_runtime_api::to_number(vm.reg(args[1])) as usize).min(10000)
|
||||
@@ -326,6 +343,7 @@ pub fn string_repeat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_pad_start<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.padStart called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let s_len = char_len(&s);
|
||||
let target = if args.len() > 1 {
|
||||
@@ -334,6 +352,7 @@ pub fn string_pad_start<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
s_len
|
||||
};
|
||||
if target > 10000 {
|
||||
builtins_error!("String.prototype.padStart: invalid receiver");
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "Invalid string length"));
|
||||
}
|
||||
let pad = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { " ".to_string() };
|
||||
@@ -349,6 +368,7 @@ pub fn string_pad_start<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_pad_end<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.padEnd called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let s_len = char_len(&s);
|
||||
let target = if args.len() > 1 {
|
||||
@@ -357,6 +377,7 @@ pub fn string_pad_end<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
s_len
|
||||
};
|
||||
if target > 10000 {
|
||||
builtins_error!("String.prototype.padEnd: invalid receiver");
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "Invalid string length"));
|
||||
}
|
||||
let pad = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { " ".to_string() };
|
||||
@@ -372,6 +393,7 @@ pub fn string_pad_end<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_starts_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.startsWith called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = char_len(&s);
|
||||
if args.len() < 2 {
|
||||
@@ -387,6 +409,7 @@ pub fn string_starts_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_ends_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.endsWith called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let n = char_len(&s);
|
||||
if args.len() < 2 {
|
||||
@@ -402,6 +425,7 @@ pub fn string_ends_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_split<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.split called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
let parts = vec![s.clone()];
|
||||
@@ -441,6 +465,7 @@ pub fn string_split<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_replace<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.replace called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
@@ -467,6 +492,7 @@ pub fn string_replace<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_match_fn<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.match called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
@@ -494,6 +520,7 @@ pub fn string_match_fn<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_search<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.search called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(JsValue::int(-1));
|
||||
@@ -523,16 +550,19 @@ pub fn string_search<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_trim_start<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.trimStart called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
NativeResult::Ok(vm.new_string(s.trim_start()))
|
||||
}
|
||||
|
||||
pub fn string_trim_end<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.trimEnd called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
NativeResult::Ok(vm.new_string(s.trim_end()))
|
||||
}
|
||||
|
||||
pub fn string_code_point_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.codePointAt called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
let pos = if args.len() > 1 {
|
||||
oxide_runtime_api::to_number(vm.reg(args[1])) as usize
|
||||
@@ -555,6 +585,7 @@ pub fn string_code_point_at<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
}
|
||||
|
||||
pub fn string_normalize<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.normalize called with {} args", args.len());
|
||||
use unicode_normalization::UnicodeNormalization;
|
||||
let s = this_string(vm, args);
|
||||
let form = if args.len() > 1 { as_string(vm, vm.reg(args[1])) } else { "NFC".to_string() };
|
||||
@@ -568,8 +599,10 @@ pub fn string_normalize<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_match_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.matchAll called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("String.prototype.matchAll: invalid receiver");
|
||||
return NativeResult::Err(JsValue::undefined());
|
||||
}
|
||||
let pattern_val = vm.reg(args[1]);
|
||||
@@ -589,6 +622,7 @@ pub fn string_match_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
|
||||
pub fn string_replace_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("String.prototype.replaceAll called with {} args", args.len());
|
||||
let s = this_string(vm, args);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Ok(vm.new_string(&s));
|
||||
|
||||
@@ -830,12 +830,14 @@ impl Compiler {
|
||||
}
|
||||
|
||||
pub fn compile(&self, program: &oxide_parser::Program) -> Result<CompiledModule, String> {
|
||||
crate::compiler_debug!("compile: starting...");
|
||||
let mut ctx = CompileCtx::new();
|
||||
ctx.pre_register_builtins();
|
||||
|
||||
for stmt in &program.body {
|
||||
self.count_statement(stmt, &mut ctx);
|
||||
}
|
||||
crate::compiler_debug!("counter: {} instructions estimated", ctx.projected_pc);
|
||||
ctx.max_regs = ctx.max_regs.max(1);
|
||||
ctx.reg_overflow = false;
|
||||
ctx.reset_regs();
|
||||
@@ -859,6 +861,7 @@ impl Compiler {
|
||||
None => last_result = None,
|
||||
}
|
||||
}
|
||||
crate::compiler_debug!("emitter: {} bytes emitted", ctx.bytecode.len());
|
||||
|
||||
if let Some(r) = last_result {
|
||||
ctx.emit(opcode::encode(OpCode::LOAD_VAR, 0, r, 0));
|
||||
@@ -883,6 +886,8 @@ impl Compiler {
|
||||
return Err("RangeError: jump offset out of range".into());
|
||||
}
|
||||
|
||||
crate::compiler_debug!("compile: done, {} instructions, {} constants", ctx.bytecode.len(), ctx.constants.len());
|
||||
|
||||
Ok(CompiledModule {
|
||||
bytecode: ctx.bytecode,
|
||||
constants: ctx.constants,
|
||||
|
||||
Reference in New Issue
Block a user