From 480055782e577903ef03a15470a54fb912c0df03 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Mon, 19 Oct 2020 17:28:38 -0700 Subject: [PATCH] Add Str.__repr__, Str.__str__, Str.__int__, Int.__repr__, and Int.__int__ builtins Builtin functions for builtin types. This allows the "hello world" program to actually work how it's supposed to. Signed-off-by: Alek Ratzloff --- src/obj/int.rs | 29 ++++++++++++---- src/obj/reserved.rs | 1 + src/obj/str.rs | 82 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/obj/int.rs b/src/obj/int.rs index 06032f7..e4a0d00 100644 --- a/src/obj/int.rs +++ b/src/obj/int.rs @@ -1,7 +1,7 @@ use crate::{obj::{prelude::*, reserved::*}, vm::error::*}; use once_cell::sync::Lazy; use shredder::Scan; -use std::{any::Any, fmt::{Debug, Formatter, self}}; +use std::fmt::{Debug, Formatter, self}; pub type IntRef = ObjRef; @@ -22,8 +22,9 @@ impl Int { attrs: Default::default(), }, vtable: |obj_ref: ObjRef| vtable! { - // TODO needs Method type so this function is given an argument when called + REPR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()), STR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()), + INT_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_INT_FUN.clone()), PLUS_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_ADD_FUN.clone()), MINUS_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_SUB_FUN.clone()), TIMES_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_MUL_FUN.clone()), @@ -54,12 +55,26 @@ impl Debug for Int { /// Int.__str__(self) impl static INT_STR_FUN: Lazy = Lazy::new(|| { NativeFun::new_obj(1, |_callee, vm, args| { - read_obj!(let int_obj = &args[0]); - if let Some(int_obj) = Any::downcast_ref::(int_obj.as_any()) { - vm.push(Str::new_obj(int_obj.value.to_string())); - } else { - panic!("{:?} is not an int", int_obj) + read_obj_downcast!(let int_obj: Option<&Int> = &args[0]); + let int_obj = int_obj.ok_or_else(|| Error::ValueError { + error: "expected Int value".to_string(), + })?; + vm.push(Str::new_obj(int_obj.value.to_string())); + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Int.__int__(self) impl +static INT_INT_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(1, |_callee, vm, args| { + { + read_obj_downcast!(let int_obj: Option<&Int> = &args[0]); + int_obj.ok_or_else(|| Error::ValueError { + error: "expected Int value".to_string(), + })?; } + // just push a copy of the "self" object + vm.push(args[0].clone()); Ok(crate::vm::signal::Signal::Return) }) diff --git a/src/obj/reserved.rs b/src/obj/reserved.rs index d5f7642..4b8c471 100644 --- a/src/obj/reserved.rs +++ b/src/obj/reserved.rs @@ -45,6 +45,7 @@ name!(SELF_MEMBER_NAME, "__self__"); name!(FUNC_MEMBER_NAME, "__func__"); name!(REPR_MEMBER_NAME, "__repr__"); name!(STR_MEMBER_NAME, "__str__"); +name!(INT_MEMBER_NAME, "__int__"); // // Predefined VM-aware symbols diff --git a/src/obj/str.rs b/src/obj/str.rs index 9270e2a..0f3aa81 100644 --- a/src/obj/str.rs +++ b/src/obj/str.rs @@ -1,9 +1,11 @@ -use crate::obj::prelude::*; +use crate::{obj::{prelude::*, reserved::*}, vm::error::*}; +use once_cell::sync::Lazy; use shredder::Scan; +use std::fmt::{Debug, Formatter, self}; pub type StrRef = ObjRef; -#[derive(Debug, Scan)] +#[derive(Scan)] pub struct Str { vtable: Vtable, attrs: Attrs, @@ -12,11 +14,18 @@ pub struct Str { impl Str { pub fn new_obj(value: String) -> StrRef { - StrRef::new(Str { - vtable: Default::default(), - attrs: Default::default(), - value, - }) + self_referring_obj! { + Self { + value, + vtable: Default::default(), + attrs: Default::default(), + }, + vtable: |obj_ref: ObjRef| vtable! { + STR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), STR_STR_FUN.clone()), + REPR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), STR_REPR_FUN.clone()), + INT_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), STR_INT_FUN.clone()), + }, + } } pub fn value(&self) -> &String { @@ -25,3 +34,62 @@ impl Str { } impl_obj_readonly!(Str); + +impl Debug for Str { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + fmt.debug_struct("Str") + .field("value", &self.value) + .finish() + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Builtin Str functions +//////////////////////////////////////////////////////////////////////////////// + +/// Str.__str__(self) impl +static STR_STR_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(1, |_callee, vm, args| { + { + read_obj_downcast!(let str_obj: Option<&Str> = &args[0]); + str_obj.ok_or_else(|| Error::ValueError { + error: "expected Str value".to_string(), + })?; + } + // just push a copy of the "self" object + vm.push(args[0].clone()); + + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Str.__repr__(self) impl +static STR_REPR_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(1, |_callee, vm, args| { + read_obj_downcast!(let str_obj: Option<&Str> = &args[0]); + let str_obj = str_obj.ok_or_else(|| Error::ValueError { + error: "expected Str value".to_string(), + })?; + + let repr = format!("\"{}\"", str_obj.value.escape_debug()); + vm.push(Str::new_obj(repr)); + + Ok(crate::vm::signal::Signal::Return) + }) +}); + +/// Str.__int__(self) impl +static STR_INT_FUN: Lazy = Lazy::new(|| { + NativeFun::new_obj(1, |_callee, vm, args| { + read_obj_downcast!(let str_obj: Option<&Str> = &args[0]); + let str_obj = str_obj.ok_or_else(|| Error::ValueError { + error: "expected Str value".to_string(), + })?; + + let int: i64 = str_obj.value.parse() + .map_err(|_| Error::ValueError { error: "invalid Int value".to_string(), })?; + vm.push(Int::new_obj(int)); + + Ok(crate::vm::signal::Signal::Return) + }) +});