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:
2024-09-25 10:22:03 -07:00
parent 6c64697cde
commit 2203957ebb
7 changed files with 194 additions and 296 deletions

View File

@@ -407,22 +407,21 @@ impl Display for CompileError {
////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)]
pub struct Compiler<'b> {
pub struct Compiler {
chunks: Vec<Chunk>,
scopes: Vec<Scope>,
constants: Vec<ObjP>,
globals: Vec<String>,
builtins: &'b HashMap<String, ObjP>,
}
impl<'b> Compiler<'b> {
pub fn new(builtins: &'b HashMap<String, ObjP>) -> Self {
impl Compiler {
pub fn new() -> Self {
Compiler {
chunks: Default::default(),
scopes: Default::default(),
constants: Default::default(),
globals: builtins.keys().map(ToString::to_string).collect(),
builtins,
globals: 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<()> {
self.compile_expr(&stmt.expr)?;
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<()> {
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.emit(stmt_line_number(stmt), Op::SetAttr(name));
Ok(())
@@ -698,7 +697,7 @@ impl StmtVisitor for Compiler<'_> {
if let Some(expr) = &stmt.expr {
self.compile_expr(expr)?;
} 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::Return);
@@ -708,7 +707,7 @@ impl StmtVisitor for Compiler<'_> {
// condition
self.compile_expr(&stmt.condition)?;
// 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::Call(0));
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<()> {
static OP_NAMES: LazyLock<HashMap<TokenKind, &'static str>> = LazyLock::new(|| {
hash_map! {
@@ -780,7 +779,7 @@ impl ExprVisitor for Compiler<'_> {
let mut exit_patch_index = 0;
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::Call(0));
exit_patch_index = self.chunk().code.len();
@@ -794,14 +793,14 @@ impl ExprVisitor for Compiler<'_> {
let name = OP_NAMES
.get(&expr.op.kind)
.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.compile_expr(&expr.rhs)?;
// convert RHS to a bool if we're doing AND or OR
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::Call(0));
}
@@ -839,7 +838,7 @@ impl ExprVisitor for Compiler<'_> {
});
self.compile_expr(&expr.expr)?;
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::Call(0));
Ok(())
@@ -863,7 +862,7 @@ impl ExprVisitor for Compiler<'_> {
fn visit_get_expr(&mut self, expr: &GetExpr) -> Result<()> {
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));
Ok(())
}
@@ -889,25 +888,25 @@ impl ExprVisitor for Compiler<'_> {
}
TokenKind::Number => {
let obj = if expr.token.text.contains('.') {
self.create_float(expr.token.text.parse().unwrap())
FloatInst::create(expr.token.text.parse().unwrap())
} else {
self.create_int(expr.token.text.parse().unwrap())
IntInst::create(expr.token.text.parse().unwrap())
};
let constant_id = self.insert_constant(obj)?;
self.emit(expr_line_number(expr), Op::PushConstant(constant_id));
}
TokenKind::String => {
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));
}
TokenKind::True | TokenKind::False => {
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));
}
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));
}
_ => unreachable!(),
@@ -965,7 +964,7 @@ impl ExprVisitor for Compiler<'_> {
}
// 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::Return);
@@ -973,7 +972,7 @@ impl ExprVisitor for Compiler<'_> {
// create the function
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
let fun_constant = self.insert_constant(fun)?;
@@ -993,9 +992,3 @@ impl ExprVisitor for Compiler<'_> {
Ok(())
}
}
impl ObjFactory for Compiler<'_> {
fn builtins(&self) -> &HashMap<String, ObjP> {
&self.builtins
}
}