diff --git a/crates/dash_middle/src/interner.rs b/crates/dash_middle/src/interner.rs index 200d5641..a6573fa6 100644 --- a/crates/dash_middle/src/interner.rs +++ b/crates/dash_middle/src/interner.rs @@ -150,6 +150,7 @@ pub mod sym { PI, isFinite, isNaN, + eval, isSafeInteger, Number, toFixed, diff --git a/crates/dash_parser/src/expr.rs b/crates/dash_parser/src/expr.rs index 4e157233..4dda1020 100644 --- a/crates/dash_parser/src/expr.rs +++ b/crates/dash_parser/src/expr.rs @@ -435,12 +435,12 @@ impl<'a, 'interner> Parser<'a, 'interner> { TokenType::LeftSquareBrace => { let mut items = Vec::new(); while !self.expect_token_type_and_skip(&[TokenType::RightSquareBrace], false) { - self.expect_token_type_and_skip(&[TokenType::Comma], false); if let Some(spread) = self.parse_spread_operator(false) { items.push(ArrayMemberKind::Spread(spread)); } else { items.push(ArrayMemberKind::Item(self.parse_yield()?)); } + self.expect_token_type_and_skip(&[TokenType::Comma], false); } let rbrace_span = self.previous()?.span; Expr { diff --git a/crates/dash_vm/src/js_std/global.rs b/crates/dash_vm/src/js_std/global.rs index 554a6d89..89323113 100755 --- a/crates/dash_vm/src/js_std/global.rs +++ b/crates/dash_vm/src/js_std/global.rs @@ -1,8 +1,11 @@ +use dash_middle::parser::error::IntoFormattableErrors; + +use crate::eval::EvalError; +use crate::throw; use crate::value::function::native::CallContext; use crate::value::ops::conversions::ValueConversion; -use crate::value::{Value, ValueContext}; +use crate::value::{Root, Value, ValueContext}; -#[rustfmt::skip] pub fn is_nan(cx: CallContext) -> Result { // 1. Let num be ? ToNumber(number). let num = cx.args.first().unwrap_or_undefined().to_number(cx.scope)?; @@ -11,6 +14,19 @@ pub fn is_nan(cx: CallContext) -> Result { Ok(Value::Boolean(num.is_nan())) } +pub fn eval(cx: CallContext) -> Result { + let source = match cx.args.first().unwrap_or_undefined() { + Value::String(s) => s.res(cx.scope).to_owned(), + other => return Ok(other), + }; + + match cx.scope.eval(&source, Default::default()) { + Ok(v) => Ok(v.root(cx.scope)), + Err(EvalError::Exception(ex)) => Err(ex.root(cx.scope)), + Err(EvalError::Middle(err)) => throw!(cx.scope, SyntaxError, "{}", err.formattable(&source, true)), + } +} + pub fn log(cx: CallContext) -> Result { for arg in cx.args { let tstr = arg.to_js_string(cx.scope)?; diff --git a/crates/dash_vm/src/lib.rs b/crates/dash_vm/src/lib.rs index c8ff528d..5d749890 100644 --- a/crates/dash_vm/src/lib.rs +++ b/crates/dash_vm/src/lib.rs @@ -1094,6 +1094,7 @@ impl Vm { object_ctor.clone(), [ (sym::isNaN, scope.statics.is_nan.clone()), + (sym::eval, scope.statics.eval.clone()), (sym::isFinite, scope.statics.is_finite.clone()), (sym::parseFloat, scope.statics.parse_float.clone()), (sym::parseInt, scope.statics.parse_int.clone()), diff --git a/crates/dash_vm/src/statics.rs b/crates/dash_vm/src/statics.rs index 3ed40367..ea2519c5 100644 --- a/crates/dash_vm/src/statics.rs +++ b/crates/dash_vm/src/statics.rs @@ -30,6 +30,7 @@ pub struct Statics { pub function_call: Handle, pub function_to_string: Handle, pub is_nan: Handle, + pub eval: Handle, pub is_finite: Handle, pub parse_float: Handle, pub parse_int: Handle, @@ -301,6 +302,7 @@ impl Statics { string_ctor: function(gc, sym::String, js_std::string::constructor), string_prototype: builtin_object(gc, BoxedString::with_obj(sym::empty.into(), NamedObject::null())), is_nan: function(gc, sym::isNaN, js_std::global::is_nan), + eval: function(gc, sym::eval, js_std::global::eval), is_finite: function(gc, sym::isFinite, js_std::global::is_finite), parse_float: function(gc, sym::parseFloat, js_std::global::parse_float), parse_int: function(gc, sym::parseInt, js_std::global::parse_int), diff --git a/crates/dash_vm/src/value/function/mod.rs b/crates/dash_vm/src/value/function/mod.rs index 12b7174e..3e8a0891 100755 --- a/crates/dash_vm/src/value/function/mod.rs +++ b/crates/dash_vm/src/value/function/mod.rs @@ -286,9 +286,10 @@ pub(crate) fn adjust_stack_from_flat_call( // NB: Order is important, this needs to happen before pushing remaining // missing undefined values and truncating let rest = if user_function.inner().rest_local.is_some() { + let stack_len = scope.stack.len(); let args = scope .stack - .drain(old_sp + expected_args..) + .drain((old_sp + expected_args).min(stack_len)..) .map(PropertyValue::static_default) .collect();