[fine] Classes!

It's kinda amazing this works actually
This commit is contained in:
John Doty 2024-01-20 11:03:33 -08:00
parent 0ee89bf26b
commit 4505996710
5 changed files with 319 additions and 40 deletions

View file

@ -585,19 +585,35 @@ impl<'a> Semantics<'a> {
match child {
Child::Tree(t) => {
let ct = &self.syntax_tree[*t];
if ct.kind == TreeKind::FunctionDecl {
// TODO: Should I have accessors for function decls?
let Some(name) = ct.nth_token(1) else {
continue;
};
match ct.kind {
TreeKind::FunctionDecl => {
// TODO: Should I have accessors for function decls?
let Some(name) = ct.nth_token(1) else {
continue;
};
environment.declarations.insert(
name.as_str().into(),
Declaration::Function {
declaration_type: self.type_of(*t),
declaration: *t,
},
);
environment.declarations.insert(
name.as_str().into(),
Declaration::Function {
declaration_type: self.type_of(*t),
declaration: *t,
},
);
}
TreeKind::ClassDecl => {
let Some(name) = ct.nth_token(1) else {
continue;
};
environment.declarations.insert(
name.as_str().into(),
Declaration::Class {
declaration_type: self.type_of(*t),
declaration: *t,
},
);
}
_ => {}
}
}
_ => {}
@ -742,7 +758,7 @@ impl<'a> Semantics<'a> {
TreeKind::Error => Some(Type::Error),
TreeKind::UnaryExpression => self.type_of_unary(tree),
TreeKind::BinaryExpression => self.type_of_binary(tree),
TreeKind::TypeExpression => self.type_of_type_expr(tree),
TreeKind::TypeExpression => self.type_of_type_expr(t, tree),
TreeKind::TypeParameter => self.type_of_type_parameter(tree),
TreeKind::Block => self.type_of_block(tree),
TreeKind::LiteralExpression => self.type_of_literal(tree),
@ -750,6 +766,7 @@ impl<'a> Semantics<'a> {
TreeKind::ConditionalExpression => self.type_of_conditional(tree),
TreeKind::CallExpression => self.type_of_call(tree),
TreeKind::Argument => self.type_of_argument(tree),
TreeKind::MemberAccess => self.type_of_member_access(tree),
TreeKind::LetStatement => Some(Type::Nothing),
TreeKind::ReturnStatement => Some(Type::Unreachable),
@ -766,6 +783,8 @@ impl<'a> Semantics<'a> {
TreeKind::ListConstructor => self.type_of_list_constructor(t, tree),
TreeKind::NewObjectExpression => self.type_of_new_object_expression(tree),
TreeKind::FieldValue => self.type_of_field_value(t, tree),
TreeKind::ClassDecl => self.type_of_class_decl(t, tree),
_ => self.internal_compiler_error(Some(t), "asking for a nonsense type"),
};
@ -935,7 +954,7 @@ impl<'a> Semantics<'a> {
}
}
fn type_of_type_expr(&self, tree: &Tree) -> Option<Type> {
fn type_of_type_expr(&self, t: TreeRef, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::TypeExpression);
// TODO: This will *clearly* need to get better.
@ -958,8 +977,30 @@ impl<'a> Semantics<'a> {
}
}
_ => {
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
Some(Type::Error)
let environment = self.environment_of(t);
match environment.bind(token) {
Some(Declaration::Class {
declaration_type, ..
}) => Some(declaration_type.clone()),
Some(Declaration::Variable { .. }) => {
self.report_error_tree(
tree,
format!("'{token}' is a variable and cannot be used as a type"),
);
Some(Type::Error)
}
Some(Declaration::Function { .. } | Declaration::ExternFunction { .. }) => {
self.report_error_tree(
tree,
format!("'{token}' is a function and cannot be used as a type"),
);
Some(Type::Error)
}
None => {
self.report_error_tree(tree, format!("Unrecognized type: '{token}'"));
Some(Type::Error)
}
}
}
}
}
@ -1157,6 +1198,34 @@ impl<'a> Semantics<'a> {
Some(result)
}
fn type_of_member_access(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::MemberAccess);
let op = tree.nth_token(1)?;
let member = tree.nth_token(2)?;
let typ = self.type_of(tree.nth_tree(0)?);
match &typ {
Type::Class(c) => {
// TODO: Accelerate?
if let Some(field) = c.fields.iter().find(|f| &*f.name == member.as_str()) {
Some(field.field_type.clone())
} else {
self.report_error(
op.start,
format!("'{typ}' does not have a member named '{member}'"),
);
Some(Type::Error)
}
}
Type::Error => Some(Type::Error),
_ => {
// TODO: This is probably wrong, yeah?
self.report_error(op.start, format!("cannot access members of '{typ}'"));
Some(Type::Error)
}
}
}
fn type_of_expression_statement(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::ExpressionStatement);
let last_is_semicolon = tree
@ -1196,9 +1265,11 @@ impl<'a> Semantics<'a> {
Declaration::ExternFunction {
declaration_type, ..
} => declaration_type.clone(),
Declaration::Class {
declaration_type, ..
} => declaration_type.clone(),
Declaration::Class { .. } => {
// TODO: Test this case
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
}
});
}
@ -1266,6 +1337,65 @@ impl<'a> Semantics<'a> {
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);
// TODO: Field types need to be lazy because of recursion.
let name = tree.nth_token(1)?;
let mut fields = Vec::new();
for field in tree.children_of_kind(self.syntax_tree, TreeKind::FieldDecl) {
let f = &self.syntax_tree[field];
let field_name = f.nth_token(0)?;
fields.push(FieldDecl {
name: field_name.as_str().into(),
field_type: self.type_of(f.nth_tree(2)?),
});
}
let cd = ClassDecl {
name: name.as_str().into(),
fields: fields.into(),
decl_tree: t,
};
Some(Type::Class(cd.into()))
}
fn type_of_field_value(&self, t: TreeRef, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::FieldValue);
if let Some(colon) = tree.nth_token(1) {
if colon.kind == TokenKind::Colon {
// Form 1: { x: e, ... }
return Some(self.type_of(tree.nth_tree(2)?));
}
}
// Form 2: { x, ... }
let environment = self.environment_of(t);
let id = tree.nth_token(0)?;
match environment.bind(id)? {
Declaration::Variable {
declaration_type, ..
}
| Declaration::Function {
declaration_type, ..
}
| Declaration::ExternFunction {
declaration_type, ..
} => Some(declaration_type.clone()),
Declaration::Class { .. } => {
self.report_error_tree(
tree,
format!("`{id}` is a class, and cannot be the value of a field"),
);
Some(Type::Error)
}
}
}
fn type_of_list_constructor_element(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::ListConstructorElement);
Some(self.type_of(tree.nth_tree(0)?))
@ -1382,7 +1512,8 @@ pub fn check(s: &Semantics) {
| TreeKind::GroupingExpression
| TreeKind::UnaryExpression
| TreeKind::ConditionalExpression
| TreeKind::BinaryExpression => {
| TreeKind::BinaryExpression
| TreeKind::MemberAccess => {
let _ = s.type_of(t);
}
TreeKind::CallExpression => {