[fine] Static methods I guess

This commit is contained in:
John Doty 2024-01-25 06:44:53 -08:00
parent bc57978dda
commit 19e57db724
6 changed files with 111 additions and 51 deletions

View file

@ -66,6 +66,7 @@ pub struct MethodDecl {
pub name: Rc<str>,
pub decl_type: Type,
pub declaration: TreeRef,
pub is_static: bool,
}
pub struct ClassDecl {
@ -75,6 +76,7 @@ pub struct ClassDecl {
pub decl_tree: TreeRef,
pub env: EnvironmentRef,
pub static_env: EnvironmentRef,
}
#[derive(Clone)]
@ -132,9 +134,14 @@ pub enum Type {
List(Box<Type>),
// Classes need to be fetched explicitly from the semantics; they are
// computed lazily.
// A class is the static type of a class; when the class is referred to
// by name it has this type. (Distinct from an instance!)
Class(TreeRef, Rc<str>),
// An object is the type of an allocated object instance. Details of its
// class need to be fetched explicitly from the semantics via the
// TreeRef and `Semantics::class_of`; they are computed lazily.
Object(TreeRef, Rc<str>),
}
impl Type {
@ -194,6 +201,7 @@ impl fmt::Display for Type {
write!(f, "$_")
}
List(t) => write!(f, "list<{t}>"),
Object(_, name) => write!(f, "{} instance", name),
Class(_, name) => write!(f, "class {}", name),
}
}
@ -813,10 +821,14 @@ impl<'a> Semantics<'a> {
};
let typ = self.type_of(lhs);
match &typ {
Type::Class(ct, _) => {
Type::Object(ct, _) => {
let class = self.class_of(*ct);
class.env.clone()
}
Type::Class(ct, _) => {
let class = self.class_of(*ct);
class.static_env.clone()
}
Type::Error => Environment::error(),
_ => {
// TODO: This is probably wrong, yeah?
@ -869,16 +881,33 @@ impl<'a> Semantics<'a> {
for method in tree.children_of_kind(self.syntax_tree, TreeKind::FunctionDecl) {
let m = &self.syntax_tree[method];
if let Some(method_name) = m.nth_token(1) {
methods.push(MethodDecl {
name: method_name.as_str().into(),
decl_type: self.type_of(method),
declaration: method,
});
// TODO: Check to see if it is actually a method, or if it is a static function.
let decl_type = self.type_of(method);
match decl_type {
Type::Method(..) => {
methods.push(MethodDecl {
name: method_name.as_str().into(),
decl_type,
declaration: method,
is_static: false,
});
}
_ => {
// TODO: Default to method or static?
methods.push(MethodDecl {
name: method_name.as_str().into(),
decl_type,
declaration: method,
is_static: true,
});
}
}
}
}
// Build into an environment
let mut env = Environment::new(None, Location::Slot);
let mut static_env = Environment::new(None, Location::Slot);
for (index, field) in fields.iter().enumerate() {
env.declarations.insert(
(&*field.name).into(),
@ -890,13 +919,23 @@ impl<'a> Semantics<'a> {
);
}
for method in methods.iter() {
let existing = env.declarations.insert(
(&*method.name).into(),
Declaration::Function {
declaration_type: method.decl_type.clone(),
declaration: method.declaration,
},
);
let existing = if method.is_static {
static_env.declarations.insert(
(&*method.name).into(),
Declaration::Function {
declaration_type: method.decl_type.clone(),
declaration: method.declaration,
},
)
} else {
env.declarations.insert(
(&*method.name).into(),
Declaration::Function {
declaration_type: method.decl_type.clone(),
declaration: method.declaration,
},
)
};
if existing.is_some() {
self.report_error_tree_ref(
method.declaration,
@ -911,6 +950,7 @@ impl<'a> Semantics<'a> {
methods: methods.into(),
decl_tree: t,
env: EnvironmentRef::new(env),
static_env: EnvironmentRef::new(static_env),
});
self.classes.borrow_mut()[t.index()] = Incremental::Complete(result.clone());
@ -937,7 +977,7 @@ impl<'a> Semantics<'a> {
.all(|(a, b)| self.type_compat(a, b))
}
(Type::Class(ca, _), Type::Class(cb, _)) => {
(Type::Object(ca, _), Type::Object(cb, _)) => {
// TODO: If we were doing structural comparisons here...
// maybe? MAYBE?
//
@ -1485,10 +1525,12 @@ impl<'a> Semantics<'a> {
Declaration::ExternFunction {
declaration_type, ..
} => declaration_type.clone(),
Declaration::Class { .. } => {
self.report_error_tree(tree, format!("{id} is a class, not a value (did you mean to create a new instance with 'new'?)"));
Type::Error
}
Declaration::Class {
declaration_type, ..
} => match declaration_type {
Type::Object(cd, name) => Type::Class(*cd, name.clone()),
_ => self.internal_compiler_error(Some(t), "bound to a class not understood"),
},
});
}
@ -1612,16 +1654,18 @@ impl<'a> Semantics<'a> {
fn type_of_new_object_expression(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::NewObjectExpression);
// NOTE: Matching fields is done in the check function.
// NOTE: Matching fields is done in the check function, as is
// reporting on the suitability of the type.
Some(self.type_of(tree.nth_tree(1)?))
}
fn type_of_class_decl(&self, t: TreeRef, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::ClassDecl);
// The type of a class is computed lazily.
// The details of a class are computed lazily, but this is enough of
// a belly-button.
let name = tree.nth_token(1)?;
Some(Type::Class(t, name.as_str().into()))
Some(Type::Object(t, name.as_str().into()))
}
fn type_of_field_value(&self, t: TreeRef, tree: &Tree) -> Option<Type> {
@ -1910,9 +1954,9 @@ fn check_new_object_expression(s: &Semantics, tree: &Tree) {
return;
};
let class_type = s.type_of(type_expression);
let class_type = s.type_of(type_expression); // TODO: Should yield a ClassType not an ObjectType?
match &class_type {
Type::Class(c, _) => {
Type::Object(c, _) => {
let class = s.class_of(*c);
let mut any_errors = false;