From e6cfef9a7767ed60b7f1c55cfc576218059b5110 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Wed, 4 Feb 2026 20:05:47 +0000 Subject: [PATCH] pr 05.d --- crates/prometeu-analysis/src/interner.rs | 6 +- crates/prometeu-compiler/src/common/files.rs | 22 +- .../src/frontends/pbs/mod.rs | 3 + .../src/frontends/pbs/resolver.rs | 237 +++++++++++++++--- 4 files changed, 237 insertions(+), 31 deletions(-) diff --git a/crates/prometeu-analysis/src/interner.rs b/crates/prometeu-analysis/src/interner.rs index 135dfcc4..e1c76f16 100644 --- a/crates/prometeu-analysis/src/interner.rs +++ b/crates/prometeu-analysis/src/interner.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct NameId(pub u32); -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct NameInterner { names: Vec, ids: HashMap, @@ -28,6 +28,10 @@ impl NameInterner { id } + pub fn get(&self, s: &str) -> Option { + self.ids.get(s).copied() + } + pub fn resolve(&self, id: NameId) -> &str { &self.names[id.0 as usize] } diff --git a/crates/prometeu-compiler/src/common/files.rs b/crates/prometeu-compiler/src/common/files.rs index 630293c8..d0c7dca9 100644 --- a/crates/prometeu-compiler/src/common/files.rs +++ b/crates/prometeu-compiler/src/common/files.rs @@ -1,3 +1,4 @@ +use prometeu_analysis::interner::NameInterner; use std::path::PathBuf; use std::sync::Arc; @@ -11,11 +12,30 @@ pub struct SourceFile { #[derive(Debug, Clone)] pub struct FileManager { files: Vec, + interner: NameInterner, } impl FileManager { pub fn new() -> Self { - Self { files: Vec::new() } + Self { + files: Vec::new(), + interner: NameInterner::new(), + } + } + + pub fn with_interner(interner: NameInterner) -> Self { + Self { + files: Vec::new(), + interner, + } + } + + pub fn interner(&self) -> &NameInterner { + &self.interner + } + + pub fn interner_mut(&mut self) -> &mut NameInterner { + &mut self.interner } pub fn add(&mut self, path: PathBuf, source: String) -> usize { diff --git a/crates/prometeu-compiler/src/frontends/pbs/mod.rs b/crates/prometeu-compiler/src/frontends/pbs/mod.rs index b0d6f114..3fa6db85 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/mod.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/mod.rs @@ -59,6 +59,9 @@ impl Frontend for PbsFrontend { } let mut resolver = Resolver::new(&module_symbols, &EmptyProvider, &interner); + // Step 3: Resolve and type expressions + let mut interner_mut = file_manager.interner_mut(); + resolver.bootstrap_types(&mut interner_mut); resolver.resolve(&parsed.arena, parsed.root)?; let imported_symbols = resolver.imported_symbols; diff --git a/crates/prometeu-compiler/src/frontends/pbs/resolver.rs b/crates/prometeu-compiler/src/frontends/pbs/resolver.rs index 64f8ad96..aee051e4 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/resolver.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/resolver.rs @@ -1,3 +1,4 @@ +use crate::analysis::types::{TypeArena, TypeFacts, TypeId, TypeKind}; use crate::common::diagnostics::{Diagnostic, DiagnosticBundle, DiagnosticLevel}; use crate::common::spans::Span; use crate::frontends::pbs::ast::*; @@ -16,6 +17,9 @@ pub struct Resolver<'a> { scopes: Vec>, pub imported_symbols: ModuleSymbols, diagnostics: Vec, + pub type_arena: TypeArena, + pub type_facts: TypeFacts, + primitives: HashMap, } impl<'a> Resolver<'a> { @@ -31,6 +35,18 @@ impl<'a> Resolver<'a> { scopes: Vec::new(), imported_symbols: ModuleSymbols::new(), diagnostics: Vec::new(), + type_arena: TypeArena::new(), + type_facts: TypeFacts::new(), + primitives: HashMap::new(), + } + } + + pub fn bootstrap_types(&mut self, interner: &mut NameInterner) { + let primitive_names = ["int", "bool", "float", "string", "bounded", "void"]; + for name in primitive_names { + let name_id = interner.intern(name); + let type_id = self.type_arena.intern_type(TypeKind::Primitive { name: name_id }); + self.primitives.insert(name.to_string(), type_id); } } @@ -148,33 +164,91 @@ impl<'a> Resolver<'a> { self.resolve_node(arena, *arg); } } - NodeKind::Unary(n) => self.resolve_node(arena, n.expr), + NodeKind::Unary(n) => { + self.resolve_node(arena, n.expr); + match n.op.as_str() { + "-" => { + let int_type = self.primitives.get("int").copied(); + if let Some(expr_type) = self.type_facts.get_node_type(n.expr) { + if Some(expr_type) == int_type { + if let Some(id) = int_type { + self.type_facts.set_node_type(node, id); + } + } else { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_MISMATCH".to_string()), + message: "Unary '-' operator expects 'int'".to_string(), + span: Some(arena.span(node)), + }); + } + } + } + "!" => { + let bool_type = self.primitives.get("bool").copied(); + if let Some(expr_type) = self.type_facts.get_node_type(n.expr) { + if Some(expr_type) == bool_type { + if let Some(id) = bool_type { + self.type_facts.set_node_type(node, id); + } + } else { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_MISMATCH".to_string()), + message: "Unary '!' operator expects 'bool'".to_string(), + span: Some(arena.span(node)), + }); + } + } + } + _ => {} + } + } NodeKind::Binary(n) => { self.resolve_node(arena, n.left); self.resolve_node(arena, n.right); - } - NodeKind::Cast(n) => { - self.resolve_node(arena, n.expr); - self.resolve_type_ref(arena, n.ty); - } - NodeKind::IfExpr(n) => { - self.resolve_node(arena, n.cond); - self.resolve_node(arena, n.then_block); - if let Some(else_block) = n.else_block { - self.resolve_node(arena, else_block); - } - } - NodeKind::WhenExpr(n) => { - for arm in &n.arms { - if let NodeKind::WhenArm(arm_node) = arena.kind(*arm) { - self.resolve_node(arena, arm_node.cond); - self.resolve_node(arena, arm_node.body); + + let left_type = self.type_facts.get_node_type(n.left); + let right_type = self.type_facts.get_node_type(n.right); + let int_type = self.primitives.get("int").copied(); + let bool_type = self.primitives.get("bool").copied(); + + match n.op.as_str() { + "+" | "-" | "*" | "/" => { + if let (Some(l), Some(r)) = (left_type, right_type) { + if Some(l) == int_type && Some(r) == int_type { + if let Some(id) = int_type { + self.type_facts.set_node_type(node, id); + } + } else { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_MISMATCH".to_string()), + message: format!("Binary '{}' operator expects 'int' operands", n.op), + span: Some(arena.span(node)), + }); + } + } } + "==" | "<" | ">" | "<=" | ">=" | "!=" => { + if let (Some(l), Some(r)) = (left_type, right_type) { + if l == r { + if let Some(id) = bool_type { + self.type_facts.set_node_type(node, id); + } + } else { + self.diagnostics.push(Diagnostic { + level: DiagnosticLevel::Error, + code: Some("E_TYPE_MISMATCH".to_string()), + message: format!("Binary '{}' operator expects operands of the same type", n.op), + span: Some(arena.span(node)), + }); + } + } + } + _ => {} } } - NodeKind::Ident(n) => { - self.resolve_identifier(n.name, arena.span(node), Namespace::Value); - } NodeKind::TypeName(n) => { self.resolve_identifier(n.name, arena.span(node), Namespace::Type); } @@ -210,6 +284,51 @@ impl<'a> Resolver<'a> { self.resolve_node(arena, n.body); self.exit_scope(); } + NodeKind::Cast(n) => { + self.resolve_node(arena, n.expr); + self.resolve_type_ref(arena, n.ty); + } + NodeKind::IfExpr(n) => { + self.resolve_node(arena, n.cond); + self.resolve_node(arena, n.then_block); + if let Some(else_block) = n.else_block { + self.resolve_node(arena, else_block); + } + } + NodeKind::WhenExpr(n) => { + for arm in &n.arms { + if let NodeKind::WhenArm(arm_node) = arena.kind(*arm) { + self.resolve_node(arena, arm_node.cond); + self.resolve_node(arena, arm_node.body); + } + } + } + NodeKind::Ident(n) => { + let _sym = self.resolve_identifier(n.name, arena.span(node), Namespace::Value); + // For v0 bootstrap, if we found a local variable, we don't know its type yet (no inference) + // but if we had a way to track symbol types, we'd use it here. + // For now, we only type literals and simple operators. + } + NodeKind::IntLit(_) => { + if let Some(id) = self.primitives.get("int") { + self.type_facts.set_node_type(node, *id); + } + } + NodeKind::FloatLit(_) => { + if let Some(id) = self.primitives.get("float") { + self.type_facts.set_node_type(node, *id); + } + } + NodeKind::BoundedLit(_) => { + if let Some(id) = self.primitives.get("bounded") { + self.type_facts.set_node_type(node, *id); + } + } + NodeKind::StringLit(_) => { + if let Some(id) = self.primitives.get("string") { + self.type_facts.set_node_type(node, *id); + } + } NodeKind::MemberAccess(n) => match arena.kind(n.object) { NodeKind::Ident(id) => { let ident_span = arena.span(n.object); @@ -231,7 +350,7 @@ impl<'a> Resolver<'a> { } } - fn resolve_fn_decl(&mut self, arena: &AstArena, id: NodeId, n: &FnDeclNodeArena) { + fn resolve_fn_decl(&mut self, arena: &AstArena, _id: NodeId, n: &FnDeclNodeArena) { self.enter_scope(); for param in &n.params { self.resolve_type_ref(arena, param.ty); @@ -507,10 +626,10 @@ mod tests { fn setup_test(source: &str) -> (ParsedAst, usize, NameInterner) { let mut fm = FileManager::new(); let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string()); - let mut interner = NameInterner::new(); - let mut parser = parser::Parser::new(source, file_id, &mut interner); + let mut interner = fm.interner().clone(); + let mut parser = parser::Parser::new(source, file_id, fm.interner_mut()); let parsed = parser.parse_file().expect("Parsing failed"); - (parsed, file_id, interner) + (parsed, file_id, fm.interner().clone()) } #[test] @@ -519,7 +638,7 @@ mod tests { declare struct Foo {} declare struct Foo {} "; - let (parsed, _, mut interner) = setup_test(source); + let (parsed, _, interner) = setup_test(source); let mut collector = SymbolCollector::new(&interner); let result = collector.collect(&parsed.arena, parsed.root); @@ -534,7 +653,7 @@ mod tests { declare struct Foo {} fn Foo() {} "; - let (parsed, _, mut interner) = setup_test(source); + let (parsed, _, interner) = setup_test(source); let mut collector = SymbolCollector::new(&interner); let result = collector.collect(&parsed.arena, parsed.root); @@ -550,7 +669,7 @@ mod tests { let x = y; } "; - let (parsed, _, mut interner) = setup_test(source); + let (parsed, _, interner) = setup_test(source); let mut collector = SymbolCollector::new(&interner); let (ts, vs) = collector .collect(&parsed.arena, parsed.root) @@ -578,7 +697,7 @@ mod tests { let y = x; } "; - let (parsed, _, mut interner) = setup_test(source); + let (parsed, _, interner) = setup_test(source); let mut collector = SymbolCollector::new(&interner); let (ts, vs) = collector .collect(&parsed.arena, parsed.root) @@ -713,4 +832,64 @@ mod tests { let bundle = result.unwrap_err(); assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_INVALID_IMPORT".to_string()))); } + + #[test] + fn test_typing_literals_and_binary() { + let source = " + fn main() { + let a = 1 + 2; + let b = 1 == 2; + let c = -1; + } + "; + let (parsed, _, mut interner) = setup_test(source); + let mut collector = SymbolCollector::new(&interner); + let (ts, vs) = collector.collect(&parsed.arena, parsed.root).unwrap(); + let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; + + struct EmptyProvider; + impl ModuleProvider for EmptyProvider { + fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None } + } + + let mut interner_for_bootstrap = interner.clone(); + let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); + resolver.bootstrap_types(&mut interner_for_bootstrap); + resolver.resolve(&parsed.arena, parsed.root).expect("Resolution failed"); + + // Verify types in TypeFacts using format_type for easier assertion + use crate::analysis::types::format_type; + + let mut found_a = false; + let mut found_b = false; + let mut found_c = false; + + for i in 0..parsed.arena.nodes.len() { + let id = NodeId(i as u32); + let kind = parsed.arena.kind(id); + + match kind { + NodeKind::Binary(n) if n.op == "+" => { + let ty = resolver.type_facts.get_node_type(id).expect("Binary + should have type"); + assert_eq!(format_type(ty, &resolver.type_arena, &interner_for_bootstrap, None), "int"); + found_a = true; + } + NodeKind::Binary(n) if n.op == "==" => { + let ty = resolver.type_facts.get_node_type(id).expect("Binary == should have type"); + assert_eq!(format_type(ty, &resolver.type_arena, &interner_for_bootstrap, None), "bool"); + found_b = true; + } + NodeKind::Unary(n) if n.op == "-" => { + let ty = resolver.type_facts.get_node_type(id).expect("Unary - should have type"); + assert_eq!(format_type(ty, &resolver.type_arena, &interner_for_bootstrap, None), "int"); + found_c = true; + } + _ => {} + } + } + + assert!(found_a, "Binary + node not found"); + assert!(found_b, "Binary == node not found"); + assert!(found_c, "Unary - node not found"); + } }