Add basic classes example.

This commit is contained in:
Jesse Brault 2026-03-12 16:24:20 -05:00
parent 75802e6ee4
commit 940671822c
2 changed files with 42 additions and 1 deletions

View File

@ -1,7 +1,7 @@
use crate::ast::constructor::Constructor; use crate::ast::constructor::Constructor;
use crate::ast::field::Field; use crate::ast::field::Field;
use crate::ast::function::Function; use crate::ast::function::Function;
use crate::diagnostic::Diagnostic; use crate::diagnostic::{Diagnostic, SecondaryLabel};
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::symbol_table::{SymbolInsertError, SymbolTable};
@ -48,6 +48,7 @@ impl Class {
.insert_class_symbol(to_insert) .insert_class_symbol(to_insert)
.map_err(|e| match e { .map_err(|e| match e {
SymbolInsertError::AlreadyDeclared(already_declared) => { SymbolInsertError::AlreadyDeclared(already_declared) => {
let symbol = already_declared.symbol().borrow();
vec![ vec![
Diagnostic::new( Diagnostic::new(
&format!( &format!(
@ -57,6 +58,11 @@ impl Class {
self.declared_name_source_range.start(), self.declared_name_source_range.start(),
self.declared_name_source_range.end(), self.declared_name_source_range.end(),
) )
.with_secondary_labels(&[SecondaryLabel::new(
symbol.declared_name_source_range().start(),
symbol.declared_name_source_range().end(),
Some("Symbol declared here.".to_string()),
)])
.with_reporter(file!(), line!()), .with_reporter(file!(), line!()),
] ]
} }
@ -151,6 +157,10 @@ impl Class {
.flatten() .flatten()
.for_each(|diagnostic| diagnostics.push(diagnostic)); .for_each(|diagnostic| diagnostics.push(diagnostic));
if !diagnostics.is_empty() {
return Err(diagnostics);
}
if let Some(constructor) = &mut self.constructor { if let Some(constructor) = &mut self.constructor {
match constructor.type_check(symbol_table) { match constructor.type_check(symbol_table) {
Ok(_) => {} Ok(_) => {}
@ -160,6 +170,10 @@ impl Class {
} }
} }
if !diagnostics.is_empty() {
return Err(diagnostics);
}
self.functions self.functions
.iter_mut() .iter_mut()
.map(|function| function.type_check(symbol_table)) .map(|function| function.type_check(symbol_table))
@ -167,6 +181,10 @@ impl Class {
.flatten() .flatten()
.for_each(|diagnostic| diagnostics.push(diagnostic)); .for_each(|diagnostic| diagnostics.push(diagnostic));
if !diagnostics.is_empty() {
return Err(diagnostics);
}
// We need to determine if fields are initialized or not (the latter is an error). // We need to determine if fields are initialized or not (the latter is an error).
// First phase: check all fields, then check constructor, leaving pending those things that // First phase: check all fields, then check constructor, leaving pending those things that
// are fields <- initialized by constructor. Then circle back to fields and check all are // are fields <- initialized by constructor. Then circle back to fields and check all are
@ -199,6 +217,9 @@ impl Class {
field.declared_name_source_range().start(), field.declared_name_source_range().start(),
field.declared_name_source_range().end(), field.declared_name_source_range().end(),
) )
.with_primary_label_message(
"Must be initialized in declaration or constructor.",
)
.with_reporter(file!(), line!()), .with_reporter(file!(), line!()),
) )
} }

20
examples/basic_classes.dm Normal file
View File

@ -0,0 +1,20 @@
class Foo
mut bar: Int = 42
ctor(_bar: Int)
end
fn baz() -> Int
bar
end
end
class Qux
fn foo() -> Foo
Foo(42)
end
end
fn main()
let crash = Qux()
end