From 14b381aae4f59d4940c0425422c58cf0dc98159f Mon Sep 17 00:00:00 2001 From: Kevin Velasco Date: Mon, 14 Jun 2021 09:38:11 +0800 Subject: [PATCH] Move all the rendering code to the builtin function struct --- boa/src/builtins/function/mod.rs | 73 ++++++++++++++++++++++++++++++++ boa/src/value/mod.rs | 67 ++--------------------------- 2 files changed, 76 insertions(+), 64 deletions(-) diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 036f0c324a0..4a3957ad46d 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -329,6 +329,78 @@ impl BuiltInFunctionObject { // TODO?: 5. PrepareForTailCall context.call(this, &this_arg, &arg_list) } + + fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + let name = { + // Is there a case here where if there is no name field on a value + // We it should default to None? Do all functions have names set? + let value = this.get_field("name", &mut *context)?; + if value.is_null_or_undefined() { + None + } else { + Some(value.to_string(context)?) + } + }; + + let function = { + let object = this.clone().as_object().expect("Should be an object"); + + let func = object + .borrow() + .as_function() + .map(|f| f.clone()) + .expect("Should be a function"); + + func + }; + + match (&function, name) { + (Function::BuiltIn(_, _), Some(name)) => { + Ok(format!("function {}() {{\n [native Code]\n}}", &name).into()) + } + (Function::Ordinary { body, params, .. }, Some(name)) => { + let arguments: String = params + .iter() + .map(|param| param.name()) + .collect::>() + .join(", "); + + let statement_list = &*body; + // This is a kluge. The implementaion in browser seems to suggest that + // the value here is printed exactly as defined in source. I'm not sure if + // that's possible here, but for now here's a dumb heuristic that prints functions + let is_multiline = { + let value = statement_list.to_string(); + value.lines().count() > 1 + }; + if is_multiline { + Ok( + // ?? For some reason statement_list string implementation + // sticks a \n at the end no matter what + format!( + "{}({}) {{\n{}}}", + &name, + arguments, + statement_list.to_string() + ) + .into(), + ) + } else { + Ok(format!( + "{}({}) {{{}}}", + &name, + arguments, + // The trim here is to remove a \n stuck at the end + // of the statement_list to_string method + statement_list.to_string().trim() + ) + .into()) + } + } + + _ => Ok("TODO".into()), + } + } } impl BuiltIn for BuiltInFunctionObject { @@ -358,6 +430,7 @@ impl BuiltIn for BuiltInFunctionObject { .length(Self::LENGTH) .method(Self::call, "call", 1) .method(Self::apply, "apply", 1) + .method(Self::to_string, "toString", 0) .build(); (Self::NAME, function_object.into(), Self::attribute()) diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index 84afa76541f..51325674885 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -612,70 +612,9 @@ impl Value { Value::String(string) => Ok(string.clone()), Value::Symbol(_) => Err(context.construct_type_error("can't convert symbol to string")), Value::BigInt(ref bigint) => Ok(bigint.to_string().into()), - Value::Object(gc_object) => { - if let Some(function) = gc_object.borrow().as_function() { - use crate::builtins::function::Function; - let name = { - // Is there a case here where if there is no name field on a value - // We it should default to None? Do all functions have names set? - let value = self.get_field("name", &mut *context)?; - if value.is_null_or_undefined() { - None - } else { - Some(value.to_string(context)?) - } - }; - - match (function, name) { - (Function::BuiltIn(_, _), Some(name)) => { - Ok(format!("function {}() {{\n [native Code]\n}}", &name).into()) - } - (Function::Ordinary { body, params, .. }, Some(name)) => { - let arguments: String = params - .iter() - .map(|param| param.name()) - .collect::>() - .join(", "); - - let statement_list = &**body; - // This is a kluge. The implementaion in browser seems to suggest that - // the value here is printed exactly as defined in source. I'm not sure if - // that's possible here, but for now here's a dumb heuristic that prints functions - let is_multiline = { - let value = statement_list.to_string(); - value.lines().count() > 1 - }; - if is_multiline { - Ok( - // ?? For some reason statement_list string implementation - // sticks a \n at the end no matter what - format!( - "{}({}) {{\n{}}}", - &name, - arguments, - statement_list.to_string() - ) - .into(), - ) - } else { - Ok(format!( - "{}({}) {{{}}}", - &name, - arguments, - // The trim here is to remove a \n stuck at the end - // of the statement_list to_string method - statement_list.to_string().trim() - ) - .into()) - } - } - - _ => Ok("TODO".into()), - } - } else { - let primitive = self.to_primitive(context, PreferredType::String)?; - primitive.to_string(context) - } + Value::Object(_) => { + let primitive = self.to_primitive(context, PreferredType::String)?; + primitive.to_string(context) } } }