diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index 201bfc0..17dd070 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -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)* }; diff --git a/src/ast/mod.rs b/src/ast/mod.rs index c0c2416..d61c0b3 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -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 { diff --git a/src/bin/dmc/ir.rs b/src/bin/dmc/ir.rs index 4cc6d24..0ca18c7 100644 --- a/src/bin/dmc/ir.rs +++ b/src/bin/dmc/ir.rs @@ -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, Box> { - 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); diff --git a/src/ir/lower_ast.rs b/src/ir/lower_ast.rs index 993de63..f21860a 100644 --- a/src/ir/lower_ast.rs +++ b/src/ir/lower_ast.rs @@ -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, @@ -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") } diff --git a/src/lib.rs b/src/lib.rs index 28c7499..efccca0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/name_analysis/symbol/variable_symbol.rs b/src/name_analysis/symbol/variable_symbol.rs index ed7b9dd..466d90b 100644 --- a/src/name_analysis/symbol/variable_symbol.rs +++ b/src/name_analysis/symbol/variable_symbol.rs @@ -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, is_mutable: bool, source_definition: Option, + analyzed_kind: Option, } 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 { diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index a3154f3..59a1746 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -1224,6 +1224,8 @@ IdentifierExpression: fields: - expressible_symbol: kind: ExpressibleSymbol + - analyzed_kind: + kind: Kind ListExpression: struct: children: diff --git a/src/type_analysis/kinds/class_kind.rs b/src/type_analysis/kinds/class_kind.rs new file mode 100644 index 0000000..b278736 --- /dev/null +++ b/src/type_analysis/kinds/class_kind.rs @@ -0,0 +1,27 @@ +use std::fmt::Display; +use std::rc::Rc; + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct ClassKind { + fqn: Rc +} + +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 { + self.fqn.clone() + } +} + +impl Display for ClassKind { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.fqn) + } +} \ No newline at end of file diff --git a/src/type_analysis/kinds/function_kind.rs b/src/type_analysis/kinds/function_kind.rs new file mode 100644 index 0000000..629addf --- /dev/null +++ b/src/type_analysis/kinds/function_kind.rs @@ -0,0 +1,27 @@ +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct FunctionKind { + fqn: Rc, +} + +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 { + self.fqn.clone() + } +} + +impl Display for FunctionKind { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.fqn) + } +} diff --git a/src/type_analysis/kinds/mod.rs b/src/type_analysis/kinds/mod.rs new file mode 100644 index 0000000..31fa6c0 --- /dev/null +++ b/src/type_analysis/kinds/mod.rs @@ -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), + Class(Box), + Function(Box), +} + +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) + } + } + } +} diff --git a/src/type_analysis/kinds/primitive_kind.rs b/src/type_analysis/kinds/primitive_kind.rs new file mode 100644 index 0000000..3ed9504 --- /dev/null +++ b/src/type_analysis/kinds/primitive_kind.rs @@ -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) + } +} diff --git a/src/type_analysis/mod.rs b/src/type_analysis/mod.rs new file mode 100644 index 0000000..f109dcc --- /dev/null +++ b/src/type_analysis/mod.rs @@ -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 { + let mut diagnostics: Vec = 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, +) { + 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, +) { + 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) { + ta_function_body(function.function_body_mut(), diagnostics); +} + +fn ta_function_body(function_body: &mut FunctionBody, diagnostics: &mut Vec) { + 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, +) { + for statement in function_block_body.statements_mut() { + ta_statement(statement, diagnostics); + } +} + +fn ta_statement(statement: &mut Statement, diagnostics: &mut Vec) { + 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, +) { + // 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, +) { + ta_expression(expression_statement.expression_mut(), diagnostics); +} + +fn ta_expression(expression: &mut Expression, diagnostics: &mut Vec) { + 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, +) { + 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); +}