Objs replace Values

* Obj is now a trait instead of a struct
* Value enum is gone, replaced with individual structs that implement
  Obj
* All instances where a Value was used, a Gc<(dyn Obj + 'static)> takes
  its place. ObjPtr is shorthand for this.
* A __str__ method for objects is implemented for a couple builtin types
  as a proof-of-concept
* println and print builtin functions are implemented using this
  interface

There's still a lot to do, mostly with interned values. For example,
whenever a new string object is created, a new __str__ function object
is created each time, rather than reusing the first one that was
created. Stuff like that.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2022-01-18 14:39:06 -08:00
parent 248dfd3630
commit 070e497e1f
6 changed files with 251 additions and 148 deletions

View File

@@ -1,4 +1,4 @@
use crate::object::{BuiltinExit, Int, Value};
use crate::object::{BuiltinExit, Obj, StrObj};
use crate::vm::{error::RuntimeError, machine::MachineBuilder};
impl MachineBuilder {
@@ -19,6 +19,7 @@ impl MachineBuilder {
panic!();
});
/*
//
// if
//
@@ -26,6 +27,7 @@ impl MachineBuilder {
let if_false = machine.stack_pop()?;
let if_true = machine.stack_pop()?;
let condition = machine.stack_pop()?;
let value = if condition.is_truthy() {
if_true
} else {
@@ -41,25 +43,75 @@ impl MachineBuilder {
.into());
}
});
*/
//
// print
//
self.register_builtin_fun("print", |machine, _| {
let value = machine.stack_pop()?;
print!("{}", value);
Ok(BuiltinExit::Return)
self.register_builtin_fun("print", |machine, reentry| {
const CALL_STR: usize = 1;
if reentry == 0 {
let obj = machine
.stack_peek()
.ok_or_else(|| RuntimeError::StackUnderflow)?;
// Push the value's __str__ value, call it, and then print it.
let str_fun = obj
.get("__str__")
.ok_or_else(|| RuntimeError::UnsetWord("__str__".to_string()))?;
let call_site = machine.call_stack().last().unwrap().call_site().cloned();
str_fun.call(call_site, machine)?;
Ok(BuiltinExit::Resume(CALL_STR))
} else if reentry == CALL_STR {
let obj_ptr = machine.stack_pop()?;
let str_obj: &(dyn Obj + 'static) = &*obj_ptr;
if let Some(string) = str_obj.as_any().downcast_ref::<StrObj>() {
print!("{}", string.value());
Ok(BuiltinExit::Return)
} else {
panic!(
"expected StrObj from __str__ function but got {:?} instead",
str_obj
);
}
} else {
unreachable!()
}
});
//
// println
//
self.register_builtin_fun("println", |machine, _| {
let value = machine.stack_pop()?;
println!("{}", value);
Ok(BuiltinExit::Return)
self.register_builtin_fun("println", |machine, reentry| {
const CALL_STR: usize = 1;
if reentry == 0 {
let obj = machine
.stack_peek()
.ok_or_else(|| RuntimeError::StackUnderflow)?;
// Push the value's __str__ value, call it, and then print it.
let str_fun = obj
.get("__str__")
.ok_or_else(|| RuntimeError::UnsetWord("__str__".to_string()))?;
let call_site = machine.call_stack().last().unwrap().call_site().cloned();
str_fun.call(call_site, machine)?;
Ok(BuiltinExit::Resume(CALL_STR))
} else if reentry == CALL_STR {
let obj_ptr = machine.stack_pop()?;
let str_obj: &(dyn Obj + 'static) = &*obj_ptr;
if let Some(string) = str_obj.as_any().downcast_ref::<StrObj>() {
println!("{}", string.value());
Ok(BuiltinExit::Return)
} else {
panic!(
"expected StrObj from __str__ function but got {:?} instead",
str_obj
);
}
} else {
unreachable!()
}
});
/*
//
// ==
//
@@ -79,5 +131,6 @@ impl MachineBuilder {
machine.stack_push(Value::Int((lhs != rhs) as Int))?;
Ok(BuiltinExit::Return)
});
*/
}
}