[fine] Static methods I guess
This commit is contained in:
parent
bc57978dda
commit
19e57db724
6 changed files with 111 additions and 51 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue