Beginnings of type analysis.

This commit is contained in:
Jesse Brault 2025-11-22 17:59:08 -06:00
parent 8d73a8ea73
commit 734a00ea92
12 changed files with 451 additions and 4 deletions

View File

@ -135,6 +135,7 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
use std::rc::Rc;
use std::cell::RefCell;
use crate::name_analysis::symbol::*;
use crate::type_analysis::kinds::*;
#(#types)*
};

View File

@ -30,6 +30,81 @@ pub mod node {
}
}
}
impl Expression {
pub fn analyzed_kind(&self) -> Kind {
match self {
Expression::Ternary(ternary_expression) => {
todo!()
}
Expression::Or(or_expression) => {todo!()}
Expression::And(and_expression) => {
todo!()
}
Expression::Comparison(comparison_expression) => {
todo!()
}
Expression::Shift(shift_expression) => {
todo!()
}
Expression::Additive(additive_expression) => {
todo!()
}
Expression::Multiplicative(multiplicative_expression) => {
todo!()
}
Expression::Prefix(prefix_expression) => {
todo!()
}
Expression::Suffix(suffix_expression) => {
todo!()
}
Expression::Literal(literal) => {
literal.analyzed_kind()
}
Expression::Identifier(identifier) => {
identifier.analyzed_kind().expect("IdentifierExpression's analyzed_kind not set.").clone()
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(closure) => {
todo!()
}
Expression::List(list_expression) => {
todo!()
}
}
}
}
impl Literal {
pub fn analyzed_kind(&self) -> Kind {
match self {
Literal::IntLiteral(_) => {
Kind::Primitive(PrimitiveKind::Int.into())
}
Literal::LongLiteral(_) => {
Kind::Primitive(PrimitiveKind::Long.into())
}
Literal::DoubleLiteral(_) => {
Kind::Primitive(PrimitiveKind::Double.into())
}
Literal::SingleQuoteString(_) => {
Kind::Primitive(PrimitiveKind::String.into())
}
Literal::DString(_) => {
todo!()
}
Literal::BacktickString(_) => {
todo!()
}
Literal::BooleanLiteral(_) => {
Kind::Primitive(PrimitiveKind::Boolean.into())
}
}
}
}
impl Default for Parameters {
fn default() -> Self {

View File

@ -3,13 +3,19 @@ use deimos::asm::assemble_ir::assemble_ir_function;
use deimos::ast::node::CompilationUnit;
use deimos::ir::lower_ast::lower_compilation_unit;
use deimos::ir::Ir;
use deimos::util::indent_writer::IndentWriter;
use deimos::type_analysis::analyze_types;
use std::path::PathBuf;
pub fn compile_to_ir(
paths: &[PathBuf],
) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
let compilation_units = name_analysis(&paths)?;
let mut compilation_units = name_analysis(&paths)?;
let type_diagnostics = analyze_types(&mut compilation_units);
if !type_diagnostics.is_empty() {
eprintln!("There were type diagnostics")
}
for compilation_unit in &compilation_units {
let cu_irs = lower_compilation_unit(compilation_unit);

View File

@ -11,6 +11,7 @@ use crate::name_analysis::symbol::{ClassSymbol, ParameterSymbol, PrimitiveTypeSy
use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use crate::type_analysis::kinds::Kind;
struct CuContext {
irs: Vec<Ir>,
@ -437,5 +438,6 @@ fn call_to_ir_expression(
receiver: &Expression,
fn_context: &mut FnContext,
) -> IrExpression {
todo!()
let function_kind = receiver.analyzed_kind().expect_function();
todo!("Rework AST nodes so that Call and children have a better api")
}

View File

@ -13,5 +13,6 @@ pub mod name_analysis;
pub mod object_file;
pub mod parser;
pub mod std_core;
pub mod type_analysis;
pub mod util;
pub mod vm;

View File

@ -2,12 +2,13 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::Symbol;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use crate::type_analysis::kinds::Kind;
#[derive(Clone)]
pub struct VariableSymbol {
declared_name: Rc<str>,
is_mutable: bool,
source_definition: Option<SourceDefinition>,
analyzed_kind: Option<Kind>,
}
impl VariableSymbol {
@ -20,6 +21,7 @@ impl VariableSymbol {
declared_name: Rc::from(declared_name),
is_mutable,
source_definition,
analyzed_kind: None,
}
}
@ -34,6 +36,14 @@ impl VariableSymbol {
pub fn is_mutable(&self) -> bool {
self.is_mutable
}
pub fn set_analyzed_kind(&mut self, analyzed_kind: Kind) {
self.analyzed_kind = Some(analyzed_kind);
}
pub fn analyzed_kind(&self) -> Option<&Kind> {
self.analyzed_kind.as_ref()
}
}
impl Symbol for VariableSymbol {

View File

@ -1224,6 +1224,8 @@ IdentifierExpression:
fields:
- expressible_symbol:
kind: ExpressibleSymbol
- analyzed_kind:
kind: Kind
ListExpression:
struct:
children:

View File

@ -0,0 +1,27 @@
use std::fmt::Display;
use std::rc::Rc;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct ClassKind {
fqn: Rc<str>
}
impl ClassKind {
pub fn new(fqn: &str) -> Self {
Self { fqn: fqn.into() }
}
pub fn fqn(&self) -> &str {
&self.fqn
}
pub fn fqn_owned(&self) -> Rc<str> {
self.fqn.clone()
}
}
impl Display for ClassKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", self.fqn)
}
}

View File

@ -0,0 +1,27 @@
use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct FunctionKind {
fqn: Rc<str>,
}
impl FunctionKind {
pub fn new(fqn: &str) -> Self {
Self { fqn: fqn.into() }
}
pub fn fqn(&self) -> &str {
&self.fqn
}
pub fn fqn_owned(&self) -> Rc<str> {
self.fqn.clone()
}
}
impl Display for FunctionKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.fqn)
}
}

View File

@ -0,0 +1,40 @@
pub use crate::type_analysis::kinds::class_kind::ClassKind;
pub use crate::type_analysis::kinds::function_kind::FunctionKind;
pub use crate::type_analysis::kinds::primitive_kind::PrimitiveKind;
use std::fmt::Display;
pub mod class_kind;
pub mod function_kind;
pub mod primitive_kind;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Kind {
Primitive(Box<PrimitiveKind>),
Class(Box<ClassKind>),
Function(Box<FunctionKind>),
}
impl Kind {
pub fn expect_function(&self) -> &FunctionKind {
match self {
Kind::Function(function_kind) => function_kind,
_ => panic!("Expected FunctionKind, found {:?}", self),
}
}
}
impl Display for Kind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Kind::Primitive(primitive_kind) => {
write!(f, "{}", primitive_kind)
}
Kind::Class(class_kind) => {
write!(f, "{}", class_kind)
}
Kind::Function(function_kind) => {
write!(f, "{}", function_kind)
}
}
}
}

View File

@ -0,0 +1,24 @@
use std::fmt::Display;
use crate::type_analysis::kinds::Kind;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum PrimitiveKind {
Byte,
Char,
Short,
Int,
Long,
Float,
Double,
Boolean,
String,
Array { inner_type: Kind },
Any,
Void,
}
impl Display for PrimitiveKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

232
src/type_analysis/mod.rs Normal file
View File

@ -0,0 +1,232 @@
pub mod kinds;
use crate::ast::node::{
AdditiveExpression, CompilationUnit, Expression, ExpressionStatement, Function,
FunctionBlockBody, FunctionBody, IdentifierExpression, ModuleLevelDeclaration, Statement,
VariableDeclaration,
};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::ExpressibleSymbol;
use crate::type_analysis::kinds::class_kind::ClassKind;
use crate::type_analysis::kinds::function_kind::FunctionKind;
use crate::type_analysis::kinds::Kind;
use codespan_reporting::files::Files;
pub fn analyze_types(compilation_units: &mut [CompilationUnit]) -> Vec<DmDiagnostic> {
let mut diagnostics: Vec<DmDiagnostic> = vec![];
for compilation_unit in compilation_units {
ta_compilation_unit(compilation_unit, &mut diagnostics);
}
diagnostics
}
fn ta_compilation_unit(
compilation_unit: &mut CompilationUnit,
diagnostics: &mut Vec<DmDiagnostic>,
) {
for module_level_declaration in compilation_unit.module_level_declarations_mut() {
ta_module_level_declaration(module_level_declaration, diagnostics);
}
}
fn ta_module_level_declaration(
module_level_declaration: &mut ModuleLevelDeclaration,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match module_level_declaration {
ModuleLevelDeclaration::Module(module) => {
todo!()
}
ModuleLevelDeclaration::Interface(interface) => {
todo!()
}
ModuleLevelDeclaration::Class(class) => {
todo!()
}
ModuleLevelDeclaration::Function(function) => {
ta_function(function, diagnostics);
}
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
todo!()
}
}
}
fn ta_function(function: &mut Function, diagnostics: &mut Vec<DmDiagnostic>) {
ta_function_body(function.function_body_mut(), diagnostics);
}
fn ta_function_body(function_body: &mut FunctionBody, diagnostics: &mut Vec<DmDiagnostic>) {
match function_body {
FunctionBody::FunctionAliasBody(function_alias_body) => {
todo!()
}
FunctionBody::FunctionEqualsBody(function_equals_body) => {
todo!()
}
FunctionBody::FunctionBlockBody(function_block_body) => {
ta_function_block_body(function_block_body, diagnostics);
}
}
}
fn ta_function_block_body(
function_block_body: &mut FunctionBlockBody,
diagnostics: &mut Vec<DmDiagnostic>,
) {
for statement in function_block_body.statements_mut() {
ta_statement(statement, diagnostics);
}
}
fn ta_statement(statement: &mut Statement, diagnostics: &mut Vec<DmDiagnostic>) {
match statement {
Statement::VariableDeclaration(variable_declaration) => {
ta_variable_declaration(variable_declaration, diagnostics);
}
Statement::AssignmentStatement(assignment_statement) => {
todo!()
}
Statement::ExpressionStatement(expression_statement) => {
ta_expression_statement(expression_statement, diagnostics);
}
Statement::UseStatement(use_statement) => {
todo!()
}
Statement::IfStatement(if_statement) => {
todo!()
}
Statement::WhileStatement(while_statement) => {
todo!()
}
Statement::ForStatement(for_statement) => {
todo!()
}
}
}
fn ta_variable_declaration(
variable_declaration: &mut VariableDeclaration,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// compute type of initializer
ta_expression(variable_declaration.expression_mut(), diagnostics);
// get type of initializer, and check against to declared type (if present)
// todo
// set type of variable's symbol to analyzed type (initializer type or declared type)
let variable_kind = if let Some(declared_type) = variable_declaration.type_use() {
todo!("declared types on variable declarations")
} else {
variable_declaration.expression().analyzed_kind().clone()
};
variable_declaration
.variable_symbol_mut()
.expect("VariableDeclaration's variable_symbol not set.")
.borrow_mut()
.set_analyzed_kind(variable_kind)
}
fn ta_expression_statement(
expression_statement: &mut ExpressionStatement,
diagnostics: &mut Vec<DmDiagnostic>,
) {
ta_expression(expression_statement.expression_mut(), diagnostics);
}
fn ta_expression(expression: &mut Expression, diagnostics: &mut Vec<DmDiagnostic>) {
match expression {
Expression::Ternary(ternary_expression) => {
todo!()
}
Expression::Or(or_expression) => {
todo!()
}
Expression::And(and_expression) => {
todo!()
}
Expression::Comparison(comparison_expression) => {
todo!()
}
Expression::Shift(shift_expression) => {
todo!()
}
Expression::Additive(additive_expression) => {
ta_additive_expression(additive_expression, diagnostics);
}
Expression::Multiplicative(multiplicative_expression) => {
todo!()
}
Expression::Prefix(prefix_expression) => {
todo!()
}
Expression::Suffix(suffix_expression) => {
todo!()
}
Expression::Literal(literal) => {
// no-op
}
Expression::Identifier(identifier_expression) => {
ta_identifier_expression(identifier_expression);
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(closure) => {
todo!()
}
Expression::List(list_expression) => {
todo!()
}
}
}
fn ta_additive_expression(
additive_expression: &mut AdditiveExpression,
diagnostics: &mut Vec<DmDiagnostic>,
) {
ta_expression(additive_expression.left_mut(), diagnostics);
ta_expression(additive_expression.rhs_mut().expression_mut(), diagnostics);
let left_kind = additive_expression.left().analyzed_kind();
let right_kind = additive_expression.rhs().expression().analyzed_kind();
if left_kind != right_kind {
diagnostics.push(DmDiagnostic::error().with_message(&format!(
"Incompatible types for additive expression: {} vs. {}",
left_kind, right_kind
)));
todo!("Error file_id and range; set Error type on additive expression")
} else {
todo!("set analyzed type for additive expression")
}
}
fn ta_identifier_expression(identifier_expression: &mut IdentifierExpression) {
let expressible_symbol = identifier_expression
.expressible_symbol()
.expect("IdentifierExpression's expressible_symbol must be set before type analysis.");
let kind = match expressible_symbol {
ExpressibleSymbol::Class(class_symbol) => {
let class_kind = ClassKind::new(&class_symbol.borrow().fqn_formatted());
Kind::Class(class_kind.into())
}
ExpressibleSymbol::Function(function_symbol) => {
let function_kind = FunctionKind::new(&function_symbol.borrow().fqn_formatted());
Kind::Function(function_kind.into())
}
ExpressibleSymbol::ClassMember(class_member_symbol) => {
todo!()
}
ExpressibleSymbol::Parameter(parameter_symbol) => {
todo!()
}
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol
.borrow()
.analyzed_kind()
.expect("VariableSymbol's analyzed_kind not set.")
.clone(),
};
identifier_expression.set_analyzed_kind(kind);
}