Browse Source

Allow Value.set_field to thow (#1329)

pull/1334/head
raskad 3 years ago committed by GitHub
parent
commit
8963938fd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      boa/src/builtins/array/mod.rs
  2. 2
      boa/src/builtins/error/eval.rs
  3. 2
      boa/src/builtins/error/mod.rs
  4. 2
      boa/src/builtins/error/range.rs
  5. 2
      boa/src/builtins/error/reference.rs
  6. 2
      boa/src/builtins/error/syntax.rs
  7. 2
      boa/src/builtins/error/type.rs
  8. 2
      boa/src/builtins/error/uri.rs
  9. 4
      boa/src/builtins/json/mod.rs
  10. 2
      boa/src/builtins/reflect/mod.rs
  11. 10
      boa/src/builtins/regexp/mod.rs
  12. 13
      boa/src/context.rs
  13. 2
      boa/src/syntax/ast/node/declaration/function_decl/mod.rs
  14. 2
      boa/src/syntax/ast/node/declaration/function_expr/mod.rs
  15. 4
      boa/src/syntax/ast/node/operator/assign/mod.rs
  16. 2
      boa/src/syntax/ast/node/operator/bin_op/mod.rs
  17. 8
      boa/src/syntax/ast/node/template/mod.rs
  18. 33
      boa/src/value/mod.rs
  19. 2
      boa/src/value/tests.rs

21
boa/src/builtins/array/mod.rs

@ -155,12 +155,12 @@ impl Array {
if !length.is_number() { if !length.is_number() {
array.set_property(0, DataDescriptor::new(length, Attribute::all())); array.set_property(0, DataDescriptor::new(length, Attribute::all()));
array.set_field("length", 1, context)?; array.set_field("length", 1, true, context)?;
} else { } else {
if length.is_double() { if length.is_double() {
return context.throw_range_error("Invalid array length"); return context.throw_range_error("Invalid array length");
} }
array.set_field("length", length.to_u32(context).unwrap(), context)?; array.set_field("length", length.to_u32(context).unwrap(), true, context)?;
} }
Ok(array) Ok(array)
@ -325,6 +325,7 @@ impl Array {
array_ptr.set_field( array_ptr.set_field(
"length", "length",
Value::from(orig_length.wrapping_add(add_values.len())), Value::from(orig_length.wrapping_add(add_values.len())),
false,
context, context,
)?; )?;
@ -374,7 +375,7 @@ impl Array {
} }
// set length // set length
array.set_field("length", args.len(), context)?; array.set_field("length", args.len(), true, context)?;
Ok(array) Ok(array)
} }
@ -454,7 +455,7 @@ impl Array {
let pop_index = curr_length.wrapping_sub(1); let pop_index = curr_length.wrapping_sub(1);
let pop_value: Value = this.get_field(pop_index.to_string(), context)?; let pop_value: Value = this.get_field(pop_index.to_string(), context)?;
this.remove_property(pop_index); this.remove_property(pop_index);
this.set_field("length", Value::from(pop_index), context)?; this.set_field("length", Value::from(pop_index), true, context)?;
Ok(pop_value) Ok(pop_value)
} }
@ -616,7 +617,7 @@ impl Array {
let len = this.get_field("length", context)?.to_length(context)?; let len = this.get_field("length", context)?.to_length(context)?;
if len == 0 { if len == 0 {
this.set_field("length", 0, context)?; this.set_field("length", 0, true, context)?;
return Ok(Value::undefined()); return Ok(Value::undefined());
} }
@ -636,7 +637,7 @@ impl Array {
let final_index = len.wrapping_sub(1); let final_index = len.wrapping_sub(1);
this.remove_property(final_index); this.remove_property(final_index);
this.set_field("length", Value::from(final_index), context)?; this.set_field("length", Value::from(final_index), true, context)?;
Ok(first) Ok(first)
} }
@ -682,7 +683,7 @@ impl Array {
} }
let temp = len.wrapping_add(arg_c); let temp = len.wrapping_add(arg_c);
this.set_field("length", Value::from(temp), context)?; this.set_field("length", Value::from(temp), true, context)?;
Ok(Value::from(temp)) Ok(Value::from(temp))
} }
@ -1011,7 +1012,7 @@ impl Array {
&Value::undefined(), &Value::undefined(),
&Value::undefined(), &Value::undefined(),
)?; )?;
new_array.set_field("length", len.to_length(context)?, context)?; new_array.set_field("length", len.to_length(context)?, false, context)?;
Ok(new_array) Ok(new_array)
} }
@ -1058,7 +1059,7 @@ impl Array {
&mapper_function, &mapper_function,
&this_arg, &this_arg,
)?; )?;
new_array.set_field("length", len.to_length(context)?, context)?; new_array.set_field("length", len.to_length(context)?, false, context)?;
// 6. Return A // 6. Return A
Ok(new_array) Ok(new_array)
@ -1271,7 +1272,7 @@ impl Array {
); );
new_array_len = new_array_len.saturating_add(1); new_array_len = new_array_len.saturating_add(1);
} }
new_array.set_field("length", Value::from(new_array_len), context)?; new_array.set_field("length", Value::from(new_array_len), true, context)?;
Ok(new_array) Ok(new_array)
} }

2
boa/src/builtins/error/eval.rs

@ -76,7 +76,7 @@ impl EvalError {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

2
boa/src/builtins/error/mod.rs

@ -92,7 +92,7 @@ impl Error {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

2
boa/src/builtins/error/range.rs

@ -73,7 +73,7 @@ impl RangeError {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

2
boa/src/builtins/error/reference.rs

@ -72,7 +72,7 @@ impl ReferenceError {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

2
boa/src/builtins/error/syntax.rs

@ -75,7 +75,7 @@ impl SyntaxError {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

2
boa/src/builtins/error/type.rs

@ -78,7 +78,7 @@ impl TypeError {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

2
boa/src/builtins/error/uri.rs

@ -74,7 +74,7 @@ impl UriError {
let this = Value::from(obj); let this = Value::from(obj);
if let Some(message) = args.get(0) { if let Some(message) = args.get(0) {
if !message.is_undefined() { if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?; this.set_field("message", message.to_string(context)?, false, context)?;
} }
} }

4
boa/src/builtins/json/mod.rs

@ -80,7 +80,7 @@ impl Json {
match args.get(1) { match args.get(1) {
Some(reviver) if reviver.is_function() => { Some(reviver) if reviver.is_function() => {
let mut holder = Value::object(Object::default()); let mut holder = Value::object(Object::default());
holder.set_field("", j, context)?; holder.set_field("", j, true, context)?;
Self::walk(reviver, context, &mut holder, &PropertyKey::from("")) Self::walk(reviver, context, &mut holder, &PropertyKey::from(""))
} }
_ => Ok(j), _ => Ok(j),
@ -111,7 +111,7 @@ impl Json {
let v = Self::walk(reviver, context, &mut value.clone(), &key); let v = Self::walk(reviver, context, &mut value.clone(), &key);
match v { match v {
Ok(v) if !v.is_undefined() => { Ok(v) if !v.is_undefined() => {
value.set_field(key, v, context)?; value.set_field(key, v, false, context)?;
} }
Ok(_) => { Ok(_) => {
value.remove_property(key); value.remove_property(key);

2
boa/src/builtins/reflect/mod.rs

@ -308,7 +308,7 @@ impl Reflect {
let keys = target.own_property_keys(); let keys = target.own_property_keys();
for (i, k) in keys.iter().enumerate() { for (i, k) in keys.iter().enumerate() {
result.set_field(i, k, context)?; result.set_field(i, k, true, context)?;
} }
Ok(result) Ok(result)

10
boa/src/builtins/regexp/mod.rs

@ -536,7 +536,7 @@ impl RegExp {
return context return context
.throw_type_error("RegExp.prototype.exec method called on incompatible value"); .throw_type_error("RegExp.prototype.exec method called on incompatible value");
}; };
this.set_field("lastIndex", Value::from(last_index), context)?; this.set_field("lastIndex", Value::from(last_index), true, context)?;
result result
} }
@ -616,7 +616,7 @@ impl RegExp {
return context.throw_type_error("exec method called on incompatible value"); return context.throw_type_error("exec method called on incompatible value");
}; };
this.set_field("lastIndex", Value::from(last_index), context)?; this.set_field("lastIndex", Value::from(last_index), true, context)?;
result result
} }
@ -742,7 +742,7 @@ impl RegExp {
let length = matches.len(); let length = matches.len();
let result = Value::from(matches); let result = Value::from(matches);
result.set_field("length", Value::from(length), context)?; result.set_field("length", Value::from(length), false, context)?;
result.set_data(ObjectData::Array); result.set_data(ObjectData::Array);
Ok(result) Ok(result)
@ -780,7 +780,7 @@ impl RegExp {
// 5. If SameValue(previousLastIndex, +0𝔽) is false, then // 5. If SameValue(previousLastIndex, +0𝔽) is false, then
if previous_last_index != 0 { if previous_last_index != 0 {
// a. Perform ? Set(rx, "lastIndex", +0𝔽, true). // a. Perform ? Set(rx, "lastIndex", +0𝔽, true).
this.set_field("lastIndex", 0, context)?; this.set_field("lastIndex", 0, true, context)?;
} }
// 6. Let result be ? RegExpExec(rx, S). // 6. Let result be ? RegExpExec(rx, S).
@ -792,7 +792,7 @@ impl RegExp {
// 8. If SameValue(currentLastIndex, previousLastIndex) is false, then // 8. If SameValue(currentLastIndex, previousLastIndex) is false, then
if current_last_index != previous_last_index { if current_last_index != previous_last_index {
// a. Perform ? Set(rx, "lastIndex", previousLastIndex, true). // a. Perform ? Set(rx, "lastIndex", previousLastIndex, true).
this.set_field("lastIndex", previous_last_index, context)?; this.set_field("lastIndex", previous_last_index, true, context)?;
} }
// 9. If result is null, return -1𝔽. // 9. If result is null, return -1𝔽.

13
boa/src/context.rs

@ -495,10 +495,10 @@ impl Context {
let val = Value::from(new_func); let val = Value::from(new_func);
// Set constructor field to the newly created Value (function object) // Set constructor field to the newly created Value (function object)
proto.set_field("constructor", val.clone(), self)?; proto.set_field("constructor", val.clone(), false, self)?;
val.set_field(PROTOTYPE, proto, self)?; val.set_field(PROTOTYPE, proto, false, self)?;
val.set_field("length", Value::from(params_len), self)?; val.set_field("length", Value::from(params_len), false, self)?;
Ok(val) Ok(val)
} }
@ -557,11 +557,14 @@ impl Context {
Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node
.obj() .obj()
.run(self)? .run(self)?
.set_field(get_const_field_node.field(), value, self)?), .set_field(get_const_field_node.field(), value, false, self)?),
Node::GetField(ref get_field) => { Node::GetField(ref get_field) => {
let field = get_field.field().run(self)?; let field = get_field.field().run(self)?;
let key = field.to_property_key(self)?; let key = field.to_property_key(self)?;
Ok(get_field.obj().run(self)?.set_field(key, value, self)?) Ok(get_field
.obj()
.run(self)?
.set_field(key, value, false, self)?)
} }
_ => self.throw_type_error(format!("invalid assignment to {}", node)), _ => self.throw_type_error(format!("invalid assignment to {}", node)),
} }

2
boa/src/syntax/ast/node/declaration/function_decl/mod.rs

@ -95,7 +95,7 @@ impl Executable for FunctionDecl {
)?; )?;
// Set the name and assign it in the current environment // Set the name and assign it in the current environment
val.set_field("name", self.name(), context)?; val.set_field("name", self.name(), false, context)?;
if context.has_binding(self.name()) { if context.has_binding(self.name()) {
context.set_mutable_binding(self.name(), val, true)?; context.set_mutable_binding(self.name(), val, true)?;

2
boa/src/syntax/ast/node/declaration/function_expr/mod.rs

@ -106,7 +106,7 @@ impl Executable for FunctionExpr {
)?; )?;
if let Some(name) = self.name() { if let Some(name) = self.name() {
val.set_field("name", Value::from(name), context)?; val.set_field("name", Value::from(name), false, context)?;
} }
Ok(val) Ok(val)

4
boa/src/syntax/ast/node/operator/assign/mod.rs

@ -72,13 +72,13 @@ impl Executable for Assign {
} }
Node::GetConstField(ref get_const_field) => { Node::GetConstField(ref get_const_field) => {
let val_obj = get_const_field.obj().run(context)?; let val_obj = get_const_field.obj().run(context)?;
val_obj.set_field(get_const_field.field(), val.clone(), context)?; val_obj.set_field(get_const_field.field(), val.clone(), false, context)?;
} }
Node::GetField(ref get_field) => { Node::GetField(ref get_field) => {
let object = get_field.obj().run(context)?; let object = get_field.obj().run(context)?;
let field = get_field.field().run(context)?; let field = get_field.field().run(context)?;
let key = field.to_property_key(context)?; let key = field.to_property_key(context)?;
object.set_field(key, val.clone(), context)?; object.set_field(key, val.clone(), false, context)?;
} }
_ => (), _ => (),
} }

2
boa/src/syntax/ast/node/operator/bin_op/mod.rs

@ -216,7 +216,7 @@ impl Executable for BinOp {
let v_r_a = get_const_field.obj().run(context)?; let v_r_a = get_const_field.obj().run(context)?;
let v_a = v_r_a.get_field(get_const_field.field(), context)?; let v_a = v_r_a.get_field(get_const_field.field(), context)?;
let value = Self::run_assign(op, v_a, self.rhs(), context)?; let value = Self::run_assign(op, v_a, self.rhs(), context)?;
v_r_a.set_field(get_const_field.field(), value.clone(), context)?; v_r_a.set_field(get_const_field.field(), value.clone(), false, context)?;
Ok(value) Ok(value)
} }
_ => Ok(Value::undefined()), _ => Ok(Value::undefined()),

8
boa/src/syntax/ast/node/template/mod.rs

@ -97,17 +97,17 @@ impl Executable for TaggedTemplate {
let raw_array = Array::new_array(context); let raw_array = Array::new_array(context);
for (i, raw) in self.raws.iter().enumerate() { for (i, raw) in self.raws.iter().enumerate() {
raw_array.set_field(i, Value::from(raw), context)?; raw_array.set_field(i, Value::from(raw), false, context)?;
} }
for (i, cooked) in self.cookeds.iter().enumerate() { for (i, cooked) in self.cookeds.iter().enumerate() {
if let Some(cooked) = cooked { if let Some(cooked) = cooked {
template_object.set_field(i, Value::from(cooked), context)?; template_object.set_field(i, Value::from(cooked), false, context)?;
} else { } else {
template_object.set_field(i, Value::undefined(), context)?; template_object.set_field(i, Value::undefined(), false, context)?;
} }
} }
template_object.set_field("raw", raw_array, context)?; template_object.set_field("raw", raw_array, false, context)?;
let (this, func) = match *self.tag { let (this, func) = match *self.tag {
Node::GetConstField(ref get_const_field) => { Node::GetConstField(ref get_const_field) => {

33
boa/src/value/mod.rs

@ -472,18 +472,47 @@ impl Value {
} }
/// Set the field in the value /// Set the field in the value
///
/// Similar to `7.3.4 Set ( O, P, V, Throw )`, but returns the value instead of a boolean.
///
/// More information:
/// - [ECMAScript][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-set-o-p-v-throw
#[inline] #[inline]
pub fn set_field<K, V>(&self, key: K, value: V, context: &mut Context) -> Result<Value> pub fn set_field<K, V>(
&self,
key: K,
value: V,
throw: bool,
context: &mut Context,
) -> Result<Value>
where where
K: Into<PropertyKey>, K: Into<PropertyKey>,
V: Into<Value>, V: Into<Value>,
{ {
// 1. Assert: Type(O) is Object.
// TODO: Currently the value may not be an object.
// In that case this function does nothing.
// 2. Assert: IsPropertyKey(P) is true.
// 3. Assert: Type(Throw) is Boolean.
let key = key.into(); let key = key.into();
let value = value.into(); let value = value.into();
let _timer = BoaProfiler::global().start_event("Value::set_field", "value"); let _timer = BoaProfiler::global().start_event("Value::set_field", "value");
if let Self::Object(ref obj) = *self { if let Self::Object(ref obj) = *self {
obj.clone() // 4. Let success be ? O.[[Set]](P, V, O).
let success = obj
.clone()
.set(key, value.clone(), obj.clone().into(), context)?; .set(key, value.clone(), obj.clone().into(), context)?;
// 5. If success is false and Throw is true, throw a TypeError exception.
// 6. Return success.
if !success && throw {
return Err(context.construct_type_error("Cannot assign value to property"));
} else {
return Ok(value);
}
} }
Ok(value) Ok(value)
} }

2
boa/src/value/tests.rs

@ -34,7 +34,7 @@ fn get_set_field() {
let obj = Value::new_object(&context); let obj = Value::new_object(&context);
// Create string and convert it to a Value // Create string and convert it to a Value
let s = Value::from("bar"); let s = Value::from("bar");
obj.set_field("foo", s, &mut context).unwrap(); obj.set_field("foo", s, false, &mut context).unwrap();
assert_eq!( assert_eq!(
obj.get_field("foo", &mut context) obj.get_field("foo", &mut context)
.unwrap() .unwrap()

Loading…
Cancel
Save