Typesystem global instance churn, again
I don't know if I'm ever going to get this right. It's a massive pain having to pass around the base "Method" type everywhere. It really makes a lot more sense to have it already defined someplace statically available. It makes doing like getting an attribute or vtable entry a lot more ergonomic. Previously we'd have to pass in the Method type every time, which was silly. Now we can just let the MethodInst::instantiate() function query it directly. Like, this is 100000% better. Also, I got rid of get_attr_lazy in favor of get_vtable_attr. I think that I want to unify get_attr and get_vtable_attr, but that would require a GC pointer to the "self" object on every object that you create. That's a bit iffy. But for now, things are feeling a little better and all the tests are passing, so that's good at least. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
109
src/builtins.rs
109
src/builtins.rs
@@ -1,19 +1,18 @@
|
|||||||
//! Builtin functions.
|
//! Builtin functions.
|
||||||
use std::collections::HashMap;
|
use crate::obj::function::{BuiltinFunctionInst, FunctionResult, FunctionState};
|
||||||
|
|
||||||
use crate::obj::function::{FunctionResult, FunctionState};
|
|
||||||
use crate::obj::*;
|
use crate::obj::*;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
|
|
||||||
pub fn init_global_builtins(builtins: &mut HashMap<String, ObjP>) {
|
pub fn init_global_builtins() {
|
||||||
macro_rules! builtins {
|
macro_rules! builtins {
|
||||||
($($builtin:ident / $argc:expr),* $(,)?) => {
|
($($builtin:ident / $argc:expr),* $(,)?) => {
|
||||||
$({
|
$({
|
||||||
let builtin_function = builtins.create_builtin_function(stringify!($builtin), $builtin, $argc);
|
let builtin_function = BuiltinFunctionInst::create(stringify!($builtin), $builtin, $argc);
|
||||||
builtins.insert(
|
$crate::obj::BUILTINS.with_borrow_mut(|builtins|
|
||||||
stringify!($builtin).to_string(),
|
builtins.insert(
|
||||||
builtin_function
|
stringify!($builtin).to_string(),
|
||||||
);
|
builtin_function
|
||||||
|
));
|
||||||
})*
|
})*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,17 +41,16 @@ pub(crate) fn println(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
|||||||
match state {
|
match state {
|
||||||
FunctionState::Begin => {
|
FunctionState::Begin => {
|
||||||
let obj = vm.peek();
|
let obj = vm.peek();
|
||||||
let method_type = vm.builtins().get("Method").unwrap().clone();
|
let method = obj
|
||||||
let to_repr = obj
|
.borrow()
|
||||||
.borrow_mut()
|
.get_vtable_attr(obj.clone(), "to_str")
|
||||||
.get_attr_lazy(obj.clone(), method_type, "to_str")
|
|
||||||
.expect("no to_str");
|
.expect("no to_str");
|
||||||
to_repr.borrow().call(vm, 0);
|
method.borrow().call(vm, 0);
|
||||||
FunctionResult::Yield(0)
|
FunctionResult::Yield(0)
|
||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
println!("{}", vm.frame_stack()[0].borrow());
|
println!("{}", vm.frame_stack()[0].borrow());
|
||||||
vm.create_nil().into()
|
NilInst::create().into()
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -62,17 +60,16 @@ pub(crate) fn print(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
|||||||
match state {
|
match state {
|
||||||
FunctionState::Begin => {
|
FunctionState::Begin => {
|
||||||
let obj = vm.peek();
|
let obj = vm.peek();
|
||||||
let method_type = vm.builtins().get("Method").unwrap().clone();
|
let method = obj
|
||||||
let to_repr = obj
|
.borrow()
|
||||||
.borrow_mut()
|
.get_vtable_attr(obj.clone(), "to_str")
|
||||||
.get_attr_lazy(obj.clone(), method_type, "to_str")
|
|
||||||
.expect("no to_str");
|
.expect("no to_str");
|
||||||
to_repr.borrow().call(vm, 0);
|
method.borrow().call(vm, 0);
|
||||||
FunctionResult::Yield(0)
|
FunctionResult::Yield(0)
|
||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
print!("{}", vm.frame_stack()[0].borrow());
|
print!("{}", vm.frame_stack()[0].borrow());
|
||||||
vm.create_nil().into()
|
NilInst::create().into()
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -91,12 +88,12 @@ impl BaseObjInst {
|
|||||||
match state {
|
match state {
|
||||||
FunctionState::Begin => {
|
FunctionState::Begin => {
|
||||||
let this = vm.frame_stack()[0].clone();
|
let this = vm.frame_stack()[0].clone();
|
||||||
let method_type = vm.builtins().get("Method").unwrap().clone();
|
let method = this
|
||||||
let to_repr = this
|
.borrow()
|
||||||
.borrow_mut()
|
.get_vtable_attr(this.clone(), "to_repr")
|
||||||
.get_attr_lazy(this.clone(), method_type, "to_repr")
|
.clone()
|
||||||
.expect("no to_repr");
|
.expect("no to_repr");
|
||||||
to_repr.borrow().call(vm, 0);
|
method.borrow().call(vm, 0);
|
||||||
FunctionResult::Yield(0)
|
FunctionResult::Yield(0)
|
||||||
}
|
}
|
||||||
FunctionState::Resume(0) => FunctionResult::Return,
|
FunctionState::Resume(0) => FunctionResult::Return,
|
||||||
@@ -106,12 +103,11 @@ impl BaseObjInst {
|
|||||||
|
|
||||||
pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let str_value = format!("{}", vm.frame_stack()[0].borrow());
|
let str_value = format!("{}", vm.frame_stack()[0].borrow());
|
||||||
vm.create_str(str_value).into()
|
StrInst::create(str_value).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_bool(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn to_bool(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
vm.create_bool(vm.frame_stack()[0].borrow().is_truthy())
|
BoolInst::create(vm.frame_stack()[0].borrow().is_truthy()).into()
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -122,14 +118,14 @@ impl BaseObjInst {
|
|||||||
let lhs = vm.frame_stack()[0].borrow();
|
let lhs = vm.frame_stack()[0].borrow();
|
||||||
let rhs = vm.frame_stack()[1].borrow();
|
let rhs = vm.frame_stack()[1].borrow();
|
||||||
let result = lhs.is_truthy() && rhs.is_truthy();
|
let result = lhs.is_truthy() && rhs.is_truthy();
|
||||||
vm.create_bool(result).into()
|
BoolInst::create(result).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn or(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn or(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].borrow();
|
let lhs = vm.frame_stack()[0].borrow();
|
||||||
let rhs = vm.frame_stack()[1].borrow();
|
let rhs = vm.frame_stack()[1].borrow();
|
||||||
let result = lhs.is_truthy() || rhs.is_truthy();
|
let result = lhs.is_truthy() || rhs.is_truthy();
|
||||||
vm.create_bool(result).into()
|
BoolInst::create(result).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ne(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
pub(crate) fn ne(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||||
@@ -137,19 +133,19 @@ impl BaseObjInst {
|
|||||||
FunctionState::Begin => {
|
FunctionState::Begin => {
|
||||||
// we actually want to be calling the lhs's eq function and then negate it
|
// we actually want to be calling the lhs's eq function and then negate it
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let method_type = vm.builtins().get("Method").unwrap().clone();
|
let method = lhs
|
||||||
let eq_method = lhs
|
.borrow()
|
||||||
.borrow_mut()
|
.get_vtable_attr(lhs.clone(), "__eq__")
|
||||||
.get_attr_lazy(lhs.clone(), method_type, "__eq__")
|
|
||||||
.expect("no __eq__");
|
.expect("no __eq__");
|
||||||
|
|
||||||
let rhs = vm.frame_stack()[1].clone();
|
let rhs = vm.frame_stack()[1].clone();
|
||||||
vm.push(rhs);
|
vm.push(rhs);
|
||||||
eq_method.borrow().call(vm, 1);
|
method.borrow().call(vm, 1);
|
||||||
FunctionResult::Yield(0)
|
FunctionResult::Yield(0)
|
||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
let result = !vm.peek().borrow().is_truthy();
|
let result = !vm.peek().borrow().is_truthy();
|
||||||
vm.create_bool(result).into()
|
BoolInst::create(result).into()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -161,24 +157,23 @@ impl BaseObjInst {
|
|||||||
let lhs = vm.frame_stack()[0].borrow();
|
let lhs = vm.frame_stack()[0].borrow();
|
||||||
let rhs = vm.frame_stack()[1].borrow();
|
let rhs = vm.frame_stack()[1].borrow();
|
||||||
let equals = lhs.equals(&*rhs);
|
let equals = lhs.equals(&*rhs);
|
||||||
vm.create_bool(equals).into()
|
BoolInst::create(equals).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn not(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
pub(crate) fn not(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||||
match state {
|
match state {
|
||||||
FunctionState::Begin => {
|
FunctionState::Begin => {
|
||||||
let obj = vm.peek();
|
let obj = vm.peek();
|
||||||
let method_type = vm.builtins().get("Method").unwrap().clone();
|
let method = obj
|
||||||
let to_bool = obj
|
.borrow()
|
||||||
.borrow_mut()
|
.get_vtable_attr(obj.clone(), "to_bool")
|
||||||
.get_attr_lazy(obj.clone(), method_type, "to_bool")
|
|
||||||
.expect("no to_bool");
|
.expect("no to_bool");
|
||||||
to_bool.borrow().call(vm, 0);
|
method.borrow().call(vm, 0);
|
||||||
FunctionResult::Yield(0)
|
FunctionResult::Yield(0)
|
||||||
}
|
}
|
||||||
FunctionState::Resume(0) => {
|
FunctionState::Resume(0) => {
|
||||||
let value = vm.peek().borrow().is_truthy();
|
let value = vm.peek().borrow().is_truthy();
|
||||||
vm.create_bool(!value).into()
|
BoolInst::create(!value).into()
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -223,14 +218,14 @@ impl StrInst {
|
|||||||
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
||||||
str_inst.str_value().as_str().escape_default().collect()
|
str_inst.str_value().as_str().escape_default().collect()
|
||||||
});
|
});
|
||||||
vm.create_str(format!("'{}'", escaped)).into()
|
StrInst::create(format!("'{}'", escaped)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn len(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn len(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let len = with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
let len = with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| {
|
||||||
str_inst.str_value().len() as i64
|
str_inst.str_value().len() as i64
|
||||||
});
|
});
|
||||||
vm.create_int(len).into()
|
IntInst::create(len).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn add(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
@@ -246,7 +241,7 @@ impl StrInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let new = format!("{}{}", lhs.borrow(), rhs.borrow());
|
let new = format!("{}{}", lhs.borrow(), rhs.borrow());
|
||||||
vm.create_str(new).into()
|
StrInst::create(new).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mul(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn mul(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
@@ -264,7 +259,7 @@ impl StrInst {
|
|||||||
};
|
};
|
||||||
let repeat_count = repeat_count.max(0) as usize;
|
let repeat_count = repeat_count.max(0) as usize;
|
||||||
let new = format!("{}", lhs.borrow()).repeat(repeat_count);
|
let new = format!("{}", lhs.borrow()).repeat(repeat_count);
|
||||||
vm.create_str(new).into()
|
StrInst::create(new).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,9 +276,9 @@ macro_rules! bin_op_math {
|
|||||||
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
||||||
vm.create_int(lhs_value $op int_inst.int_value())
|
IntInst::create(lhs_value $op int_inst.int_value())
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
||||||
vm.create_float(lhs_value as f64 $op float_inst.float_value())
|
FloatInst::create(lhs_value as f64 $op float_inst.float_value())
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst arithmetic operator - throw an exception when RHS is not Int, Float
|
// TODO IntInst arithmetic operator - throw an exception when RHS is not Int, Float
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
@@ -306,9 +301,9 @@ macro_rules! bin_op_logical {
|
|||||||
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
||||||
vm.create_bool(lhs_value $op int_inst.int_value())
|
BoolInst::create(lhs_value $op int_inst.int_value())
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
||||||
vm.create_bool((lhs_value as f64) $op float_inst.float_value())
|
BoolInst::create((lhs_value as f64) $op float_inst.float_value())
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst logical operator - throw an exception when RHS is not Int, Float
|
// TODO IntInst logical operator - throw an exception when RHS is not Int, Float
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
@@ -334,13 +329,13 @@ impl IntInst {
|
|||||||
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
let lhs_value = with_obj_downcast(lhs, IntInst::int_value);
|
||||||
|
|
||||||
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
let result = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::<IntInst>() {
|
||||||
vm.create_int(lhs_value * int_inst.int_value())
|
IntInst::create(lhs_value * int_inst.int_value())
|
||||||
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
} else if let Some(float_inst) = rhs.borrow().as_any().downcast_ref::<FloatInst>() {
|
||||||
vm.create_float(lhs_value as f64 * float_inst.float_value())
|
FloatInst::create(lhs_value as f64 * float_inst.float_value())
|
||||||
} else if let Some(str_inst) = rhs.borrow().as_any().downcast_ref::<StrInst>() {
|
} else if let Some(str_inst) = rhs.borrow().as_any().downcast_ref::<StrInst>() {
|
||||||
// TODO IntInst::mul - maybe convert this to just call Str.mul with arguments reversed?
|
// TODO IntInst::mul - maybe convert this to just call Str.mul with arguments reversed?
|
||||||
// Just so we have the same logic here
|
// Just so we have the same logic here
|
||||||
vm.create_str(str_inst.str_value().repeat(lhs_value as usize))
|
StrInst::create(str_inst.str_value().repeat(lhs_value as usize))
|
||||||
} else {
|
} else {
|
||||||
// TODO IntInst::mul - throw an exception when RHS is not Int, Float, Str
|
// TODO IntInst::mul - throw an exception when RHS is not Int, Float, Str
|
||||||
// BLOCKED-ON: exceptions
|
// BLOCKED-ON: exceptions
|
||||||
@@ -365,12 +360,12 @@ impl IntInst {
|
|||||||
pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn pos(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let value = with_obj_downcast(lhs, IntInst::int_value);
|
let value = with_obj_downcast(lhs, IntInst::int_value);
|
||||||
vm.create_int(value.abs()).into()
|
IntInst::create(value.abs()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
pub(crate) fn neg(vm: &mut Vm, _state: FunctionState) -> FunctionResult {
|
||||||
let lhs = vm.frame_stack()[0].clone();
|
let lhs = vm.frame_stack()[0].clone();
|
||||||
let value = with_obj_downcast(lhs, IntInst::int_value);
|
let value = with_obj_downcast(lhs, IntInst::int_value);
|
||||||
vm.create_int(-value).into()
|
IntInst::create(-value).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -407,22 +407,21 @@ impl Display for CompileError {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Compiler<'b> {
|
pub struct Compiler {
|
||||||
chunks: Vec<Chunk>,
|
chunks: Vec<Chunk>,
|
||||||
scopes: Vec<Scope>,
|
scopes: Vec<Scope>,
|
||||||
constants: Vec<ObjP>,
|
constants: Vec<ObjP>,
|
||||||
globals: Vec<String>,
|
globals: Vec<String>,
|
||||||
builtins: &'b HashMap<String, ObjP>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> Compiler<'b> {
|
impl Compiler {
|
||||||
pub fn new(builtins: &'b HashMap<String, ObjP>) -> Self {
|
pub fn new() -> Self {
|
||||||
Compiler {
|
Compiler {
|
||||||
chunks: Default::default(),
|
chunks: Default::default(),
|
||||||
scopes: Default::default(),
|
scopes: Default::default(),
|
||||||
constants: Default::default(),
|
constants: Default::default(),
|
||||||
globals: builtins.keys().map(ToString::to_string).collect(),
|
globals: BUILTINS
|
||||||
builtins,
|
.with_borrow(|builtins| builtins.keys().map(ToString::to_string).collect()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,7 +632,7 @@ impl<'b> Compiler<'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StmtVisitor for Compiler<'_> {
|
impl StmtVisitor for Compiler {
|
||||||
fn visit_expr_stmt(&mut self, stmt: &ExprStmt) -> Result<()> {
|
fn visit_expr_stmt(&mut self, stmt: &ExprStmt) -> Result<()> {
|
||||||
self.compile_expr(&stmt.expr)?;
|
self.compile_expr(&stmt.expr)?;
|
||||||
self.emit(stmt_line_number(stmt), Op::Pop);
|
self.emit(stmt_line_number(stmt), Op::Pop);
|
||||||
@@ -679,7 +678,7 @@ impl StmtVisitor for Compiler<'_> {
|
|||||||
|
|
||||||
fn visit_set_stmt(&mut self, stmt: &SetStmt) -> Result<()> {
|
fn visit_set_stmt(&mut self, stmt: &SetStmt) -> Result<()> {
|
||||||
self.compile_expr(&stmt.expr)?;
|
self.compile_expr(&stmt.expr)?;
|
||||||
let name = self.insert_constant(self.create_str(&stmt.name.text))?;
|
let name = self.insert_constant(StrInst::create(&stmt.name.text))?;
|
||||||
self.compile_expr(&stmt.rhs)?;
|
self.compile_expr(&stmt.rhs)?;
|
||||||
self.emit(stmt_line_number(stmt), Op::SetAttr(name));
|
self.emit(stmt_line_number(stmt), Op::SetAttr(name));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -698,7 +697,7 @@ impl StmtVisitor for Compiler<'_> {
|
|||||||
if let Some(expr) = &stmt.expr {
|
if let Some(expr) = &stmt.expr {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
} else {
|
} else {
|
||||||
let nil = self.insert_constant(self.create_nil())?;
|
let nil = self.insert_constant(NilInst::create())?;
|
||||||
self.emit(stmt_line_number(stmt), Op::PushConstant(nil));
|
self.emit(stmt_line_number(stmt), Op::PushConstant(nil));
|
||||||
}
|
}
|
||||||
self.emit(stmt_line_number(stmt), Op::Return);
|
self.emit(stmt_line_number(stmt), Op::Return);
|
||||||
@@ -708,7 +707,7 @@ impl StmtVisitor for Compiler<'_> {
|
|||||||
// condition
|
// condition
|
||||||
self.compile_expr(&stmt.condition)?;
|
self.compile_expr(&stmt.condition)?;
|
||||||
// call obj.to_bool()
|
// call obj.to_bool()
|
||||||
let bool_attr = self.insert_constant(self.create_str("to_bool"))?;
|
let bool_attr = self.insert_constant(StrInst::create("to_bool"))?;
|
||||||
self.emit(expr_line_number(&*stmt.condition), Op::GetAttr(bool_attr));
|
self.emit(expr_line_number(&*stmt.condition), Op::GetAttr(bool_attr));
|
||||||
self.emit(expr_line_number(&*stmt.condition), Op::Call(0));
|
self.emit(expr_line_number(&*stmt.condition), Op::Call(0));
|
||||||
let condition_patch_index = self.chunk().code.len();
|
let condition_patch_index = self.chunk().code.len();
|
||||||
@@ -755,7 +754,7 @@ impl StmtVisitor for Compiler<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprVisitor for Compiler<'_> {
|
impl ExprVisitor for Compiler {
|
||||||
fn visit_binary_expr(&mut self, expr: &BinaryExpr) -> Result<()> {
|
fn visit_binary_expr(&mut self, expr: &BinaryExpr) -> Result<()> {
|
||||||
static OP_NAMES: LazyLock<HashMap<TokenKind, &'static str>> = LazyLock::new(|| {
|
static OP_NAMES: LazyLock<HashMap<TokenKind, &'static str>> = LazyLock::new(|| {
|
||||||
hash_map! {
|
hash_map! {
|
||||||
@@ -780,7 +779,7 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
let mut exit_patch_index = 0;
|
let mut exit_patch_index = 0;
|
||||||
|
|
||||||
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
||||||
let constant_id = self.insert_constant(self.create_str("to_bool"))?;
|
let constant_id = self.insert_constant(StrInst::create("to_bool"))?;
|
||||||
self.emit(expr_line_number(&*expr.lhs), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(&*expr.lhs), Op::GetAttr(constant_id));
|
||||||
self.emit(expr_line_number(&*expr.lhs), Op::Call(0));
|
self.emit(expr_line_number(&*expr.lhs), Op::Call(0));
|
||||||
exit_patch_index = self.chunk().code.len();
|
exit_patch_index = self.chunk().code.len();
|
||||||
@@ -794,14 +793,14 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
let name = OP_NAMES
|
let name = OP_NAMES
|
||||||
.get(&expr.op.kind)
|
.get(&expr.op.kind)
|
||||||
.expect("invalid binary operator");
|
.expect("invalid binary operator");
|
||||||
let constant_id = self.insert_constant(self.create_str(name))?;
|
let constant_id = self.insert_constant(StrInst::create(name))?;
|
||||||
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
||||||
|
|
||||||
self.compile_expr(&expr.rhs)?;
|
self.compile_expr(&expr.rhs)?;
|
||||||
|
|
||||||
// convert RHS to a bool if we're doing AND or OR
|
// convert RHS to a bool if we're doing AND or OR
|
||||||
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
if let TokenKind::And | TokenKind::Or = expr.op.kind {
|
||||||
let constant_id = self.insert_constant(self.create_str("to_bool"))?;
|
let constant_id = self.insert_constant(StrInst::create("to_bool"))?;
|
||||||
self.emit(expr_line_number(&*expr.rhs), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(&*expr.rhs), Op::GetAttr(constant_id));
|
||||||
self.emit(expr_line_number(&*expr.rhs), Op::Call(0));
|
self.emit(expr_line_number(&*expr.rhs), Op::Call(0));
|
||||||
}
|
}
|
||||||
@@ -839,7 +838,7 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
});
|
});
|
||||||
self.compile_expr(&expr.expr)?;
|
self.compile_expr(&expr.expr)?;
|
||||||
let name = OP_NAMES.get(&expr.op.kind).expect("invalid unary operator");
|
let name = OP_NAMES.get(&expr.op.kind).expect("invalid unary operator");
|
||||||
let constant_id = self.insert_constant(self.create_str(name))?;
|
let constant_id = self.insert_constant(StrInst::create(name))?;
|
||||||
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
||||||
self.emit(expr_line_number(expr), Op::Call(0));
|
self.emit(expr_line_number(expr), Op::Call(0));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -863,7 +862,7 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
|
|
||||||
fn visit_get_expr(&mut self, expr: &GetExpr) -> Result<()> {
|
fn visit_get_expr(&mut self, expr: &GetExpr) -> Result<()> {
|
||||||
self.compile_expr(&expr.expr)?;
|
self.compile_expr(&expr.expr)?;
|
||||||
let constant_id = self.insert_constant(self.create_str(&expr.name.text))?;
|
let constant_id = self.insert_constant(StrInst::create(&expr.name.text))?;
|
||||||
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -889,25 +888,25 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
}
|
}
|
||||||
TokenKind::Number => {
|
TokenKind::Number => {
|
||||||
let obj = if expr.token.text.contains('.') {
|
let obj = if expr.token.text.contains('.') {
|
||||||
self.create_float(expr.token.text.parse().unwrap())
|
FloatInst::create(expr.token.text.parse().unwrap())
|
||||||
} else {
|
} else {
|
||||||
self.create_int(expr.token.text.parse().unwrap())
|
IntInst::create(expr.token.text.parse().unwrap())
|
||||||
};
|
};
|
||||||
let constant_id = self.insert_constant(obj)?;
|
let constant_id = self.insert_constant(obj)?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
TokenKind::String => {
|
TokenKind::String => {
|
||||||
let constant_id =
|
let constant_id =
|
||||||
self.insert_constant(self.create_str(unescape(&expr.token.text)))?;
|
self.insert_constant(StrInst::create(unescape(&expr.token.text)))?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
TokenKind::True | TokenKind::False => {
|
TokenKind::True | TokenKind::False => {
|
||||||
let constant_id =
|
let constant_id =
|
||||||
self.insert_constant(self.create_bool(expr.token.kind == TokenKind::True))?;
|
self.insert_constant(BoolInst::create(expr.token.kind == TokenKind::True))?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
TokenKind::Nil => {
|
TokenKind::Nil => {
|
||||||
let constant_id = self.insert_constant(self.create_nil())?;
|
let constant_id = self.insert_constant(NilInst::create())?;
|
||||||
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@@ -965,7 +964,7 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// always end with a "return nil"
|
// always end with a "return nil"
|
||||||
let nil = self.insert_constant(self.create_nil())?;
|
let nil = self.insert_constant(NilInst::create())?;
|
||||||
self.emit(end_line, Op::PushConstant(nil));
|
self.emit(end_line, Op::PushConstant(nil));
|
||||||
self.emit(end_line, Op::Return);
|
self.emit(end_line, Op::Return);
|
||||||
|
|
||||||
@@ -973,7 +972,7 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
|
|
||||||
// create the function
|
// create the function
|
||||||
let chunk = self.chunks.pop().unwrap();
|
let chunk = self.chunks.pop().unwrap();
|
||||||
let fun = self.create_user_function(chunk, expr.params.len() as Argc);
|
let fun = UserFunctionInst::create(chunk, expr.params.len() as Argc);
|
||||||
|
|
||||||
// register the function as a constant
|
// register the function as a constant
|
||||||
let fun_constant = self.insert_constant(fun)?;
|
let fun_constant = self.insert_constant(fun)?;
|
||||||
@@ -993,9 +992,3 @@ impl ExprVisitor for Compiler<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjFactory for Compiler<'_> {
|
|
||||||
fn builtins(&self) -> &HashMap<String, ObjP> {
|
|
||||||
&self.builtins
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
10
src/main.rs
10
src/main.rs
@@ -12,7 +12,6 @@ mod parser;
|
|||||||
mod token;
|
mod token;
|
||||||
mod vm;
|
mod vm;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
@@ -54,12 +53,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initialize type system
|
// initialize type system
|
||||||
let mut builtins = HashMap::new();
|
obj::init_types();
|
||||||
obj::init_types(&mut builtins);
|
crate::builtins::init_global_builtins();
|
||||||
crate::builtins::init_global_builtins(&mut builtins);
|
|
||||||
|
|
||||||
// compile
|
// compile
|
||||||
let (chunk, constants, globals) = compiler::Compiler::new(&builtins).compile(&ast)?;
|
let (chunk, constants, globals) = compiler::Compiler::new().compile(&ast)?;
|
||||||
|
|
||||||
if args.disassemble {
|
if args.disassemble {
|
||||||
disassemble::disassemble(&chunk, &constants, &globals);
|
disassemble::disassemble(&chunk, &constants, &globals);
|
||||||
@@ -67,7 +65,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run
|
// run
|
||||||
let mut vm = vm::Vm::new(chunk.into(), constants, globals, builtins);
|
let mut vm = vm::Vm::new(chunk.into(), constants, globals);
|
||||||
vm.run();
|
vm.run();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
251
src/obj.rs
251
src/obj.rs
@@ -6,6 +6,7 @@ mod macros;
|
|||||||
pub mod function;
|
pub mod function;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Debug, Display};
|
use std::fmt::{self, Debug, Display};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -14,7 +15,7 @@ use gc::{Finalize, Gc, GcCell, Trace};
|
|||||||
|
|
||||||
use crate::obj::function::*;
|
use crate::obj::function::*;
|
||||||
use crate::obj::macros::*;
|
use crate::obj::macros::*;
|
||||||
use crate::vm::{Argc, Chunk, Vm};
|
use crate::vm::{Argc, Vm};
|
||||||
|
|
||||||
pub type Ptr<T> = Gc<GcCell<T>>;
|
pub type Ptr<T> = Gc<GcCell<T>>;
|
||||||
pub type ObjP = Ptr<dyn Obj>;
|
pub type ObjP = Ptr<dyn Obj>;
|
||||||
@@ -71,7 +72,11 @@ pub fn upcast_obj<T: Obj>(ptr: Ptr<T>) -> ObjP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_types(builtins: &mut HashMap<String, ObjP>) {
|
thread_local! {
|
||||||
|
pub static BUILTINS: RefCell<HashMap<String, ObjP>> = RefCell::new(HashMap::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_types() {
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
macro_rules! types {
|
macro_rules! types {
|
||||||
(
|
(
|
||||||
@@ -84,6 +89,7 @@ pub fn init_types(builtins: &mut HashMap<String, ObjP>) {
|
|||||||
) => {{
|
) => {{
|
||||||
$(
|
$(
|
||||||
let $name = make_ptr(TypeInst::new(stringify!($name)));
|
let $name = make_ptr(TypeInst::new(stringify!($name)));
|
||||||
|
BUILTINS.with_borrow_mut(|builtins| builtins.insert(stringify!($name).to_string(), $name.clone()));
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// We have to instantiate these objects all by hand. This is because the `instantiate`
|
// We have to instantiate these objects all by hand. This is because the `instantiate`
|
||||||
@@ -93,13 +99,8 @@ pub fn init_types(builtins: &mut HashMap<String, ObjP>) {
|
|||||||
let base_type = $base_type.clone();
|
let base_type = $base_type.clone();
|
||||||
$name.borrow_mut().set_attr("__type__", base_type);
|
$name.borrow_mut().set_attr("__type__", base_type);
|
||||||
with_obj_downcast_mut($name.clone(), |type_inst: &mut TypeInst| { type_inst.base.is_instantiated = true; });
|
with_obj_downcast_mut($name.clone(), |type_inst: &mut TypeInst| { type_inst.base.is_instantiated = true; });
|
||||||
//$name.borrow_mut().base.is_instantiated = true;
|
|
||||||
})*
|
})*
|
||||||
|
|
||||||
$(
|
|
||||||
builtins.insert(stringify!($name).to_string(), $name.clone());
|
|
||||||
)*
|
|
||||||
|
|
||||||
$({
|
$({
|
||||||
$(
|
$(
|
||||||
let vtable_name = stringify!($vtable_name);
|
let vtable_name = stringify!($vtable_name);
|
||||||
@@ -118,49 +119,49 @@ pub fn init_types(builtins: &mut HashMap<String, ObjP>) {
|
|||||||
// type definitions
|
// type definitions
|
||||||
Type {
|
Type {
|
||||||
// Method conversion
|
// Method conversion
|
||||||
to_str => builtins.create_builtin_function("to_str", BaseObjInst::to_str, 1),
|
to_str => BuiltinFunctionInst::create("to_str", BaseObjInst::to_str, 1),
|
||||||
to_repr => builtins.create_builtin_function("to_repr", BaseObjInst::to_repr, 1),
|
to_repr => BuiltinFunctionInst::create("to_repr", BaseObjInst::to_repr, 1),
|
||||||
to_bool => builtins.create_builtin_function("to_bool", BaseObjInst::to_bool, 1),
|
to_bool => BuiltinFunctionInst::create("to_bool", BaseObjInst::to_bool, 1),
|
||||||
len => builtins.create_builtin_function("len", BaseObjInst::not_implemented_un, 1),
|
len => BuiltinFunctionInst::create("len", BaseObjInst::not_implemented_un, 1),
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => builtins.create_builtin_function("__add__", BaseObjInst::not_implemented_bin, 2),
|
__add__ => BuiltinFunctionInst::create("__add__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__sub__ => builtins.create_builtin_function("__sub__", BaseObjInst::not_implemented_bin, 2),
|
__sub__ => BuiltinFunctionInst::create("__sub__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__mul__ => builtins.create_builtin_function("__mul__", BaseObjInst::not_implemented_bin, 2),
|
__mul__ => BuiltinFunctionInst::create("__mul__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__div__ => builtins.create_builtin_function("__div__", BaseObjInst::not_implemented_bin, 2),
|
__div__ => BuiltinFunctionInst::create("__div__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__and__ => builtins.create_builtin_function("__and__", BaseObjInst::and, 2),
|
__and__ => BuiltinFunctionInst::create("__and__", BaseObjInst::and, 2),
|
||||||
__or__ => builtins.create_builtin_function("__or__", BaseObjInst::or, 2),
|
__or__ => BuiltinFunctionInst::create("__or__", BaseObjInst::or, 2),
|
||||||
__ne__ => builtins.create_builtin_function("__ne__", BaseObjInst::ne, 2),
|
__ne__ => BuiltinFunctionInst::create("__ne__", BaseObjInst::ne, 2),
|
||||||
__eq__ => builtins.create_builtin_function("__eq__", BaseObjInst::eq, 2),
|
__eq__ => BuiltinFunctionInst::create("__eq__", BaseObjInst::eq, 2),
|
||||||
__gt__ => builtins.create_builtin_function("__gt__", BaseObjInst::not_implemented_bin, 2),
|
__gt__ => BuiltinFunctionInst::create("__gt__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__ge__ => builtins.create_builtin_function("__ge__", BaseObjInst::not_implemented_bin, 2),
|
__ge__ => BuiltinFunctionInst::create("__ge__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__lt__ => builtins.create_builtin_function("__lt__", BaseObjInst::not_implemented_bin, 2),
|
__lt__ => BuiltinFunctionInst::create("__lt__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__le__ => builtins.create_builtin_function("__le__", BaseObjInst::not_implemented_bin, 2),
|
__le__ => BuiltinFunctionInst::create("__le__", BaseObjInst::not_implemented_bin, 2),
|
||||||
__pos__ => builtins.create_builtin_function("__pos__", BaseObjInst::not_implemented_un, 1),
|
__pos__ => BuiltinFunctionInst::create("__pos__", BaseObjInst::not_implemented_un, 1),
|
||||||
__neg__ => builtins.create_builtin_function("__neg__", BaseObjInst::not_implemented_un, 1),
|
__neg__ => BuiltinFunctionInst::create("__neg__", BaseObjInst::not_implemented_un, 1),
|
||||||
__not__ => builtins.create_builtin_function("__not__", BaseObjInst::not, 1),
|
__not__ => BuiltinFunctionInst::create("__not__", BaseObjInst::not, 1),
|
||||||
},
|
},
|
||||||
Obj { },
|
Obj { },
|
||||||
Str {
|
Str {
|
||||||
to_str => builtins.create_builtin_function("to_str", StrInst::to_str, 1),
|
to_str => BuiltinFunctionInst::create("to_str", StrInst::to_str, 1),
|
||||||
to_repr => builtins.create_builtin_function("to_repr", StrInst::to_repr, 1),
|
to_repr => BuiltinFunctionInst::create("to_repr", StrInst::to_repr, 1),
|
||||||
len => builtins.create_builtin_function("len", StrInst::len, 1),
|
len => BuiltinFunctionInst::create("len", StrInst::len, 1),
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => builtins.create_builtin_function("__add__", StrInst::add, 2),
|
__add__ => BuiltinFunctionInst::create("__add__", StrInst::add, 2),
|
||||||
__mul__ => builtins.create_builtin_function("__mul__", StrInst::mul, 2),
|
__mul__ => BuiltinFunctionInst::create("__mul__", StrInst::mul, 2),
|
||||||
// .lower, .upper, .slice, etc
|
// .lower, .upper, .slice, etc
|
||||||
},
|
},
|
||||||
Int {
|
Int {
|
||||||
// Operators
|
// Operators
|
||||||
__add__ => builtins.create_builtin_function("__add__", IntInst::add, 2),
|
__add__ => BuiltinFunctionInst::create("__add__", IntInst::add, 2),
|
||||||
__sub__ => builtins.create_builtin_function("__sub__", IntInst::sub, 2),
|
__sub__ => BuiltinFunctionInst::create("__sub__", IntInst::sub, 2),
|
||||||
__mul__ => builtins.create_builtin_function("__mul__", IntInst::mul, 2),
|
__mul__ => BuiltinFunctionInst::create("__mul__", IntInst::mul, 2),
|
||||||
__div__ => builtins.create_builtin_function("__div__", IntInst::div, 2),
|
__div__ => BuiltinFunctionInst::create("__div__", IntInst::div, 2),
|
||||||
__gt__ => builtins.create_builtin_function("__gt__", IntInst::gt, 2),
|
__gt__ => BuiltinFunctionInst::create("__gt__", IntInst::gt, 2),
|
||||||
__ge__ => builtins.create_builtin_function("__ge__", IntInst::ge, 2),
|
__ge__ => BuiltinFunctionInst::create("__ge__", IntInst::ge, 2),
|
||||||
__lt__ => builtins.create_builtin_function("__lt__", IntInst::lt, 2),
|
__lt__ => BuiltinFunctionInst::create("__lt__", IntInst::lt, 2),
|
||||||
__le__ => builtins.create_builtin_function("__le__", IntInst::le, 2),
|
__le__ => BuiltinFunctionInst::create("__le__", IntInst::le, 2),
|
||||||
__pos__ => builtins.create_builtin_function("__pos__", IntInst::pos, 1),
|
__pos__ => BuiltinFunctionInst::create("__pos__", IntInst::pos, 1),
|
||||||
__neg__ => builtins.create_builtin_function("__neg__", IntInst::neg, 1),
|
__neg__ => BuiltinFunctionInst::create("__neg__", IntInst::neg, 1),
|
||||||
},
|
},
|
||||||
Float { },
|
Float { },
|
||||||
Bool { },
|
Bool { },
|
||||||
@@ -171,74 +172,6 @@ pub fn init_types(builtins: &mut HashMap<String, ObjP>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ObjFactory {
|
|
||||||
fn builtins(&self) -> &HashMap<String, ObjP>;
|
|
||||||
|
|
||||||
fn create_obj(&self) -> ObjP {
|
|
||||||
ObjInst::create(self.builtins().get("Obj").unwrap().clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_type(&self, name: impl ToString) -> ObjP {
|
|
||||||
TypeInst::create(self.builtins().get("Type").unwrap().clone(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_str(&self, str_value: impl ToString) -> ObjP {
|
|
||||||
StrInst::create(self.builtins().get("Str").unwrap().clone(), str_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_int(&self, int_value: i64) -> ObjP {
|
|
||||||
IntInst::create(self.builtins().get("Int").unwrap().clone(), int_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_float(&self, float_value: f64) -> ObjP {
|
|
||||||
FloatInst::create(self.builtins().get("Float").unwrap().clone(), float_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_bool(&self, bool_value: bool) -> ObjP {
|
|
||||||
BoolInst::create(self.builtins().get("Bool").unwrap().clone(), bool_value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_nil(&self) -> ObjP {
|
|
||||||
NilInst::create(self.builtins().get("Nil").unwrap().clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_builtin_function(
|
|
||||||
&self,
|
|
||||||
name: impl ToString,
|
|
||||||
function: BuiltinFunctionPtr,
|
|
||||||
arity: Argc,
|
|
||||||
) -> ObjP {
|
|
||||||
BuiltinFunctionInst::create(
|
|
||||||
self.builtins().get("BuiltinFunction").unwrap().clone(),
|
|
||||||
name,
|
|
||||||
function,
|
|
||||||
arity,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_user_function(&self, chunk: Chunk, arity: Argc) -> ObjP {
|
|
||||||
UserFunctionInst::create(
|
|
||||||
self.builtins().get("UserFunction").unwrap().clone(),
|
|
||||||
chunk,
|
|
||||||
arity,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_method(&self, self_binding: ObjP, function: ObjP) -> ObjP {
|
|
||||||
MethodInst::create(
|
|
||||||
self.builtins().get("Method").unwrap().clone(),
|
|
||||||
self_binding,
|
|
||||||
function,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjFactory for HashMap<String, ObjP> {
|
|
||||||
fn builtins(&self) -> &Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenience function for creating pointers, in case the `Arc<RwLock<T>>` pointer type has to
|
/// Convenience function for creating pointers, in case the `Arc<RwLock<T>>` pointer type has to
|
||||||
/// change.
|
/// change.
|
||||||
///
|
///
|
||||||
@@ -253,7 +186,7 @@ pub fn make_ptr<T: Obj>(obj: T) -> ObjP {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub trait Obj: Debug + Display + Any + Trace {
|
pub trait Obj: Debug + Display + Any + Trace {
|
||||||
fn instantiate(&mut self, ty: ObjP);
|
fn instantiate(&mut self);
|
||||||
|
|
||||||
fn is_instantiated(&self) -> bool;
|
fn is_instantiated(&self) -> bool;
|
||||||
fn attrs(&self) -> &Attrs;
|
fn attrs(&self) -> &Attrs;
|
||||||
@@ -264,21 +197,12 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_attr(&self, name: &str) -> Option<ObjP> {
|
fn get_attr(&self, name: &str) -> Option<ObjP> {
|
||||||
// check attrs, then check vtable
|
self.attrs().get(name).map(ObjP::clone)
|
||||||
self.attrs().get(name).map(Ptr::clone)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This tries to get an attribute using these sources:
|
fn get_vtable_attr(&self, self_ptr: ObjP, name: &str) -> Option<ObjP> {
|
||||||
/// * `self.attrs()`
|
// check attrs, then check vtable
|
||||||
/// * `self.type_inst().vtable`
|
let attr = self.attrs().get(name).map(ObjP::clone);
|
||||||
/// * `self.type_inst().type_inst().vtable` - our type's type's vtable (search up the type
|
|
||||||
/// inheritance tree)
|
|
||||||
///
|
|
||||||
/// If the value is found in a vtable, then it is inserted as an attribute. If it is a
|
|
||||||
/// function (BuiltinFunctionInst, UserFunctionInst), then it is wrapped in a `MethodInst`
|
|
||||||
/// first.
|
|
||||||
fn get_attr_lazy(&mut self, self_ptr: ObjP, method_ty: ObjP, name: &str) -> Option<ObjP> {
|
|
||||||
let attr = self.get_attr(name);
|
|
||||||
if attr.is_some() {
|
if attr.is_some() {
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
@@ -293,11 +217,14 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
let ptr = if obj_is_inst::<BuiltinFunctionInst>(&vtable_entry)
|
let ptr = if obj_is_inst::<BuiltinFunctionInst>(&vtable_entry)
|
||||||
|| obj_is_inst::<UserFunctionInst>(&vtable_entry)
|
|| obj_is_inst::<UserFunctionInst>(&vtable_entry)
|
||||||
{
|
{
|
||||||
MethodInst::create(method_ty.clone(), self_ptr.clone(), vtable_entry)
|
MethodInst::create(self_ptr.clone(), vtable_entry)
|
||||||
} else {
|
} else {
|
||||||
vtable_entry
|
vtable_entry
|
||||||
};
|
};
|
||||||
self.set_attr(name, ptr.clone());
|
// TODO Obj::get_attr - cache the vtable result somehow? we aren't caching for
|
||||||
|
// speed, but rather so we don't have a million different method objects
|
||||||
|
// floating around.
|
||||||
|
//self.set_attr(name, ptr.clone());
|
||||||
ptr
|
ptr
|
||||||
});
|
});
|
||||||
if vtable_entry.is_some() {
|
if vtable_entry.is_some() {
|
||||||
@@ -311,9 +238,7 @@ pub trait Obj: Debug + Display + Any + Trace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_inst(&self) -> ObjP {
|
fn type_inst(&self) -> ObjP;
|
||||||
self.get_attr("__type__").unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_name(&self) -> Rc<String> {
|
fn type_name(&self) -> Rc<String> {
|
||||||
with_obj_downcast(self.type_inst(), |type_inst: &TypeInst| {
|
with_obj_downcast(self.type_inst(), |type_inst: &TypeInst| {
|
||||||
@@ -372,8 +297,7 @@ impl Display for BaseObjInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Obj for BaseObjInst {
|
impl Obj for BaseObjInst {
|
||||||
fn instantiate(&mut self, ty: ObjP) {
|
fn instantiate(&mut self) {
|
||||||
self.set_attr("__type__", ty);
|
|
||||||
self.is_instantiated = true;
|
self.is_instantiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,6 +313,10 @@ impl Obj for BaseObjInst {
|
|||||||
&mut self.attrs
|
&mut self.attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_inst(&self) -> ObjP {
|
||||||
|
self.get_attr("__type__").expect("no __type__")
|
||||||
|
}
|
||||||
|
|
||||||
fn equals(&self, other: &dyn Obj) -> bool {
|
fn equals(&self, other: &dyn Obj) -> bool {
|
||||||
if let Some(other) = other.as_any().downcast_ref::<BaseObjInst>() {
|
if let Some(other) = other.as_any().downcast_ref::<BaseObjInst>() {
|
||||||
// compare all attrs
|
// compare all attrs
|
||||||
@@ -451,7 +379,7 @@ impl Obj for ObjInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -523,7 +451,7 @@ impl Obj for TypeInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -575,7 +503,7 @@ impl Obj for StrInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Str);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -628,7 +556,7 @@ impl Obj for IntInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Int);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -681,7 +609,7 @@ impl Obj for FloatInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Float);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -732,7 +660,7 @@ impl Obj for BoolInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -771,7 +699,7 @@ impl Obj for NilInst {
|
|||||||
other.as_any().downcast_ref::<NilInst>().is_some()
|
other.as_any().downcast_ref::<NilInst>().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -780,53 +708,51 @@ impl Obj for NilInst {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_objects() {
|
fn test_new_objects() {
|
||||||
let mut builtins = HashMap::new();
|
init_types();
|
||||||
init_types(&mut builtins);
|
|
||||||
|
|
||||||
let type_value = builtins.create_type("Type");
|
let type_value = TypeInst::create("Type");
|
||||||
assert_eq!(&*type_value.borrow().type_name(), "Type");
|
assert_eq!(&*type_value.borrow().type_name(), "Type");
|
||||||
|
|
||||||
let str_value = builtins.create_str("asdfasdfasdfasdfasdf");
|
let str_value = StrInst::create("asdfasdfasdfasdfasdf");
|
||||||
assert_eq!(&*str_value.borrow().type_name(), "Str");
|
assert_eq!(&*str_value.borrow().type_name(), "Str");
|
||||||
|
|
||||||
let int_value = builtins.create_int(1234);
|
let int_value = IntInst::create(1234);
|
||||||
assert_eq!(&*int_value.borrow().type_name(), "Int");
|
assert_eq!(&*int_value.borrow().type_name(), "Int");
|
||||||
|
|
||||||
let float_value = builtins.create_float(1234.5678);
|
let float_value = FloatInst::create(1234.5678);
|
||||||
assert_eq!(&*float_value.borrow().type_name(), "Float");
|
assert_eq!(&*float_value.borrow().type_name(), "Float");
|
||||||
|
|
||||||
let nil_value = builtins.create_nil();
|
let nil_value = NilInst::create();
|
||||||
assert_eq!(&*nil_value.borrow().type_name(), "Nil");
|
assert_eq!(&*nil_value.borrow().type_name(), "Nil");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_obj_equals() {
|
fn test_obj_equals() {
|
||||||
let mut builtins = HashMap::new();
|
init_types();
|
||||||
init_types(&mut builtins);
|
|
||||||
|
|
||||||
let int1 = builtins.create_int(1234);
|
let int1 = IntInst::create(1234);
|
||||||
let int2 = builtins.create_int(1234);
|
let int2 = IntInst::create(1234);
|
||||||
|
|
||||||
assert!(int1.borrow().equals(&*int2.borrow()));
|
assert!(int1.borrow().equals(&*int2.borrow()));
|
||||||
assert!(int2.borrow().equals(&*int1.borrow()));
|
assert!(int2.borrow().equals(&*int1.borrow()));
|
||||||
|
|
||||||
let float1 = builtins.create_float(1234.0);
|
let float1 = FloatInst::create(1234.0);
|
||||||
assert!(int1.borrow().equals(&*float1.borrow()));
|
assert!(int1.borrow().equals(&*float1.borrow()));
|
||||||
assert!(float1.borrow().equals(&*int2.borrow()));
|
assert!(float1.borrow().equals(&*int2.borrow()));
|
||||||
|
|
||||||
// self-equality
|
// self-equality
|
||||||
let str1 = builtins.create_str("1234");
|
let str1 = StrInst::create("1234");
|
||||||
assert!(str1.borrow().equals(&*str1.borrow()));
|
assert!(str1.borrow().equals(&*str1.borrow()));
|
||||||
|
|
||||||
let str2 = builtins.create_str("1234");
|
let str2 = StrInst::create("1234");
|
||||||
assert!(str1.borrow().equals(&*str2.borrow()));
|
assert!(str1.borrow().equals(&*str2.borrow()));
|
||||||
assert!(str2.borrow().equals(&*str1.borrow()));
|
assert!(str2.borrow().equals(&*str1.borrow()));
|
||||||
|
|
||||||
assert!(!str1.borrow().equals(&*float1.borrow()));
|
assert!(!str1.borrow().equals(&*float1.borrow()));
|
||||||
assert!(!str1.borrow().equals(&*int1.borrow()));
|
assert!(!str1.borrow().equals(&*int1.borrow()));
|
||||||
|
|
||||||
let obj1 = builtins.create_obj();
|
let obj1 = ObjInst::create();
|
||||||
let obj2 = builtins.create_obj();
|
let obj2 = ObjInst::create();
|
||||||
assert!(obj1.borrow().equals(&*obj2.borrow()));
|
assert!(obj1.borrow().equals(&*obj2.borrow()));
|
||||||
|
|
||||||
// these objects aren't equal anymore
|
// these objects aren't equal anymore
|
||||||
@@ -840,15 +766,10 @@ fn test_obj_equals() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_obj_vtable() {
|
fn test_obj_vtable() {
|
||||||
let mut builtins = HashMap::new();
|
init_types();
|
||||||
init_types(&mut builtins);
|
let str1 = StrInst::create("asdfasdfasdf");
|
||||||
let str1 = builtins.create_str("asdfasdfasdf");
|
|
||||||
|
|
||||||
let to_string_ptr = str1.borrow_mut().get_attr_lazy(
|
let to_string_ptr = str1.borrow_mut().get_vtable_attr(str1.clone(), "to_str");
|
||||||
str1.clone(),
|
|
||||||
builtins.get("Method").unwrap().clone(),
|
|
||||||
"to_str",
|
|
||||||
);
|
|
||||||
assert!(to_string_ptr.is_some());
|
assert!(to_string_ptr.is_some());
|
||||||
|
|
||||||
let to_string_ptr = to_string_ptr.unwrap();
|
let to_string_ptr = to_string_ptr.unwrap();
|
||||||
@@ -858,11 +779,9 @@ fn test_obj_vtable() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// now get the method's to_string ptr
|
// now get the method's to_string ptr
|
||||||
let method_to_string_ptr = to_string_ptr.borrow_mut().get_attr_lazy(
|
let method_to_string_ptr = to_string_ptr
|
||||||
to_string_ptr.clone(),
|
.borrow_mut()
|
||||||
builtins.get("Method").unwrap().clone(),
|
.get_vtable_attr(to_string_ptr.clone(), "to_str");
|
||||||
"to_str",
|
|
||||||
);
|
|
||||||
assert!(method_to_string_ptr.is_some());
|
assert!(method_to_string_ptr.is_some());
|
||||||
|
|
||||||
// this is like doing "asdfasdfasdf".to_string().to_string()
|
// this is like doing "asdfasdfasdf".to_string().to_string()
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ impl Obj for BuiltinFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(BuiltinFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -216,7 +216,7 @@ impl Obj for UserFunctionInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(UserFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -249,9 +249,9 @@ impl MethodInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(ty: ObjP, self_binding: ObjP, function: ObjP) -> ObjP {
|
pub fn create(self_binding: ObjP, function: ObjP) -> ObjP {
|
||||||
let ptr = make_ptr(Self::new(self_binding, function));
|
let ptr = make_ptr(Self::new(self_binding, function));
|
||||||
ptr.borrow_mut().instantiate(ty.clone());
|
ptr.borrow_mut().instantiate();
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,5 +294,5 @@ impl Obj for MethodInst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_base_obj!();
|
impl_base_obj!(Method);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
macro_rules! impl_base_obj {
|
macro_rules! impl_base_obj {
|
||||||
($base_name:ident) => {
|
($base_name:ident, $type_name:ident) => {
|
||||||
fn instantiate(&mut self, ty: $crate::obj::ObjP) {
|
fn instantiate(&mut self) {
|
||||||
self.$base_name.instantiate(ty);
|
let ty = $crate::obj::BUILTINS.with_borrow(|builtins| {
|
||||||
|
builtins
|
||||||
|
.get(stringify!($type_name))
|
||||||
|
.expect(concat!("no ", stringify!($type_name)))
|
||||||
|
.clone()
|
||||||
|
});
|
||||||
|
self.set_attr("__type__", ty);
|
||||||
|
self.$base_name.instantiate();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_instantiated(&self) -> bool {
|
fn is_instantiated(&self) -> bool {
|
||||||
@@ -16,6 +23,10 @@ macro_rules! impl_base_obj {
|
|||||||
self.$base_name.attrs_mut()
|
self.$base_name.attrs_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_inst(&self) -> ObjP {
|
||||||
|
self.$base_name.type_inst()
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -24,16 +35,16 @@ macro_rules! impl_base_obj {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
() => {
|
($type_name:ident) => {
|
||||||
impl_base_obj! { base }
|
impl_base_obj! { base, $type_name }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_create {
|
macro_rules! impl_create {
|
||||||
($($arg:ident : $ty:ty),* $(,)?) => {
|
($($arg:ident : $ty:ty),* $(,)?) => {
|
||||||
pub fn create(ty: $crate::obj::ObjP $(, $arg : $ty )*) -> $crate::obj::ObjP {
|
pub fn create($($arg : $ty ),*) -> $crate::obj::ObjP {
|
||||||
let ptr = make_ptr(Self::new($($arg),*));
|
let ptr = make_ptr(Self::new($($arg),*));
|
||||||
ptr.borrow_mut().instantiate(ty);
|
ptr.borrow_mut().instantiate();
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/vm.rs
34
src/vm.rs
@@ -1,4 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::obj::function::*;
|
use crate::obj::function::*;
|
||||||
@@ -93,19 +92,13 @@ pub struct Vm {
|
|||||||
globals: Vec<ObjP>,
|
globals: Vec<ObjP>,
|
||||||
stack: Vec<ObjP>,
|
stack: Vec<ObjP>,
|
||||||
frames: Vec<Frame>,
|
frames: Vec<Frame>,
|
||||||
builtins: HashMap<String, ObjP>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
/// Create a new virtual machine with the given chunk, constants, and global names.
|
/// Create a new virtual machine with the given chunk, constants, and global names.
|
||||||
pub fn new(
|
pub fn new(chunk: Rc<Chunk>, constants: Vec<ObjP>, global_names: Vec<String>) -> Self {
|
||||||
chunk: Rc<Chunk>,
|
|
||||||
constants: Vec<ObjP>,
|
|
||||||
global_names: Vec<String>,
|
|
||||||
builtins: HashMap<String, ObjP>,
|
|
||||||
) -> Self {
|
|
||||||
// set up globals
|
// set up globals
|
||||||
let nil = builtins.create_nil();
|
let nil = NilInst::create();
|
||||||
let mut globals: Vec<_> = global_names.iter().map(|_| ObjP::clone(&nil)).collect();
|
let mut globals: Vec<_> = global_names.iter().map(|_| ObjP::clone(&nil)).collect();
|
||||||
|
|
||||||
let mut register_global = |name: &str, value: ObjP| {
|
let mut register_global = |name: &str, value: ObjP| {
|
||||||
@@ -116,9 +109,11 @@ impl Vm {
|
|||||||
globals[index] = value;
|
globals[index] = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (name, builtin) in builtins.iter() {
|
BUILTINS.with_borrow(|builtins| {
|
||||||
register_global(&name, ObjP::clone(&builtin));
|
for (name, builtin) in builtins.iter() {
|
||||||
}
|
register_global(&name, builtin.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// stack and frames
|
// stack and frames
|
||||||
let stack = Vec::new();
|
let stack = Vec::new();
|
||||||
@@ -134,7 +129,6 @@ impl Vm {
|
|||||||
globals,
|
globals,
|
||||||
stack,
|
stack,
|
||||||
frames,
|
frames,
|
||||||
builtins,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,9 +255,6 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
// Cached pointers that we just always want to have on hand
|
|
||||||
let method_type = self.builtins().get("Method").unwrap().clone();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let op = self.dispatch();
|
let op = self.dispatch();
|
||||||
|
|
||||||
@@ -301,10 +292,7 @@ impl Vm {
|
|||||||
let name =
|
let name =
|
||||||
with_obj_downcast(name_obj, |name: &StrInst| Rc::clone(&name.str_value()));
|
with_obj_downcast(name_obj, |name: &StrInst| Rc::clone(&name.str_value()));
|
||||||
let owner = self.pop();
|
let owner = self.pop();
|
||||||
let value =
|
let value = owner.borrow_mut().get_vtable_attr(owner.clone(), &name);
|
||||||
owner
|
|
||||||
.borrow_mut()
|
|
||||||
.get_attr_lazy(owner.clone(), method_type.clone(), &name);
|
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
self.push(value);
|
self.push(value);
|
||||||
} else {
|
} else {
|
||||||
@@ -410,9 +398,3 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjFactory for Vm {
|
|
||||||
fn builtins(&self) -> &HashMap<String, ObjP> {
|
|
||||||
&self.builtins
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user