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 <alekratz@gmail.com>
This commit is contained in:
2020-10-19 17:28:38 -07:00
parent fee1ce2a47
commit 480055782e
3 changed files with 98 additions and 14 deletions

View File

@@ -1,7 +1,7 @@
use crate::{obj::{prelude::*, reserved::*}, vm::error::*}; use crate::{obj::{prelude::*, reserved::*}, vm::error::*};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use shredder::Scan; use shredder::Scan;
use std::{any::Any, fmt::{Debug, Formatter, self}}; use std::fmt::{Debug, Formatter, self};
pub type IntRef = ObjRef<Int>; pub type IntRef = ObjRef<Int>;
@@ -22,8 +22,9 @@ impl Int {
attrs: Default::default(), attrs: Default::default(),
}, },
vtable: |obj_ref: ObjRef| vtable! { 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()), 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()), 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()), 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()), 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 /// Int.__str__(self) impl
static INT_STR_FUN: Lazy<NativeFunRef> = Lazy::new(|| { static INT_STR_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
NativeFun::new_obj(1, |_callee, vm, args| { NativeFun::new_obj(1, |_callee, vm, args| {
read_obj!(let int_obj = &args[0]); read_obj_downcast!(let int_obj: Option<&Int> = &args[0]);
if let Some(int_obj) = Any::downcast_ref::<Int>(int_obj.as_any()) { let int_obj = int_obj.ok_or_else(|| Error::ValueError {
vm.push(Str::new_obj(int_obj.value.to_string())); error: "expected Int value".to_string(),
} else { })?;
panic!("{:?} is not an int", int_obj) 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<NativeFunRef> = 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) Ok(crate::vm::signal::Signal::Return)
}) })

View File

@@ -45,6 +45,7 @@ name!(SELF_MEMBER_NAME, "__self__");
name!(FUNC_MEMBER_NAME, "__func__"); name!(FUNC_MEMBER_NAME, "__func__");
name!(REPR_MEMBER_NAME, "__repr__"); name!(REPR_MEMBER_NAME, "__repr__");
name!(STR_MEMBER_NAME, "__str__"); name!(STR_MEMBER_NAME, "__str__");
name!(INT_MEMBER_NAME, "__int__");
// //
// Predefined VM-aware symbols // Predefined VM-aware symbols

View File

@@ -1,9 +1,11 @@
use crate::obj::prelude::*; use crate::{obj::{prelude::*, reserved::*}, vm::error::*};
use once_cell::sync::Lazy;
use shredder::Scan; use shredder::Scan;
use std::fmt::{Debug, Formatter, self};
pub type StrRef = ObjRef<Str>; pub type StrRef = ObjRef<Str>;
#[derive(Debug, Scan)] #[derive(Scan)]
pub struct Str { pub struct Str {
vtable: Vtable, vtable: Vtable,
attrs: Attrs, attrs: Attrs,
@@ -12,11 +14,18 @@ pub struct Str {
impl Str { impl Str {
pub fn new_obj(value: String) -> StrRef { pub fn new_obj(value: String) -> StrRef {
StrRef::new(Str { self_referring_obj! {
vtable: Default::default(), Self {
attrs: Default::default(), value,
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 { pub fn value(&self) -> &String {
@@ -25,3 +34,62 @@ impl Str {
} }
impl_obj_readonly!(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<NativeFunRef> = 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<NativeFunRef> = 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<NativeFunRef> = 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)
})
});