Change to_repr/to_str implementation story
Let's talk about to_repr and to_str. to_repr tries to do what Python's `repr` function does - that is, it converts an object into a developer-readable (but maybe not human-readable) string. This function is implemented for every object, and may very well just write out "<MyType at 0x12345678>". to_str, on the other hand, tries to turn an object into an explicitly human-readable format. In Python (which we are modeling a lot of our design after), the str() function usually will end up calling `repr()` itself, if no other implementation has been provided. Previously in our implementation, there was a bit of a disconnect between `to_repr` and `to_str`, versus `Debug` and `Display`. `to_repr` would kind of do its own thing, and then maybe call either `Display` or `Debug` to format an object. Consequently, `to_str` would kind of do its own thing too - usually calling `to_repr` but not always. This change attempts to strengthen the definitions of `to_repr` and `to_str`. *In general*, a call to `to_repr` should be calling an object's `Debug::fmt` function, and *in general* a call to `to_str()` should be calling an object's `Display::fmt` function. Often, the `Display::fmt` will just end up calling `Debug::fmt` itself, but now the `to_str()` and `to_repr()` interfaces are much better defined than they used to be. The only major downside is that we are giving up the `Debug` implementation for language logic, rather than debugging-the-language-itself logic. I can see this biting us down the road if we ever need a Rust-style `Debug` implementation, but for now, I think this is going to serve our needs just fine. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -54,7 +54,7 @@ pub enum FunctionState {
|
||||
|
||||
pub type BuiltinFunctionPtr = fn(vm: &mut Vm, function_state: FunctionState) -> FunctionResult;
|
||||
|
||||
#[derive(Debug, Trace, Finalize)]
|
||||
#[derive(Trace, Finalize)]
|
||||
pub struct BuiltinFunction {
|
||||
base: BaseObj,
|
||||
#[unsafe_ignore_trace]
|
||||
@@ -80,12 +80,18 @@ impl BuiltinFunction {
|
||||
arity: Argc,
|
||||
);
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
pub fn name(&self) -> &Rc<String> {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BuiltinFunction {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for BuiltinFunction {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
fmt,
|
||||
@@ -128,7 +134,7 @@ impl Object for BuiltinFunction {
|
||||
// UserFunction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Debug, Clone, Trace, Finalize)]
|
||||
#[derive(Clone, Trace, Finalize)]
|
||||
pub struct UserFunction {
|
||||
base: BaseObj,
|
||||
#[unsafe_ignore_trace]
|
||||
@@ -152,7 +158,7 @@ impl UserFunction {
|
||||
|
||||
impl_create!(chunk: Chunk, arity: Argc);
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
pub fn name(&self) -> &Rc<String> {
|
||||
&self.name
|
||||
}
|
||||
|
||||
@@ -170,6 +176,12 @@ impl UserFunction {
|
||||
}
|
||||
|
||||
impl Display for UserFunction {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for UserFunction {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
fmt,
|
||||
@@ -222,16 +234,6 @@ pub struct Method {
|
||||
function: ObjP,
|
||||
}
|
||||
|
||||
impl Debug for Method {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Method")
|
||||
.field("base", &self.base)
|
||||
.field("self_binding", &format!("{}", self.self_binding.borrow()))
|
||||
.field("function", &self.function)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn new(self_binding: ObjP, function: ObjP) -> Self {
|
||||
Self {
|
||||
@@ -254,7 +256,37 @@ impl Method {
|
||||
|
||||
impl Display for Method {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{}", self.function.borrow())
|
||||
Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Method {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let function_name: Rc<_> = if let Some(function) = self
|
||||
.function
|
||||
.borrow()
|
||||
.as_any()
|
||||
.downcast_ref::<BuiltinFunction>()
|
||||
{
|
||||
Rc::clone(&function.name())
|
||||
} else if let Some(function) = self
|
||||
.function
|
||||
.borrow()
|
||||
.as_any()
|
||||
.downcast_ref::<UserFunction>()
|
||||
{
|
||||
function.name().clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
write!(
|
||||
fmt,
|
||||
"<Method {}.{}/{} at {}>",
|
||||
self.self_binding.borrow().ty_name(),
|
||||
function_name,
|
||||
self.function.borrow().arity().unwrap(),
|
||||
self as *const _ as usize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user