This commit is contained in:
bQUARKz 2026-02-04 18:00:57 +00:00
parent 4e66387f4e
commit 4c97430ea4
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
11 changed files with 1452 additions and 2324 deletions

View File

@ -4,7 +4,7 @@ use crate::common::diagnostics::DiagnosticBundle;
use crate::common::files::FileManager; use crate::common::files::FileManager;
use crate::common::spans::Span; use crate::common::spans::Span;
use crate::deps::resolver::ProjectId; use crate::deps::resolver::ProjectId;
use crate::frontends::pbs::ast::FileNode; use crate::frontends::pbs::ast::ParsedAst;
use crate::frontends::pbs::collector::SymbolCollector; use crate::frontends::pbs::collector::SymbolCollector;
use crate::frontends::pbs::lowering::Lowerer; use crate::frontends::pbs::lowering::Lowerer;
use crate::frontends::pbs::parser::Parser; use crate::frontends::pbs::parser::Parser;
@ -116,7 +116,7 @@ pub fn compile_project(
let mut interner = NameInterner::new(); let mut interner = NameInterner::new();
// 1. Parse all files and group symbols by module // 1. Parse all files and group symbols by module
let mut module_symbols_map: HashMap<String, ModuleSymbols> = HashMap::new(); let mut module_symbols_map: HashMap<String, ModuleSymbols> = HashMap::new();
let mut parsed_files: Vec<(String, FileNode)> = Vec::new(); // (module_path, ast) let mut parsed_files: Vec<(String, ParsedAst)> = Vec::new(); // (module_path, ast)
for source_rel in &step.sources { for source_rel in &step.sources {
let source_abs = step.project_dir.join(source_rel); let source_abs = step.project_dir.join(source_rel);
@ -124,10 +124,10 @@ pub fn compile_project(
let file_id = file_manager.add(source_abs.clone(), source_code.clone()); let file_id = file_manager.add(source_abs.clone(), source_code.clone());
let mut parser = Parser::new(&source_code, file_id, &mut interner); let mut parser = Parser::new(&source_code, file_id, &mut interner);
let ast = parser.parse_file()?; let parsed = parser.parse_file()?;
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (ts, vs) = collector.collect(&ast)?; let (ts, vs) = collector.collect(&parsed.arena, parsed.root)?;
let full_path = source_rel.to_string_lossy().replace('\\', "/"); let full_path = source_rel.to_string_lossy().replace('\\', "/");
let logical_module_path = if let Some(stripped) = full_path.strip_prefix("src/main/modules/") { let logical_module_path = if let Some(stripped) = full_path.strip_prefix("src/main/modules/") {
@ -173,7 +173,7 @@ pub fn compile_project(
let _ = ms.value_symbols.insert(sym); let _ = ms.value_symbols.insert(sym);
} }
parsed_files.push((module_path, ast)); parsed_files.push((module_path, parsed));
} }
// 2. Synthesize ModuleSymbols for dependencies // 2. Synthesize ModuleSymbols for dependencies
@ -243,10 +243,10 @@ pub fn compile_project(
// We need to collect imported symbols for Lowerer // We need to collect imported symbols for Lowerer
let mut file_imported_symbols: HashMap<String, ModuleSymbols> = HashMap::new(); // keyed by module_path let mut file_imported_symbols: HashMap<String, ModuleSymbols> = HashMap::new(); // keyed by module_path
for (module_path, ast) in &parsed_files { for (module_path, parsed) in &parsed_files {
let ms = module_symbols_map.get(module_path).unwrap(); let ms = module_symbols_map.get(module_path).unwrap();
let mut resolver = Resolver::new(ms, &module_provider, &interner); let mut resolver = Resolver::new(ms, &module_provider, &interner);
resolver.resolve(ast)?; resolver.resolve(&parsed.arena, parsed.root)?;
// Capture imported symbols // Capture imported symbols
file_imported_symbols.insert(module_path.clone(), resolver.imported_symbols.clone()); file_imported_symbols.insert(module_path.clone(), resolver.imported_symbols.clone());
@ -255,7 +255,7 @@ pub fn compile_project(
let mut ms_mut = module_symbols_map.get_mut(module_path).unwrap(); let mut ms_mut = module_symbols_map.get_mut(module_path).unwrap();
let imported = file_imported_symbols.get(module_path).unwrap(); let imported = file_imported_symbols.get(module_path).unwrap();
let mut typechecker = TypeChecker::new(&mut ms_mut, imported, &module_provider, &interner); let mut typechecker = TypeChecker::new(&mut ms_mut, imported, &module_provider, &interner);
typechecker.check(ast)?; typechecker.check(&parsed.arena, parsed.root)?;
} }
// 4. Lower to IR // 4. Lower to IR
@ -266,11 +266,11 @@ pub fn compile_project(
field_types: HashMap::new(), field_types: HashMap::new(),
}; };
for (module_path, ast) in &parsed_files { for (module_path, parsed) in &parsed_files {
let ms = module_symbols_map.get(module_path).unwrap(); let ms = module_symbols_map.get(module_path).unwrap();
let imported = file_imported_symbols.get(module_path).unwrap(); let imported = file_imported_symbols.get(module_path).unwrap();
let lowerer = Lowerer::new(ms, imported, &interner); let lowerer = Lowerer::new(&parsed.arena, ms, imported, &interner);
let program = lowerer.lower_file(ast, module_path)?; let program = lowerer.lower_file(parsed.root, module_path)?;
// Combine program into combined_program // Combine program into combined_program
if combined_program.modules.is_empty() { if combined_program.modules.is_empty() {

View File

@ -2,296 +2,296 @@ use crate::common::spans::Span;
use prometeu_analysis::NameId; use prometeu_analysis::NameId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct NodeId(pub u32);
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct AstArena {
pub nodes: Vec<NodeKind>,
pub spans: Vec<Span>,
pub roots: Vec<NodeId>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ParsedAst {
pub arena: AstArena,
pub root: NodeId,
}
impl AstArena {
pub fn push(&mut self, kind: NodeKind, span: Span) -> NodeId {
let id = NodeId(self.nodes.len() as u32);
self.nodes.push(kind);
self.spans.push(span);
id
}
pub fn kind(&self, id: NodeId) -> &NodeKind {
&self.nodes[id.0 as usize]
}
pub fn span(&self, id: NodeId) -> Span {
self.spans[id.0 as usize]
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "kind")] #[serde(tag = "kind")]
pub enum Node { pub enum NodeKind {
File(FileNode), File(FileNodeArena),
Import(ImportNode), Import(ImportNodeArena),
ImportSpec(ImportSpecNode), ImportSpec(ImportSpecNodeArena),
ServiceDecl(ServiceDeclNode), ServiceDecl(ServiceDeclNodeArena),
ServiceFnSig(ServiceFnSigNode), ServiceFnSig(ServiceFnSigNodeArena),
FnDecl(FnDeclNode), FnDecl(FnDeclNodeArena),
TypeDecl(TypeDeclNode), TypeDecl(TypeDeclNodeArena),
TypeBody(TypeBodyNode), TypeBody(TypeBodyNodeArena),
Block(BlockNode), Block(BlockNodeArena),
LetStmt(LetStmtNode), LetStmt(LetStmtNodeArena),
ExprStmt(ExprStmtNode), ExprStmt(ExprStmtNodeArena),
ReturnStmt(ReturnStmtNode), ReturnStmt(ReturnStmtNodeArena),
IntLit(IntLitNode), IntLit(IntLitNodeArena),
FloatLit(FloatLitNode), FloatLit(FloatLitNodeArena),
BoundedLit(BoundedLitNode), BoundedLit(BoundedLitNodeArena),
StringLit(StringLitNode), StringLit(StringLitNodeArena),
Ident(IdentNode), Ident(IdentNodeArena),
Call(CallNode), Call(CallNodeArena),
Unary(UnaryNode), Unary(UnaryNodeArena),
Binary(BinaryNode), Binary(BinaryNodeArena),
Cast(CastNode), Cast(CastNodeArena),
IfExpr(IfExprNode), IfExpr(IfExprNodeArena),
WhenExpr(WhenExprNode), WhenExpr(WhenExprNodeArena),
WhenArm(WhenArmNode), WhenArm(WhenArmNodeArena),
TypeName(TypeNameNode), TypeName(TypeNameNodeArena),
TypeApp(TypeAppNode), TypeApp(TypeAppNodeArena),
ConstructorDecl(ConstructorDeclNode), ConstructorDecl(ConstructorDeclNodeArena),
ConstantDecl(ConstantDeclNode), ConstantDecl(ConstantDeclNodeArena),
Alloc(AllocNode), Alloc(AllocNodeArena),
Mutate(MutateNode), Mutate(MutateNodeArena),
Borrow(BorrowNode), Borrow(BorrowNodeArena),
Peek(PeekNode), Peek(PeekNodeArena),
MemberAccess(MemberAccessNode), MemberAccess(MemberAccessNodeArena),
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FileNode { pub struct FileNodeArena {
pub span: Span, pub imports: Vec<NodeId>,
pub imports: Vec<Node>, pub decls: Vec<NodeId>,
pub decls: Vec<Node>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ImportNode { pub struct ImportNodeArena {
pub span: Span, pub spec: NodeId,
pub spec: Box<Node>, // Must be ImportSpec
pub from: String, pub from: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ImportSpecNode { pub struct ImportSpecNodeArena {
pub span: Span,
pub path: Vec<NameId>, pub path: Vec<NameId>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ServiceDeclNode { pub struct ServiceDeclNodeArena {
pub span: Span, pub vis: Option<String>,
pub vis: Option<String>, // "pub" | "mod"
pub name: NameId, pub name: NameId,
pub extends: Option<NameId>, pub extends: Option<NameId>,
pub members: Vec<Node>, // ServiceFnSig pub members: Vec<NodeId>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ServiceFnSigNode { pub struct ServiceFnSigNodeArena {
pub name: NameId,
pub params: Vec<ParamNodeArena>,
pub ret: NodeId,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ParamNodeArena {
pub span: Span, pub span: Span,
pub name: NameId, pub name: NameId,
pub params: Vec<ParamNode>, pub ty: NodeId,
pub ret: Box<Node>, // TypeName or TypeApp
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ParamNode { pub struct FnDeclNodeArena {
pub span: Span,
pub name: NameId,
pub ty: Box<Node>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FnDeclNode {
pub span: Span,
pub vis: Option<String>, pub vis: Option<String>,
pub name: NameId, pub name: NameId,
pub params: Vec<ParamNode>, pub params: Vec<ParamNodeArena>,
pub ret: Option<Box<Node>>, pub ret: Option<NodeId>,
pub else_fallback: Option<Box<Node>>, // Block pub else_fallback: Option<NodeId>,
pub body: Box<Node>, // Block pub body: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeDeclNode { pub struct TypeDeclNodeArena {
pub span: Span,
pub vis: Option<String>, pub vis: Option<String>,
pub type_kind: String, // "struct" | "contract" | "error" pub type_kind: String,
pub name: NameId, pub name: NameId,
pub is_host: bool, pub is_host: bool,
pub params: Vec<ParamNode>, // fields for struct/error pub params: Vec<ParamNodeArena>,
pub constructors: Vec<ConstructorDeclNode>, // [ ... ] pub constructors: Vec<NodeId>,
pub constants: Vec<ConstantDeclNode>, // [[ ... ]] pub constants: Vec<NodeId>,
pub body: Option<Box<Node>>, // TypeBody (methods) pub body: Option<NodeId>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConstructorDeclNode { pub struct ConstructorDeclNodeArena {
pub span: Span, pub params: Vec<ParamNodeArena>,
pub params: Vec<ParamNode>, pub initializers: Vec<NodeId>,
pub initializers: Vec<Node>,
pub name: NameId, pub name: NameId,
pub body: Box<Node>, // BlockNode pub body: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConstantDeclNode { pub struct ConstantDeclNodeArena {
pub name: NameId,
pub value: NodeId,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeBodyNodeArena {
pub members: Vec<TypeMemberNodeArena>,
pub methods: Vec<NodeId>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeMemberNodeArena {
pub span: Span, pub span: Span,
pub name: NameId, pub name: NameId,
pub value: Box<Node>, pub ty: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeBodyNode { pub struct BlockNodeArena {
pub span: Span, pub stmts: Vec<NodeId>,
pub members: Vec<TypeMemberNode>, pub tail: Option<NodeId>,
pub methods: Vec<ServiceFnSigNode>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeMemberNode { pub struct LetStmtNodeArena {
pub span: Span,
pub name: NameId,
pub ty: Box<Node>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BlockNode {
pub span: Span,
pub stmts: Vec<Node>,
pub tail: Option<Box<Node>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct LetStmtNode {
pub span: Span,
pub name: NameId, pub name: NameId,
pub is_mut: bool, pub is_mut: bool,
pub ty: Option<Box<Node>>, pub ty: Option<NodeId>,
pub init: Box<Node>, pub init: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ExprStmtNode { pub struct ExprStmtNodeArena {
pub span: Span, pub expr: NodeId,
pub expr: Box<Node>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ReturnStmtNode { pub struct ReturnStmtNodeArena {
pub span: Span, pub expr: Option<NodeId>,
pub expr: Option<Box<Node>>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IntLitNode { pub struct IntLitNodeArena {
pub span: Span,
pub value: i64, pub value: i64,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FloatLitNode { pub struct FloatLitNodeArena {
pub span: Span,
pub value: f64, pub value: f64,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BoundedLitNode { pub struct BoundedLitNodeArena {
pub span: Span,
pub value: u32, pub value: u32,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StringLitNode { pub struct StringLitNodeArena {
pub span: Span,
pub value: String, pub value: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IdentNode { pub struct IdentNodeArena {
pub span: Span,
pub name: NameId, pub name: NameId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CallNode { pub struct CallNodeArena {
pub span: Span, pub callee: NodeId,
pub callee: Box<Node>, pub args: Vec<NodeId>,
pub args: Vec<Node>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct UnaryNode { pub struct UnaryNodeArena {
pub span: Span,
pub op: String, pub op: String,
pub expr: Box<Node>, pub expr: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BinaryNode { pub struct BinaryNodeArena {
pub span: Span,
pub op: String, pub op: String,
pub left: Box<Node>, pub left: NodeId,
pub right: Box<Node>, pub right: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CastNode { pub struct CastNodeArena {
pub span: Span, pub expr: NodeId,
pub expr: Box<Node>, pub ty: NodeId,
pub ty: Box<Node>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct IfExprNode { pub struct IfExprNodeArena {
pub span: Span, pub cond: NodeId,
pub cond: Box<Node>, pub then_block: NodeId,
pub then_block: Box<Node>, pub else_block: Option<NodeId>,
pub else_block: Option<Box<Node>>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct WhenExprNode { pub struct WhenExprNodeArena {
pub span: Span, pub arms: Vec<NodeId>,
pub arms: Vec<Node>, // WhenArm
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct WhenArmNode { pub struct WhenArmNodeArena {
pub span: Span, pub cond: NodeId,
pub cond: Box<Node>, pub body: NodeId,
pub body: Box<Node>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeNameNode { pub struct TypeNameNodeArena {
pub span: Span,
pub name: NameId, pub name: NameId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TypeAppNode { pub struct TypeAppNodeArena {
pub span: Span,
pub base: NameId, pub base: NameId,
pub args: Vec<Node>, pub args: Vec<NodeId>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AllocNode { pub struct AllocNodeArena {
pub span: Span, pub ty: NodeId,
pub ty: Box<Node>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MutateNode { pub struct MutateNodeArena {
pub span: Span, pub target: NodeId,
pub target: Box<Node>,
pub binding: NameId, pub binding: NameId,
pub body: Box<Node>, // BlockNode pub body: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BorrowNode { pub struct BorrowNodeArena {
pub span: Span, pub target: NodeId,
pub target: Box<Node>,
pub binding: NameId, pub binding: NameId,
pub body: Box<Node>, // BlockNode pub body: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PeekNode { pub struct PeekNodeArena {
pub span: Span, pub target: NodeId,
pub target: Box<Node>,
pub binding: NameId, pub binding: NameId,
pub body: Box<Node>, // BlockNode pub body: NodeId,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MemberAccessNode { pub struct MemberAccessNodeArena {
pub span: Span, pub object: NodeId,
pub object: Box<Node>,
pub member: NameId, pub member: NameId,
} }

View File

@ -21,12 +21,26 @@ impl<'a> SymbolCollector<'a> {
} }
} }
pub fn collect(&mut self, file: &FileNode) -> Result<(SymbolTable, SymbolTable), DiagnosticBundle> { pub fn collect(
&mut self,
arena: &AstArena,
root: NodeId,
) -> Result<(SymbolTable, SymbolTable), DiagnosticBundle> {
let file = match arena.kind(root) {
NodeKind::File(file) => file,
_ => {
return Err(DiagnosticBundle::error(
"Expected File node as root".to_string(),
None,
))
}
};
for decl in &file.decls { for decl in &file.decls {
match decl { match arena.kind(*decl) {
Node::FnDecl(fn_decl) => self.collect_fn(fn_decl), NodeKind::FnDecl(fn_decl) => self.collect_fn(arena, *decl, fn_decl),
Node::ServiceDecl(service_decl) => self.collect_service(service_decl), NodeKind::ServiceDecl(service_decl) => self.collect_service(arena, *decl, service_decl),
Node::TypeDecl(type_decl) => self.collect_type(type_decl), NodeKind::TypeDecl(type_decl) => self.collect_type(arena, *decl, type_decl),
_ => {} _ => {}
} }
} }
@ -43,50 +57,53 @@ impl<'a> SymbolCollector<'a> {
)) ))
} }
fn collect_fn(&mut self, decl: &FnDeclNode) { fn collect_fn(&mut self, arena: &AstArena, id: NodeId, decl: &FnDeclNodeArena) {
let vis = match decl.vis.as_deref() { let vis = match decl.vis.as_deref() {
Some("pub") => Visibility::Pub, Some("pub") => Visibility::Pub,
Some("mod") => Visibility::Mod, Some("mod") => Visibility::Mod,
_ => Visibility::FilePrivate, _ => Visibility::FilePrivate,
}; };
self.check_export_eligibility(SymbolKind::Function, vis, decl.span); let span = arena.span(id);
self.check_export_eligibility(SymbolKind::Function, vis, span);
let symbol = Symbol { let symbol = Symbol {
name: decl.name.clone(), name: decl.name,
kind: SymbolKind::Function, kind: SymbolKind::Function,
namespace: Namespace::Value, namespace: Namespace::Value,
visibility: vis, visibility: vis,
ty: None, // Will be resolved later ty: None, // Will be resolved later
is_host: false, is_host: false,
span: decl.span, span,
origin: None, origin: None,
}; };
self.insert_value_symbol(symbol); self.insert_value_symbol(symbol);
} }
fn collect_service(&mut self, decl: &ServiceDeclNode) { fn collect_service(&mut self, arena: &AstArena, id: NodeId, decl: &ServiceDeclNodeArena) {
let vis = match decl.vis.as_deref() { let vis = match decl.vis.as_deref() {
Some("pub") => Visibility::Pub, Some("pub") => Visibility::Pub,
_ => Visibility::Mod, // Defaults to Mod _ => Visibility::Mod, // Defaults to Mod
}; };
self.check_export_eligibility(SymbolKind::Service, vis, decl.span); let span = arena.span(id);
self.check_export_eligibility(SymbolKind::Service, vis, span);
let symbol = Symbol { let symbol = Symbol {
name: decl.name.clone(), name: decl.name,
kind: SymbolKind::Service, kind: SymbolKind::Service,
namespace: Namespace::Type, // Service is a type namespace: Namespace::Type, // Service is a type
visibility: vis, visibility: vis,
ty: None, ty: None,
is_host: false, is_host: false,
span: decl.span, span,
origin: None, origin: None,
}; };
self.insert_type_symbol(symbol); self.insert_type_symbol(symbol);
} }
fn collect_type(&mut self, decl: &TypeDeclNode) { fn collect_type(&mut self, arena: &AstArena, id: NodeId, decl: &TypeDeclNodeArena) {
let vis = match decl.vis.as_deref() { let vis = match decl.vis.as_deref() {
Some("pub") => Visibility::Pub, Some("pub") => Visibility::Pub,
Some("mod") => Visibility::Mod, Some("mod") => Visibility::Mod,
@ -99,16 +116,18 @@ impl<'a> SymbolCollector<'a> {
_ => SymbolKind::Struct, // Default _ => SymbolKind::Struct, // Default
}; };
self.check_export_eligibility(kind.clone(), vis, decl.span); let span = arena.span(id);
self.check_export_eligibility(kind.clone(), vis, span);
let symbol = Symbol { let symbol = Symbol {
name: decl.name.clone(), name: decl.name,
kind, kind,
namespace: Namespace::Type, namespace: Namespace::Type,
visibility: vis, visibility: vis,
ty: None, ty: None,
is_host: decl.is_host, is_host: decl.is_host,
span: decl.span, span,
origin: None, origin: None,
}; };
self.insert_type_symbol(symbol); self.insert_type_symbol(symbol);

File diff suppressed because it is too large Load Diff

View File

@ -45,10 +45,11 @@ impl Frontend for PbsFrontend {
let mut interner = NameInterner::new(); let mut interner = NameInterner::new();
let mut parser = parser::Parser::new(&source, file_id, &mut interner); let mut parser = parser::Parser::new(&source, file_id, &mut interner);
let ast = parser.parse_file()?; let parsed = parser.parse_file()?;
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (type_symbols, value_symbols) = collector.collect(&ast)?; let (type_symbols, value_symbols) =
collector.collect(&parsed.arena, parsed.root)?;
let mut module_symbols = ModuleSymbols { type_symbols, value_symbols }; let mut module_symbols = ModuleSymbols { type_symbols, value_symbols };
struct EmptyProvider; struct EmptyProvider;
@ -57,16 +58,16 @@ impl Frontend for PbsFrontend {
} }
let mut resolver = Resolver::new(&module_symbols, &EmptyProvider, &interner); let mut resolver = Resolver::new(&module_symbols, &EmptyProvider, &interner);
resolver.resolve(&ast)?; resolver.resolve(&parsed.arena, parsed.root)?;
let imported_symbols = resolver.imported_symbols; let imported_symbols = resolver.imported_symbols;
let mut typechecker = TypeChecker::new(&mut module_symbols, &imported_symbols, &EmptyProvider, &interner); let mut typechecker = TypeChecker::new(&mut module_symbols, &imported_symbols, &EmptyProvider, &interner);
typechecker.check(&ast)?; typechecker.check(&parsed.arena, parsed.root)?;
// Lower to Core IR // Lower to Core IR
let lowerer = Lowerer::new(&module_symbols, &imported_symbols, &interner); let lowerer = Lowerer::new(&parsed.arena, &module_symbols, &imported_symbols, &interner);
let module_name = entry.file_stem().unwrap().to_string_lossy(); let module_name = entry.file_stem().unwrap().to_string_lossy();
let core_program = lowerer.lower_file(&ast, &module_name)?; let core_program = lowerer.lower_file(parsed.root, &module_name)?;
// Validate Core IR Invariants // Validate Core IR Invariants
crate::ir_core::validate_program(&core_program).map_err(|e| { crate::ir_core::validate_program(&core_program).map_err(|e| {

File diff suppressed because it is too large Load Diff

View File

@ -34,17 +34,27 @@ impl<'a> Resolver<'a> {
} }
} }
pub fn resolve(&mut self, file: &FileNode) -> Result<(), DiagnosticBundle> { pub fn resolve(&mut self, arena: &AstArena, root: NodeId) -> Result<(), DiagnosticBundle> {
let file = match arena.kind(root) {
NodeKind::File(file) => file,
_ => {
return Err(DiagnosticBundle::error(
"Expected File node as root".to_string(),
None,
))
}
};
// Step 1: Process imports to populate imported_symbols // Step 1: Process imports to populate imported_symbols
for imp in &file.imports { for imp in &file.imports {
if let Node::Import(imp_node) = imp { if let NodeKind::Import(imp_node) = arena.kind(*imp) {
self.resolve_import(imp_node); self.resolve_import(arena, *imp, imp_node);
} }
} }
// Step 2: Resolve all top-level declarations // Step 2: Resolve all top-level declarations
for decl in &file.decls { for decl in &file.decls {
self.resolve_node(decl); self.resolve_node(arena, *decl);
} }
if !self.diagnostics.is_empty() { if !self.diagnostics.is_empty() {
@ -56,237 +66,270 @@ impl<'a> Resolver<'a> {
Ok(()) Ok(())
} }
fn resolve_import(&mut self, imp: &ImportNode) { fn resolve_import(&mut self, arena: &AstArena, imp_id: NodeId, imp: &ImportNodeArena) {
let provider = self.module_provider; let provider = self.module_provider;
if let Some(target_symbols) = provider.get_module_symbols(&imp.from) { if let Some(target_symbols) = provider.get_module_symbols(&imp.from) {
if let Node::ImportSpec(spec) = &*imp.spec { let spec = match arena.kind(imp.spec) {
for name in &spec.path { NodeKind::ImportSpec(spec) => spec,
// Try to find in Type namespace _ => {
if let Some(sym) = target_symbols.type_symbols.get(*name) { self.diagnostics.push(Diagnostic {
if sym.visibility == Visibility::Pub { level: DiagnosticLevel::Error,
let mut sym = sym.clone(); code: Some("E_RESOLVE_INVALID_IMPORT".to_string()),
sym.origin = Some(imp.from.clone()); message: "Invalid import spec".to_string(),
if let Err(_) = self.imported_symbols.type_symbols.insert(sym) { span: Some(arena.span(imp_id)),
self.error_duplicate_import(*name, imp.span); });
} return;
} else { }
self.error_visibility(sym, imp.span); };
}
} for name in &spec.path {
// Try to find in Value namespace // Try to find in Type namespace
else if let Some(sym) = target_symbols.value_symbols.get(*name) { if let Some(sym) = target_symbols.type_symbols.get(*name) {
if sym.visibility == Visibility::Pub { if sym.visibility == Visibility::Pub {
let mut sym = sym.clone(); let mut sym = sym.clone();
sym.origin = Some(imp.from.clone()); sym.origin = Some(imp.from.clone());
if let Err(_) = self.imported_symbols.value_symbols.insert(sym) { if let Err(_) = self.imported_symbols.type_symbols.insert(sym) {
self.error_duplicate_import(*name, imp.span); self.error_duplicate_import(*name, arena.span(imp_id));
}
} else {
self.error_visibility(sym, imp.span);
} }
} else { } else {
self.error_undefined(*name, imp.span); self.error_visibility(sym, arena.span(imp_id));
} }
} }
// Try to find in Value namespace
else if let Some(sym) = target_symbols.value_symbols.get(*name) {
if sym.visibility == Visibility::Pub {
let mut sym = sym.clone();
sym.origin = Some(imp.from.clone());
if let Err(_) = self.imported_symbols.value_symbols.insert(sym) {
self.error_duplicate_import(*name, arena.span(imp_id));
}
} else {
self.error_visibility(sym, arena.span(imp_id));
}
} else {
self.error_undefined(*name, arena.span(imp_id));
}
} }
} else { } else {
self.diagnostics.push(Diagnostic { self.diagnostics.push(Diagnostic {
level: DiagnosticLevel::Error, level: DiagnosticLevel::Error,
code: Some("E_RESOLVE_INVALID_IMPORT".to_string()), code: Some("E_RESOLVE_INVALID_IMPORT".to_string()),
message: format!("Module not found: {}", imp.from), message: format!("Module not found: {}", imp.from),
span: Some(imp.span), span: Some(arena.span(imp_id)),
}); });
} }
} }
fn resolve_node(&mut self, node: &Node) { fn resolve_node(&mut self, arena: &AstArena, node: NodeId) {
match node { match arena.kind(node) {
Node::FnDecl(n) => self.resolve_fn_decl(n), NodeKind::FnDecl(n) => self.resolve_fn_decl(arena, node, n),
Node::ServiceDecl(n) => self.resolve_service_decl(n), NodeKind::ServiceDecl(n) => self.resolve_service_decl(arena, node, n),
Node::TypeDecl(n) => self.resolve_type_decl(n), NodeKind::TypeDecl(n) => self.resolve_type_decl(arena, node, n),
Node::Block(n) => self.resolve_block(n), NodeKind::Block(n) => self.resolve_block(arena, n),
Node::LetStmt(n) => self.resolve_let_stmt(n), NodeKind::LetStmt(n) => self.resolve_let_stmt(arena, node, n),
Node::ExprStmt(n) => self.resolve_node(&n.expr), NodeKind::ExprStmt(n) => self.resolve_node(arena, n.expr),
Node::ReturnStmt(n) => { NodeKind::ReturnStmt(n) => {
if let Some(expr) = &n.expr { if let Some(expr) = n.expr {
self.resolve_node(expr); self.resolve_node(arena, expr);
} }
} }
Node::Call(n) => { NodeKind::Call(n) => {
self.resolve_node(&n.callee); if let NodeKind::Ident(id) = arena.kind(n.callee) {
if !self.is_builtin(id.name, Namespace::Value) {
let value_sym = self.lookup_identifier(id.name, Namespace::Value);
if value_sym.is_none() && self.lookup_identifier(id.name, Namespace::Type).is_none() {
// TODO: Resolver for v0 allows unresolved call targets (e.g. constructors via prelude)
}
}
} else {
self.resolve_node(arena, n.callee);
}
for arg in &n.args { for arg in &n.args {
self.resolve_node(arg); self.resolve_node(arena, *arg);
} }
} }
Node::Unary(n) => self.resolve_node(&n.expr), NodeKind::Unary(n) => self.resolve_node(arena, n.expr),
Node::Binary(n) => { NodeKind::Binary(n) => {
self.resolve_node(&n.left); self.resolve_node(arena, n.left);
self.resolve_node(&n.right); self.resolve_node(arena, n.right);
} }
Node::Cast(n) => { NodeKind::Cast(n) => {
self.resolve_node(&n.expr); self.resolve_node(arena, n.expr);
self.resolve_type_ref(&n.ty); self.resolve_type_ref(arena, n.ty);
} }
Node::IfExpr(n) => { NodeKind::IfExpr(n) => {
self.resolve_node(&n.cond); self.resolve_node(arena, n.cond);
self.resolve_node(&n.then_block); self.resolve_node(arena, n.then_block);
if let Some(else_block) = &n.else_block { if let Some(else_block) = n.else_block {
self.resolve_node(else_block); self.resolve_node(arena, else_block);
} }
} }
Node::WhenExpr(n) => { NodeKind::WhenExpr(n) => {
for arm in &n.arms { for arm in &n.arms {
if let Node::WhenArm(arm_node) = arm { if let NodeKind::WhenArm(arm_node) = arena.kind(*arm) {
self.resolve_node(&arm_node.cond); self.resolve_node(arena, arm_node.cond);
self.resolve_node(&arm_node.body); self.resolve_node(arena, arm_node.body);
} }
} }
} }
Node::Ident(n) => { NodeKind::Ident(n) => {
self.resolve_identifier(n.name, n.span, Namespace::Value); self.resolve_identifier(n.name, arena.span(node), Namespace::Value);
} }
Node::TypeName(n) => { NodeKind::TypeName(n) => {
self.resolve_identifier(n.name, n.span, Namespace::Type); self.resolve_identifier(n.name, arena.span(node), Namespace::Type);
} }
Node::TypeApp(n) => { NodeKind::TypeApp(n) => {
self.resolve_identifier(n.base, n.span, Namespace::Type); self.resolve_identifier(n.base, arena.span(node), Namespace::Type);
for arg in &n.args { for arg in &n.args {
self.resolve_type_ref(arg); self.resolve_type_ref(arena, *arg);
} }
} }
Node::ConstructorDecl(n) => self.resolve_constructor_decl(n), NodeKind::ConstructorDecl(n) => self.resolve_constructor_decl(arena, node, n),
Node::ConstantDecl(n) => self.resolve_node(&n.value), NodeKind::ConstantDecl(n) => self.resolve_node(arena, n.value),
Node::Alloc(n) => { NodeKind::Alloc(n) => {
self.resolve_type_ref(&n.ty); self.resolve_type_ref(arena, n.ty);
} }
Node::Mutate(n) => { NodeKind::Mutate(n) => {
self.resolve_node(&n.target); self.resolve_node(arena, n.target);
self.enter_scope(); self.enter_scope();
self.define_local(n.binding, n.span, SymbolKind::Local); self.define_local(n.binding, arena.span(node), SymbolKind::Local);
self.resolve_node(&n.body); self.resolve_node(arena, n.body);
self.exit_scope(); self.exit_scope();
} }
Node::Borrow(n) => { NodeKind::Borrow(n) => {
self.resolve_node(&n.target); self.resolve_node(arena, n.target);
self.enter_scope(); self.enter_scope();
self.define_local(n.binding, n.span, SymbolKind::Local); self.define_local(n.binding, arena.span(node), SymbolKind::Local);
self.resolve_node(&n.body); self.resolve_node(arena, n.body);
self.exit_scope(); self.exit_scope();
} }
Node::Peek(n) => { NodeKind::Peek(n) => {
self.resolve_node(&n.target); self.resolve_node(arena, n.target);
self.enter_scope(); self.enter_scope();
self.define_local(n.binding, n.span, SymbolKind::Local); self.define_local(n.binding, arena.span(node), SymbolKind::Local);
self.resolve_node(&n.body); self.resolve_node(arena, n.body);
self.exit_scope(); self.exit_scope();
} }
Node::MemberAccess(n) => { NodeKind::MemberAccess(n) => match arena.kind(n.object) {
if let Node::Ident(id) = &*n.object { NodeKind::Ident(id) => {
let ident_span = arena.span(n.object);
if !self.is_builtin(id.name, Namespace::Type) { if !self.is_builtin(id.name, Namespace::Type) {
if self.lookup_identifier(id.name, Namespace::Value).is_none() { if self.lookup_identifier(id.name, Namespace::Value).is_none() {
// If not found in Value namespace, try Type namespace (for Contracts/Services) // If not found in Value namespace, try Type namespace (for Contracts/Services)
if self.lookup_identifier(id.name, Namespace::Type).is_none() { if self.lookup_identifier(id.name, Namespace::Type).is_none() {
// Still not found, use resolve_identifier to report error in Value namespace // Still not found, use resolve_identifier to report error in Value namespace
self.resolve_identifier(id.name, id.span, Namespace::Value); self.resolve_identifier(id.name, ident_span, Namespace::Value);
} }
} }
} }
} else {
self.resolve_node(&n.object);
} }
} _ => {
self.resolve_node(arena, n.object);
}
},
_ => {} _ => {}
} }
} }
fn resolve_fn_decl(&mut self, n: &FnDeclNode) { fn resolve_fn_decl(&mut self, arena: &AstArena, id: NodeId, n: &FnDeclNodeArena) {
self.enter_scope(); self.enter_scope();
for param in &n.params { for param in &n.params {
self.resolve_type_ref(&param.ty); self.resolve_type_ref(arena, param.ty);
self.define_local(param.name, param.span, SymbolKind::Local); self.define_local(param.name, param.span, SymbolKind::Local);
} }
if let Some(ret) = &n.ret { if let Some(ret) = n.ret {
self.resolve_type_ref(ret); self.resolve_type_ref(arena, ret);
} }
self.resolve_node(&n.body); self.resolve_node(arena, n.body);
self.exit_scope(); self.exit_scope();
} }
fn resolve_service_decl(&mut self, n: &ServiceDeclNode) { fn resolve_service_decl(&mut self, arena: &AstArena, id: NodeId, n: &ServiceDeclNodeArena) {
if let Some(ext) = &n.extends { if let Some(ext) = n.extends {
self.resolve_identifier(*ext, n.span, Namespace::Type); self.resolve_identifier(ext, arena.span(id), Namespace::Type);
} }
for member in &n.members { for member in &n.members {
if let Node::ServiceFnSig(sig) = member { if let NodeKind::ServiceFnSig(sig) = arena.kind(*member) {
for param in &sig.params { for param in &sig.params {
self.resolve_type_ref(&param.ty); self.resolve_type_ref(arena, param.ty);
} }
self.resolve_type_ref(&sig.ret); self.resolve_type_ref(arena, sig.ret);
} }
} }
} }
fn resolve_type_decl(&mut self, n: &TypeDeclNode) { fn resolve_type_decl(&mut self, arena: &AstArena, _id: NodeId, n: &TypeDeclNodeArena) {
for param in &n.params { for param in &n.params {
self.resolve_type_ref(&param.ty); self.resolve_type_ref(arena, param.ty);
} }
for constructor in &n.constructors { for constructor in &n.constructors {
self.resolve_constructor_decl(constructor); if let NodeKind::ConstructorDecl(ctor) = arena.kind(*constructor) {
self.resolve_constructor_decl(arena, *constructor, ctor);
}
} }
self.enter_scope(); self.enter_scope();
for ctor in &n.constructors { for ctor_id in &n.constructors {
self.define_local(ctor.name, ctor.span, SymbolKind::Local); if let NodeKind::ConstructorDecl(ctor) = arena.kind(*ctor_id) {
self.define_local(ctor.name, arena.span(*ctor_id), SymbolKind::Local);
}
} }
for constant in &n.constants { for constant in &n.constants {
self.resolve_node(&constant.value); self.resolve_node(arena, *constant);
} }
self.exit_scope(); self.exit_scope();
if let Some(body_node) = &n.body { if let Some(body_node) = n.body {
if let Node::TypeBody(body) = &**body_node { if let NodeKind::TypeBody(body) = arena.kind(body_node) {
for member in &body.members { for member in &body.members {
self.resolve_type_ref(&member.ty); self.resolve_type_ref(arena, member.ty);
} }
for method in &body.methods { for method in &body.methods {
for param in &method.params { if let NodeKind::ServiceFnSig(sig) = arena.kind(*method) {
self.resolve_type_ref(&param.ty); for param in &sig.params {
self.resolve_type_ref(arena, param.ty);
}
self.resolve_type_ref(arena, sig.ret);
} }
self.resolve_type_ref(&method.ret);
} }
} }
} }
} }
fn resolve_constructor_decl(&mut self, n: &ConstructorDeclNode) { fn resolve_constructor_decl(
&mut self,
arena: &AstArena,
_id: NodeId,
n: &ConstructorDeclNodeArena,
) {
self.enter_scope(); self.enter_scope();
for param in &n.params { for param in &n.params {
self.resolve_type_ref(&param.ty); self.resolve_type_ref(arena, param.ty);
self.define_local(param.name, param.span, SymbolKind::Local); self.define_local(param.name, param.span, SymbolKind::Local);
} }
for init in &n.initializers { for init in &n.initializers {
self.resolve_node(init); self.resolve_node(arena, *init);
} }
self.resolve_node(&n.body); self.resolve_node(arena, n.body);
self.exit_scope(); self.exit_scope();
} }
fn resolve_block(&mut self, n: &BlockNode) { fn resolve_block(&mut self, arena: &AstArena, n: &BlockNodeArena) {
self.enter_scope(); self.enter_scope();
for stmt in &n.stmts { for stmt in &n.stmts {
self.resolve_node(stmt); self.resolve_node(arena, *stmt);
} }
self.exit_scope(); self.exit_scope();
} }
fn resolve_let_stmt(&mut self, n: &LetStmtNode) { fn resolve_let_stmt(&mut self, arena: &AstArena, id: NodeId, n: &LetStmtNodeArena) {
if let Some(ty) = &n.ty { if let Some(ty) = n.ty {
self.resolve_type_ref(ty); self.resolve_type_ref(arena, ty);
} }
self.resolve_node(&n.init); self.resolve_node(arena, n.init);
self.define_local(n.name, n.span, SymbolKind::Local); self.define_local(n.name, arena.span(id), SymbolKind::Local);
} }
fn resolve_type_ref(&mut self, node: &Node) { fn resolve_type_ref(&mut self, arena: &AstArena, node: NodeId) {
self.resolve_node(node); self.resolve_node(arena, node);
} }
fn resolve_identifier(&mut self, name: NameId, span: Span, namespace: Namespace) -> Option<Symbol> { fn resolve_identifier(&mut self, name: NameId, span: Span, namespace: Namespace) -> Option<Symbol> {
@ -461,13 +504,13 @@ mod tests {
use crate::frontends::pbs::*; use crate::frontends::pbs::*;
use std::path::PathBuf; use std::path::PathBuf;
fn setup_test(source: &str) -> (ast::FileNode, usize, NameInterner) { fn setup_test(source: &str) -> (ParsedAst, usize, NameInterner) {
let mut fm = FileManager::new(); let mut fm = FileManager::new();
let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string()); let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string());
let mut interner = NameInterner::new(); let mut interner = NameInterner::new();
let mut parser = parser::Parser::new(source, file_id, &mut interner); let mut parser = parser::Parser::new(source, file_id, &mut interner);
let ast = parser.parse_file().expect("Parsing failed"); let parsed = parser.parse_file().expect("Parsing failed");
(ast, file_id, interner) (parsed, file_id, interner)
} }
#[test] #[test]
@ -476,9 +519,9 @@ mod tests {
declare struct Foo {} declare struct Foo {}
declare struct Foo {} declare struct Foo {}
"; ";
let (ast, _, mut interner) = setup_test(source); let (parsed, _, mut interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let result = collector.collect(&ast); let result = collector.collect(&parsed.arena, parsed.root);
assert!(result.is_err()); assert!(result.is_err());
let bundle = result.unwrap_err(); let bundle = result.unwrap_err();
@ -491,9 +534,9 @@ mod tests {
declare struct Foo {} declare struct Foo {}
fn Foo() {} fn Foo() {}
"; ";
let (ast, _, mut interner) = setup_test(source); let (parsed, _, mut interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let result = collector.collect(&ast); let result = collector.collect(&parsed.arena, parsed.root);
assert!(result.is_err()); assert!(result.is_err());
let bundle = result.unwrap_err(); let bundle = result.unwrap_err();
@ -507,9 +550,11 @@ mod tests {
let x = y; let x = y;
} }
"; ";
let (ast, _, mut interner) = setup_test(source); let (parsed, _, mut interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let (ts, vs) = collector
.collect(&parsed.arena, parsed.root)
.expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct EmptyProvider; struct EmptyProvider;
@ -518,7 +563,7 @@ mod tests {
} }
let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner);
let result = resolver.resolve(&ast); let result = resolver.resolve(&parsed.arena, parsed.root);
assert!(result.is_err()); assert!(result.is_err());
let bundle = result.unwrap_err(); let bundle = result.unwrap_err();
@ -533,9 +578,11 @@ mod tests {
let y = x; let y = x;
} }
"; ";
let (ast, _, mut interner) = setup_test(source); let (parsed, _, mut interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let (ts, vs) = collector
.collect(&parsed.arena, parsed.root)
.expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct EmptyProvider; struct EmptyProvider;
@ -544,7 +591,7 @@ mod tests {
} }
let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner);
let result = resolver.resolve(&ast); let result = resolver.resolve(&parsed.arena, parsed.root);
assert!(result.is_ok()); assert!(result.is_ok());
} }
@ -555,9 +602,11 @@ mod tests {
import PrivateType from \"./other.pbs\" import PrivateType from \"./other.pbs\"
fn main() {} fn main() {}
"; ";
let (ast, _, mut interner) = setup_test(source); let (parsed, _, mut interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let (ts, vs) = collector
.collect(&parsed.arena, parsed.root)
.expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct MockProvider { struct MockProvider {
@ -586,7 +635,7 @@ mod tests {
}; };
let mut resolver = Resolver::new(&ms, &mock_provider, &interner); let mut resolver = Resolver::new(&ms, &mock_provider, &interner);
let result = resolver.resolve(&ast); let result = resolver.resolve(&parsed.arena, parsed.root);
assert!(result.is_err()); assert!(result.is_err());
let bundle = result.unwrap_err(); let bundle = result.unwrap_err();
@ -601,9 +650,11 @@ mod tests {
let x: PubType = 10; let x: PubType = 10;
} }
"; ";
let (ast, _, mut interner) = setup_test(source); let (parsed, _, mut interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let (ts, vs) = collector
.collect(&parsed.arena, parsed.root)
.expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct MockProvider { struct MockProvider {
@ -632,7 +683,7 @@ mod tests {
}; };
let mut resolver = Resolver::new(&ms, &mock_provider, &interner); let mut resolver = Resolver::new(&ms, &mock_provider, &interner);
let result = resolver.resolve(&ast); let result = resolver.resolve(&parsed.arena, parsed.root);
assert!(result.is_ok()); assert!(result.is_ok());
} }
@ -643,9 +694,11 @@ mod tests {
import NonExistent from \"./missing.pbs\" import NonExistent from \"./missing.pbs\"
fn main() {} fn main() {}
"; ";
let (ast, _, interner) = setup_test(source); let (parsed, _, interner) = setup_test(source);
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (ts, vs) = collector.collect(&ast).expect("Collection failed"); let (ts, vs) = collector
.collect(&parsed.arena, parsed.root)
.expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs }; let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct EmptyProvider; struct EmptyProvider;
@ -654,7 +707,7 @@ mod tests {
} }
let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner); let mut resolver = Resolver::new(&ms, &EmptyProvider, &interner);
let result = resolver.resolve(&ast); let result = resolver.resolve(&parsed.arena, parsed.root);
assert!(result.is_err()); assert!(result.is_err());
let bundle = result.unwrap_err(); let bundle = result.unwrap_err();

View File

@ -46,13 +46,23 @@ impl<'a> TypeChecker<'a> {
} }
} }
pub fn check(&mut self, file: &FileNode) -> Result<(), DiagnosticBundle> { pub fn check(&mut self, arena: &AstArena, root: NodeId) -> Result<(), DiagnosticBundle> {
let file = match arena.kind(root) {
NodeKind::File(file) => file,
_ => {
return Err(DiagnosticBundle::error(
"Expected File node as root".to_string(),
None,
))
}
};
// Step 1: Resolve signatures of all top-level declarations // Step 1: Resolve signatures of all top-level declarations
self.resolve_signatures(file); self.resolve_signatures(arena, file);
// Step 2: Check bodies // Step 2: Check bodies
for decl in &file.decls { for decl in &file.decls {
self.check_node(decl); self.check_node(arena, *decl);
} }
if !self.diagnostics.is_empty() { if !self.diagnostics.is_empty() {
@ -64,16 +74,16 @@ impl<'a> TypeChecker<'a> {
Ok(()) Ok(())
} }
fn resolve_signatures(&mut self, file: &FileNode) { fn resolve_signatures(&mut self, arena: &AstArena, file: &FileNodeArena) {
for decl in &file.decls { for decl in &file.decls {
match decl { match arena.kind(*decl) {
Node::FnDecl(n) => { NodeKind::FnDecl(n) => {
let mut params = Vec::new(); let mut params = Vec::new();
for param in &n.params { for param in &n.params {
params.push(self.resolve_type_node(&param.ty)); params.push(self.resolve_type_node(arena, param.ty));
} }
let return_type = if let Some(ret) = &n.ret { let return_type = if let Some(ret) = n.ret {
self.resolve_type_node(ret) self.resolve_type_node(arena, ret)
} else { } else {
PbsType::Void PbsType::Void
}; };
@ -85,13 +95,13 @@ impl<'a> TypeChecker<'a> {
sym.ty = Some(ty); sym.ty = Some(ty);
} }
} }
Node::ServiceDecl(n) => { NodeKind::ServiceDecl(n) => {
// For service, the symbol's type is just Service(name) // For service, the symbol's type is just Service(name)
if let Some(sym) = self.module_symbols.type_symbols.symbols.get_mut(&n.name) { if let Some(sym) = self.module_symbols.type_symbols.symbols.get_mut(&n.name) {
sym.ty = Some(PbsType::Service(self.interner.resolve(n.name).to_string())); sym.ty = Some(PbsType::Service(self.interner.resolve(n.name).to_string()));
} }
} }
Node::TypeDecl(n) => { NodeKind::TypeDecl(n) => {
let type_name = self.interner.resolve(n.name).to_string(); let type_name = self.interner.resolve(n.name).to_string();
let ty = match n.type_kind.as_str() { let ty = match n.type_kind.as_str() {
"struct" => PbsType::Struct(type_name.clone()), "struct" => PbsType::Struct(type_name.clone()),
@ -109,49 +119,48 @@ impl<'a> TypeChecker<'a> {
// Default constructor: TypeName(...) // Default constructor: TypeName(...)
if n.type_kind == "struct" { if n.type_kind == "struct" {
let mut params = Vec::new(); let mut params = Vec::new();
let mut initializers = Vec::new();
for p in &n.params { for p in &n.params {
let p_ty = self.resolve_type_node(&p.ty); let p_ty = self.resolve_type_node(arena, p.ty);
params.push(p_ty); params.push(p_ty);
initializers.push(Node::Ident(IdentNode {
span: p.span,
name: p.name.clone(),
}));
} }
let default_ctor_ty = PbsType::Function { let default_ctor_ty = PbsType::Function {
params: params.clone(), params,
return_type: Box::new(ty.clone()), return_type: Box::new(ty.clone()),
}; };
ctors.insert(type_name.clone(), default_ctor_ty); ctors.insert(type_name.clone(), default_ctor_ty);
} }
for ctor in &n.constructors { for ctor in &n.constructors {
let mut params = Vec::new(); if let NodeKind::ConstructorDecl(ctor) = arena.kind(*ctor) {
for p in &ctor.params { let mut params = Vec::new();
params.push(self.resolve_type_node(&p.ty)); for p in &ctor.params {
params.push(self.resolve_type_node(arena, p.ty));
}
let ctor_ty = PbsType::Function {
params,
return_type: Box::new(ty.clone()),
};
ctors.insert(self.interner.resolve(ctor.name).to_string(), ctor_ty);
} }
let ctor_ty = PbsType::Function {
params,
return_type: Box::new(ty.clone()),
};
ctors.insert(self.interner.resolve(ctor.name).to_string(), ctor_ty);
} }
self.struct_constructors.insert(type_name.clone(), ctors); self.struct_constructors.insert(type_name.clone(), ctors);
// Resolve methods // Resolve methods
let mut methods = HashMap::new(); let mut methods = HashMap::new();
if let Some(body_node) = &n.body { if let Some(body_node) = n.body {
if let Node::TypeBody(body) = &**body_node { if let NodeKind::TypeBody(body) = arena.kind(body_node) {
for m in &body.methods { for m in &body.methods {
let mut params = Vec::new(); if let NodeKind::ServiceFnSig(sig) = arena.kind(*m) {
for p in &m.params { let mut params = Vec::new();
params.push(self.resolve_type_node(&p.ty)); for p in &sig.params {
params.push(self.resolve_type_node(arena, p.ty));
}
let m_ty = PbsType::Function {
params,
return_type: Box::new(self.resolve_type_node(arena, sig.ret)),
};
methods.insert(self.interner.resolve(sig.name).to_string(), m_ty);
} }
let m_ty = PbsType::Function {
params,
return_type: Box::new(self.resolve_type_node(&m.ret)),
};
methods.insert(self.interner.resolve(m.name).to_string(), m_ty);
} }
} }
} }
@ -162,66 +171,77 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn check_node(&mut self, node: &Node) -> PbsType { fn check_node(&mut self, arena: &AstArena, node: NodeId) -> PbsType {
match node { match arena.kind(node) {
Node::FnDecl(n) => { NodeKind::FnDecl(n) => {
self.check_fn_decl(n); self.check_fn_decl(arena, node, n);
PbsType::Void PbsType::Void
} }
Node::TypeDecl(n) => { NodeKind::TypeDecl(n) => {
self.check_type_decl(n); self.check_type_decl(arena, node, n);
PbsType::Void PbsType::Void
} }
Node::ConstructorDecl(n) => { NodeKind::ConstructorDecl(n) => {
self.check_constructor_decl(n); self.check_constructor_decl(arena, node, n);
PbsType::Void PbsType::Void
} }
Node::ConstantDecl(n) => self.check_node(&n.value), NodeKind::ConstantDecl(n) => self.check_node(arena, n.value),
Node::Block(n) => self.check_block(n), NodeKind::Block(n) => self.check_block(arena, n),
Node::LetStmt(n) => { NodeKind::LetStmt(n) => {
self.check_let_stmt(n); self.check_let_stmt(arena, node, n);
PbsType::Void PbsType::Void
} }
Node::ExprStmt(n) => { NodeKind::ExprStmt(n) => {
self.check_node(&n.expr); self.check_node(arena, n.expr);
PbsType::Void PbsType::Void
} }
Node::ReturnStmt(n) => { NodeKind::ReturnStmt(n) => {
let ret_ty = if let Some(expr) = &n.expr { let ret_ty = if let Some(expr) = n.expr {
self.check_node(expr) self.check_node(arena, expr)
} else { } else {
PbsType::Void PbsType::Void
}; };
if let Some(expected) = self.current_return_type.clone() { if let Some(expected) = self.current_return_type.clone() {
if !self.is_assignable(&expected, &ret_ty) { if !self.is_assignable(&expected, &ret_ty) {
self.error_type_mismatch(&expected, &ret_ty, n.span); self.error_type_mismatch(&expected, &ret_ty, arena.span(node));
} }
} }
PbsType::Void PbsType::Void
} }
Node::IntLit(_) => PbsType::Int, NodeKind::IntLit(_) => PbsType::Int,
Node::FloatLit(_) => PbsType::Float, NodeKind::FloatLit(_) => PbsType::Float,
Node::BoundedLit(_) => PbsType::Bounded, NodeKind::BoundedLit(_) => PbsType::Bounded,
Node::StringLit(_) => PbsType::String, NodeKind::StringLit(_) => PbsType::String,
Node::Ident(n) => self.check_identifier(n), NodeKind::Ident(n) => self.check_identifier(arena, node, n),
Node::Call(n) => self.check_call(n), NodeKind::Call(n) => self.check_call(arena, node, n),
Node::Unary(n) => self.check_unary(n), NodeKind::Unary(n) => self.check_unary(arena, node, n),
Node::Binary(n) => self.check_binary(n), NodeKind::Binary(n) => self.check_binary(arena, node, n),
Node::Cast(n) => self.check_cast(n), NodeKind::Cast(n) => self.check_cast(arena, node, n),
Node::IfExpr(n) => self.check_if_expr(n), NodeKind::IfExpr(n) => self.check_if_expr(arena, node, n),
Node::WhenExpr(n) => self.check_when_expr(n), NodeKind::WhenExpr(n) => self.check_when_expr(arena, node, n),
Node::Alloc(n) => self.check_alloc(n), NodeKind::Alloc(n) => self.check_alloc(arena, node, n),
Node::Mutate(n) => self.check_hip(n.span, &n.target, n.binding, &n.body, true), NodeKind::Mutate(n) => {
Node::Borrow(n) => self.check_hip(n.span, &n.target, n.binding, &n.body, false), self.check_hip(arena, arena.span(node), n.target, n.binding, n.body, true)
Node::Peek(n) => self.check_hip(n.span, &n.target, n.binding, &n.body, false), }
Node::MemberAccess(n) => self.check_member_access(n), NodeKind::Borrow(n) => {
self.check_hip(arena, arena.span(node), n.target, n.binding, n.body, false)
}
NodeKind::Peek(n) => {
self.check_hip(arena, arena.span(node), n.target, n.binding, n.body, false)
}
NodeKind::MemberAccess(n) => self.check_member_access(arena, node, n),
_ => PbsType::Void, _ => PbsType::Void,
} }
} }
fn check_member_access(&mut self, n: &MemberAccessNode) -> PbsType { fn check_member_access(
&mut self,
arena: &AstArena,
node: NodeId,
n: &MemberAccessNodeArena,
) -> PbsType {
let member_str = self.interner.resolve(n.member); let member_str = self.interner.resolve(n.member);
if let Node::Ident(id) = &*n.object { if let NodeKind::Ident(id) = arena.kind(n.object) {
let name_str = self.interner.resolve(id.name); let name_str = self.interner.resolve(id.name);
// Check if it's a local first // Check if it's a local first
let is_local = self.scopes.iter().any(|s| s.contains_key(name_str)); let is_local = self.scopes.iter().any(|s| s.contains_key(name_str));
@ -244,7 +264,7 @@ impl<'a> TypeChecker<'a> {
level: DiagnosticLevel::Error, level: DiagnosticLevel::Error,
code: Some("E_RESOLVE_UNDEFINED".to_string()), code: Some("E_RESOLVE_UNDEFINED".to_string()),
message: format!("Method '{}' not found on host contract '{}'", member_str, name_str), message: format!("Method '{}' not found on host contract '{}'", member_str, name_str),
span: Some(n.span), span: Some(arena.span(node)),
}); });
} }
return PbsType::Void; return PbsType::Void;
@ -284,7 +304,7 @@ impl<'a> TypeChecker<'a> {
} }
} }
let obj_ty = self.check_node(&n.object); let obj_ty = self.check_node(arena, n.object);
if let PbsType::Struct(ref name) = obj_ty { if let PbsType::Struct(ref name) = obj_ty {
if let Some(methods) = self.struct_methods.get(name) { if let Some(methods) = self.struct_methods.get(name) {
if let Some(ty) = methods.get(member_str) { if let Some(ty) = methods.get(member_str) {
@ -355,21 +375,29 @@ impl<'a> TypeChecker<'a> {
level: DiagnosticLevel::Error, level: DiagnosticLevel::Error,
code: Some("E_RESOLVE_UNDEFINED".to_string()), code: Some("E_RESOLVE_UNDEFINED".to_string()),
message: msg, message: msg,
span: Some(n.span), span: Some(arena.span(node)),
}); });
} }
PbsType::Void PbsType::Void
} }
fn check_alloc(&mut self, n: &AllocNode) -> PbsType { fn check_alloc(&mut self, arena: &AstArena, _node: NodeId, n: &AllocNodeArena) -> PbsType {
let ty = self.resolve_type_node(&n.ty); let ty = self.resolve_type_node(arena, n.ty);
// For v0, alloc returns something that can be used with mutate/borrow/peek. // For v0, alloc returns something that can be used with mutate/borrow/peek.
// We'll call it a gate to the type. // We'll call it a gate to the type.
PbsType::Contract(format!("Gate<{}>", ty)) // Approximation for v0 PbsType::Contract(format!("Gate<{}>", ty)) // Approximation for v0
} }
fn check_hip(&mut self, _span: Span, target: &Node, binding: NameId, body: &Node, is_mut: bool) -> PbsType { fn check_hip(
let target_ty = self.check_node(target); &mut self,
arena: &AstArena,
_span: Span,
target: NodeId,
binding: NameId,
body: NodeId,
is_mut: bool,
) -> PbsType {
let target_ty = self.check_node(arena, target);
// In v0, we assume target is a gate. We bind the inner type to the binding. // In v0, we assume target is a gate. We bind the inner type to the binding.
let inner_ty = match target_ty { let inner_ty = match target_ty {
PbsType::Contract(name) if name.starts_with("Gate<") => { PbsType::Contract(name) if name.starts_with("Gate<") => {
@ -389,12 +417,12 @@ impl<'a> TypeChecker<'a> {
self.enter_scope(); self.enter_scope();
let binding_str = self.interner.resolve(binding); let binding_str = self.interner.resolve(binding);
self.define_local(binding_str, inner_ty, is_mut); self.define_local(binding_str, inner_ty, is_mut);
let body_ty = self.check_node(body); let body_ty = self.check_node(arena, body);
self.exit_scope(); self.exit_scope();
body_ty body_ty
} }
fn check_fn_decl(&mut self, n: &FnDeclNode) { fn check_fn_decl(&mut self, arena: &AstArena, id: NodeId, n: &FnDeclNodeArena) {
let sig = self.module_symbols.value_symbols.get(n.name).and_then(|s| s.ty.clone()); let sig = self.module_symbols.value_symbols.get(n.name).and_then(|s| s.ty.clone());
if let Some(PbsType::Function { params, return_type }) = sig { if let Some(PbsType::Function { params, return_type }) = sig {
self.enter_scope(); self.enter_scope();
@ -404,10 +432,10 @@ impl<'a> TypeChecker<'a> {
self.define_local(self.interner.resolve(param.name), ty.clone(), false); self.define_local(self.interner.resolve(param.name), ty.clone(), false);
} }
let _body_ty = self.check_node(&n.body); let _body_ty = self.check_node(arena, n.body);
// Return path validation // Return path validation
if !self.all_paths_return(&n.body) { if !self.all_paths_return(arena, n.body) {
if n.else_fallback.is_some() { if n.else_fallback.is_some() {
// OK // OK
} else if matches!(*return_type, PbsType::Optional(_)) { } else if matches!(*return_type, PbsType::Optional(_)) {
@ -423,13 +451,13 @@ impl<'a> TypeChecker<'a> {
self.interner.resolve(n.name), self.interner.resolve(n.name),
return_type return_type
), ),
span: Some(n.span), span: Some(arena.span(id)),
}); });
} }
} }
if let Some(fallback) = &n.else_fallback { if let Some(fallback) = n.else_fallback {
self.check_node(fallback); self.check_node(arena, fallback);
} }
self.current_return_type = None; self.current_return_type = None;
@ -437,13 +465,13 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn check_block(&mut self, n: &BlockNode) -> PbsType { fn check_block(&mut self, arena: &AstArena, n: &BlockNodeArena) -> PbsType {
self.enter_scope(); self.enter_scope();
for stmt in &n.stmts { for stmt in &n.stmts {
self.check_node(stmt); self.check_node(arena, *stmt);
} }
let tail_ty = if let Some(tail) = &n.tail { let tail_ty = if let Some(tail) = n.tail {
self.check_node(tail) self.check_node(arena, tail)
} else { } else {
PbsType::Void PbsType::Void
}; };
@ -451,13 +479,13 @@ impl<'a> TypeChecker<'a> {
tail_ty tail_ty
} }
fn check_let_stmt(&mut self, n: &LetStmtNode) { fn check_let_stmt(&mut self, arena: &AstArena, id: NodeId, n: &LetStmtNodeArena) {
let init_ty = self.check_node(&n.init); let init_ty = self.check_node(arena, n.init);
let declared_ty = n.ty.as_ref().map(|t| self.resolve_type_node(t)); let declared_ty = n.ty.map(|t| self.resolve_type_node(arena, t));
let final_ty = if let Some(dty) = declared_ty { let final_ty = if let Some(dty) = declared_ty {
if !self.is_assignable(&dty, &init_ty) { if !self.is_assignable(&dty, &init_ty) {
self.error_type_mismatch(&dty, &init_ty, n.span); self.error_type_mismatch(&dty, &init_ty, arena.span(id));
} }
dty dty
} else { } else {
@ -467,7 +495,7 @@ impl<'a> TypeChecker<'a> {
self.define_local(self.interner.resolve(n.name), final_ty, n.is_mut); self.define_local(self.interner.resolve(n.name), final_ty, n.is_mut);
} }
fn check_identifier(&mut self, n: &IdentNode) -> PbsType { fn check_identifier(&mut self, _arena: &AstArena, _id: NodeId, n: &IdentNodeArena) -> PbsType {
let name_str = self.interner.resolve(n.name); let name_str = self.interner.resolve(n.name);
// Check locals // Check locals
for scope in self.scopes.iter().rev() { for scope in self.scopes.iter().rev() {
@ -510,27 +538,27 @@ impl<'a> TypeChecker<'a> {
PbsType::Void PbsType::Void
} }
fn check_call(&mut self, n: &CallNode) -> PbsType { fn check_call(&mut self, arena: &AstArena, node: NodeId, n: &CallNodeArena) -> PbsType {
let callee_ty = self.check_node(&n.callee); let callee_ty = self.check_node(arena, n.callee);
// Handle special built-in "constructors" // Handle special built-in "constructors"
if let Node::Ident(id) = &*n.callee { if let NodeKind::Ident(id) = arena.kind(n.callee) {
match self.interner.resolve(id.name) { match self.interner.resolve(id.name) {
"some" => { "some" => {
if n.args.len() == 1 { if n.args.len() == 1 {
let inner_ty = self.check_node(&n.args[0]); let inner_ty = self.check_node(arena, n.args[0]);
return PbsType::Optional(Box::new(inner_ty)); return PbsType::Optional(Box::new(inner_ty));
} }
} }
"ok" => { "ok" => {
if n.args.len() == 1 { if n.args.len() == 1 {
let inner_ty = self.check_node(&n.args[0]); let inner_ty = self.check_node(arena, n.args[0]);
return PbsType::Result(Box::new(inner_ty), Box::new(PbsType::Void)); // Error type unknown here return PbsType::Result(Box::new(inner_ty), Box::new(PbsType::Void)); // Error type unknown here
} }
} }
"err" => { "err" => {
if n.args.len() == 1 { if n.args.len() == 1 {
let inner_ty = self.check_node(&n.args[0]); let inner_ty = self.check_node(arena, n.args[0]);
return PbsType::Result(Box::new(PbsType::Void), Box::new(inner_ty)); return PbsType::Result(Box::new(PbsType::Void), Box::new(inner_ty));
} }
} }
@ -545,13 +573,13 @@ impl<'a> TypeChecker<'a> {
level: DiagnosticLevel::Error, level: DiagnosticLevel::Error,
code: Some("E_TYPE_MISMATCH".to_string()), code: Some("E_TYPE_MISMATCH".to_string()),
message: format!("Expected {} arguments, found {}", params.len(), n.args.len()), message: format!("Expected {} arguments, found {}", params.len(), n.args.len()),
span: Some(n.span), span: Some(arena.span(node)),
}); });
} else { } else {
for (i, arg) in n.args.iter().enumerate() { for (i, arg) in n.args.iter().enumerate() {
let arg_ty = self.check_node(arg); let arg_ty = self.check_node(arena, *arg);
if !self.is_assignable(&params[i], &arg_ty) { if !self.is_assignable(&params[i], &arg_ty) {
self.error_type_mismatch(&params[i], &arg_ty, arg.span()); self.error_type_mismatch(&params[i], &arg_ty, arena.span(*arg));
} }
} }
} }
@ -563,7 +591,7 @@ impl<'a> TypeChecker<'a> {
level: DiagnosticLevel::Error, level: DiagnosticLevel::Error,
code: Some("E_TYPE_MISMATCH".to_string()), code: Some("E_TYPE_MISMATCH".to_string()),
message: format!("Type {} is not callable", callee_ty), message: format!("Type {} is not callable", callee_ty),
span: Some(n.span), span: Some(arena.span(node)),
}); });
} }
PbsType::Void PbsType::Void
@ -571,14 +599,14 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn check_unary(&mut self, n: &UnaryNode) -> PbsType { fn check_unary(&mut self, arena: &AstArena, node: NodeId, n: &UnaryNodeArena) -> PbsType {
let expr_ty = self.check_node(&n.expr); let expr_ty = self.check_node(arena, n.expr);
match n.op.as_str() { match n.op.as_str() {
"-" => { "-" => {
if expr_ty == PbsType::Int || expr_ty == PbsType::Float { if expr_ty == PbsType::Int || expr_ty == PbsType::Float {
expr_ty expr_ty
} else { } else {
self.error_type_mismatch(&PbsType::Int, &expr_ty, n.span); self.error_type_mismatch(&PbsType::Int, &expr_ty, arena.span(node));
PbsType::Void PbsType::Void
} }
} }
@ -586,7 +614,7 @@ impl<'a> TypeChecker<'a> {
if expr_ty == PbsType::Bool { if expr_ty == PbsType::Bool {
PbsType::Bool PbsType::Bool
} else { } else {
self.error_type_mismatch(&PbsType::Bool, &expr_ty, n.span); self.error_type_mismatch(&PbsType::Bool, &expr_ty, arena.span(node));
PbsType::Void PbsType::Void
} }
} }
@ -594,16 +622,16 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn check_binary(&mut self, n: &BinaryNode) -> PbsType { fn check_binary(&mut self, arena: &AstArena, node: NodeId, n: &BinaryNodeArena) -> PbsType {
let left_ty = self.check_node(&n.left); let left_ty = self.check_node(arena, n.left);
let right_ty = self.check_node(&n.right); let right_ty = self.check_node(arena, n.right);
match n.op.as_str() { match n.op.as_str() {
"+" | "-" | "*" | "/" | "%" => { "+" | "-" | "*" | "/" | "%" => {
if (left_ty == PbsType::Int || left_ty == PbsType::Float) && left_ty == right_ty { if (left_ty == PbsType::Int || left_ty == PbsType::Float) && left_ty == right_ty {
left_ty left_ty
} else { } else {
self.error_type_mismatch(&left_ty, &right_ty, n.span); self.error_type_mismatch(&left_ty, &right_ty, arena.span(node));
PbsType::Void PbsType::Void
} }
} }
@ -611,7 +639,7 @@ impl<'a> TypeChecker<'a> {
if left_ty == right_ty { if left_ty == right_ty {
PbsType::Bool PbsType::Bool
} else { } else {
self.error_type_mismatch(&left_ty, &right_ty, n.span); self.error_type_mismatch(&left_ty, &right_ty, arena.span(node));
PbsType::Bool PbsType::Bool
} }
} }
@ -619,7 +647,7 @@ impl<'a> TypeChecker<'a> {
if (left_ty == PbsType::Int || left_ty == PbsType::Float) && left_ty == right_ty { if (left_ty == PbsType::Int || left_ty == PbsType::Float) && left_ty == right_ty {
PbsType::Bool PbsType::Bool
} else { } else {
self.error_type_mismatch(&left_ty, &right_ty, n.span); self.error_type_mismatch(&left_ty, &right_ty, arena.span(node));
PbsType::Bool PbsType::Bool
} }
} }
@ -627,8 +655,8 @@ impl<'a> TypeChecker<'a> {
if left_ty == PbsType::Bool && right_ty == PbsType::Bool { if left_ty == PbsType::Bool && right_ty == PbsType::Bool {
PbsType::Bool PbsType::Bool
} else { } else {
self.error_type_mismatch(&PbsType::Bool, &left_ty, n.left.span()); self.error_type_mismatch(&PbsType::Bool, &left_ty, arena.span(n.left));
self.error_type_mismatch(&PbsType::Bool, &right_ty, n.right.span()); self.error_type_mismatch(&PbsType::Bool, &right_ty, arena.span(n.right));
PbsType::Bool PbsType::Bool
} }
} }
@ -636,23 +664,23 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn check_cast(&mut self, n: &CastNode) -> PbsType { fn check_cast(&mut self, arena: &AstArena, _node: NodeId, n: &CastNodeArena) -> PbsType {
let _expr_ty = self.check_node(&n.expr); let _expr_ty = self.check_node(arena, n.expr);
let target_ty = self.resolve_type_node(&n.ty); let target_ty = self.resolve_type_node(arena, n.ty);
// Minimal cast validation for v0 // Minimal cast validation for v0
target_ty target_ty
} }
fn check_if_expr(&mut self, n: &IfExprNode) -> PbsType { fn check_if_expr(&mut self, arena: &AstArena, node: NodeId, n: &IfExprNodeArena) -> PbsType {
let cond_ty = self.check_node(&n.cond); let cond_ty = self.check_node(arena, n.cond);
if cond_ty != PbsType::Bool { if cond_ty != PbsType::Bool {
self.error_type_mismatch(&PbsType::Bool, &cond_ty, n.cond.span()); self.error_type_mismatch(&PbsType::Bool, &cond_ty, arena.span(n.cond));
} }
let then_ty = self.check_node(&n.then_block); let then_ty = self.check_node(arena, n.then_block);
if let Some(else_block) = &n.else_block { if let Some(else_block) = n.else_block {
let else_ty = self.check_node(else_block); let else_ty = self.check_node(arena, else_block);
if then_ty != else_ty { if then_ty != else_ty {
self.error_type_mismatch(&then_ty, &else_ty, n.span); self.error_type_mismatch(&then_ty, &else_ty, arena.span(node));
} }
then_ty then_ty
} else { } else {
@ -660,20 +688,20 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn check_when_expr(&mut self, n: &WhenExprNode) -> PbsType { fn check_when_expr(&mut self, arena: &AstArena, _node: NodeId, n: &WhenExprNodeArena) -> PbsType {
let mut first_ty = None; let mut first_ty = None;
for arm in &n.arms { for arm in &n.arms {
if let Node::WhenArm(arm_node) = arm { if let NodeKind::WhenArm(arm_node) = arena.kind(*arm) {
let cond_ty = self.check_node(&arm_node.cond); let cond_ty = self.check_node(arena, arm_node.cond);
if cond_ty != PbsType::Bool { if cond_ty != PbsType::Bool {
self.error_type_mismatch(&PbsType::Bool, &cond_ty, arm_node.cond.span()); self.error_type_mismatch(&PbsType::Bool, &cond_ty, arena.span(arm_node.cond));
} }
let body_ty = self.check_node(&arm_node.body); let body_ty = self.check_node(arena, arm_node.body);
if first_ty.is_none() { if first_ty.is_none() {
first_ty = Some(body_ty); first_ty = Some(body_ty);
} else if let Some(fty) = &first_ty { } else if let Some(fty) = &first_ty {
if *fty != body_ty { if *fty != body_ty {
self.error_type_mismatch(fty, &body_ty, arm_node.body.span()); self.error_type_mismatch(fty, &body_ty, arena.span(arm_node.body));
} }
} }
} }
@ -681,9 +709,11 @@ impl<'a> TypeChecker<'a> {
first_ty.unwrap_or(PbsType::Void) first_ty.unwrap_or(PbsType::Void)
} }
fn check_type_decl(&mut self, n: &TypeDeclNode) { fn check_type_decl(&mut self, arena: &AstArena, _id: NodeId, n: &TypeDeclNodeArena) {
for constructor in &n.constructors { for constructor in &n.constructors {
self.check_constructor_decl(constructor); if let NodeKind::ConstructorDecl(ctor) = arena.kind(*constructor) {
self.check_constructor_decl(arena, *constructor, ctor);
}
} }
let type_name = self.interner.resolve(n.name).to_string(); let type_name = self.interner.resolve(n.name).to_string();
@ -697,37 +727,47 @@ impl<'a> TypeChecker<'a> {
let mut constants_map = HashMap::new(); let mut constants_map = HashMap::new();
self.scopes.push(constants_scope); self.scopes.push(constants_scope);
for constant in &n.constants { for constant_id in &n.constants {
let val_ty = self.check_node(&constant.value); if let NodeKind::ConstantDecl(constant) = arena.kind(*constant_id) {
if !self.is_assignable(&struct_ty, &val_ty) { let val_ty = self.check_node(arena, constant.value);
self.error_type_mismatch(&struct_ty, &val_ty, constant.span); if !self.is_assignable(&struct_ty, &val_ty) {
self.error_type_mismatch(&struct_ty, &val_ty, arena.span(*constant_id));
}
constants_map.insert(
self.interner.resolve(constant.name).to_string(),
struct_ty.clone(),
);
} }
constants_map.insert(self.interner.resolve(constant.name).to_string(), struct_ty.clone());
} }
self.scopes.pop(); self.scopes.pop();
self.struct_constants.insert(type_name, constants_map); self.struct_constants.insert(type_name, constants_map);
if let Some(body) = &n.body { if let Some(body) = n.body {
self.check_node(body); self.check_node(arena, body);
} }
} }
fn check_constructor_decl(&mut self, n: &ConstructorDeclNode) { fn check_constructor_decl(
&mut self,
arena: &AstArena,
_id: NodeId,
n: &ConstructorDeclNodeArena,
) {
self.enter_scope(); self.enter_scope();
for param in &n.params { for param in &n.params {
let ty = self.resolve_type_node(&param.ty); let ty = self.resolve_type_node(arena, param.ty);
self.define_local(self.interner.resolve(param.name), ty, false); self.define_local(self.interner.resolve(param.name), ty, false);
} }
for init in &n.initializers { for init in &n.initializers {
self.check_node(init); self.check_node(arena, *init);
} }
self.check_node(&n.body); self.check_node(arena, n.body);
self.exit_scope(); self.exit_scope();
} }
fn resolve_type_node(&mut self, node: &Node) -> PbsType { fn resolve_type_node(&mut self, arena: &AstArena, node: NodeId) -> PbsType {
match node { match arena.kind(node) {
Node::TypeName(tn) => { NodeKind::TypeName(tn) => {
let name_str = self.interner.resolve(tn.name); let name_str = self.interner.resolve(tn.name);
match name_str { match name_str {
"int" => PbsType::Int, "int" => PbsType::Int,
@ -752,35 +792,33 @@ impl<'a> TypeChecker<'a> {
level: DiagnosticLevel::Error, level: DiagnosticLevel::Error,
code: Some("E_TYPE_UNKNOWN_TYPE".to_string()), code: Some("E_TYPE_UNKNOWN_TYPE".to_string()),
message: format!("Unknown type: {}", name_str), message: format!("Unknown type: {}", name_str),
span: Some(tn.span), span: Some(arena.span(node)),
}); });
PbsType::Void PbsType::Void
} }
} }
} }
} }
Node::TypeApp(ta) => { NodeKind::TypeApp(ta) => match self.interner.resolve(ta.base) {
match self.interner.resolve(ta.base) { "optional" => {
"optional" => { if ta.args.len() == 1 {
if ta.args.len() == 1 { PbsType::Optional(Box::new(self.resolve_type_node(arena, ta.args[0])))
PbsType::Optional(Box::new(self.resolve_type_node(&ta.args[0]))) } else {
} else { PbsType::Void
PbsType::Void
}
} }
"result" => {
if ta.args.len() == 2 {
PbsType::Result(
Box::new(self.resolve_type_node(&ta.args[0])),
Box::new(self.resolve_type_node(&ta.args[1])),
)
} else {
PbsType::Void
}
}
_ => PbsType::Void,
} }
} "result" => {
if ta.args.len() == 2 {
PbsType::Result(
Box::new(self.resolve_type_node(arena, ta.args[0])),
Box::new(self.resolve_type_node(arena, ta.args[1])),
)
} else {
PbsType::Void
}
}
_ => PbsType::Void,
},
_ => PbsType::Void, _ => PbsType::Void,
} }
} }
@ -826,23 +864,26 @@ impl<'a> TypeChecker<'a> {
} }
} }
fn all_paths_return(&self, node: &Node) -> bool { fn all_paths_return(&self, arena: &AstArena, node: NodeId) -> bool {
match node { match arena.kind(node) {
Node::ReturnStmt(_) => true, NodeKind::ReturnStmt(_) => true,
Node::Block(n) => { NodeKind::Block(n) => {
for stmt in &n.stmts { for stmt in &n.stmts {
if self.all_paths_return(stmt) { if self.all_paths_return(arena, *stmt) {
return true; return true;
} }
} }
if let Some(tail) = &n.tail { if let Some(tail) = n.tail {
return self.all_paths_return(tail); return self.all_paths_return(arena, tail);
} }
false false
} }
Node::IfExpr(n) => { NodeKind::IfExpr(n) => {
let then_returns = self.all_paths_return(&n.then_block); let then_returns = self.all_paths_return(arena, n.then_block);
let else_returns = n.else_block.as_ref().map(|b| self.all_paths_return(b)).unwrap_or(false); let else_returns = n
.else_block
.map(|b| self.all_paths_return(arena, b))
.unwrap_or(false);
then_returns && else_returns then_returns && else_returns
} }
// For simplicity, we don't assume When returns unless all arms do // For simplicity, we don't assume When returns unless all arms do

View File

@ -132,10 +132,11 @@ pub fn build_exports(module_dir: &Path, file_manager: &mut FileManager) -> Resul
let file_id = file_manager.add(file_path.clone(), source.clone()); let file_id = file_manager.add(file_path.clone(), source.clone());
let mut parser = Parser::new(&source, file_id, &mut interner); let mut parser = Parser::new(&source, file_id, &mut interner);
let ast = parser.parse_file()?; let parsed = parser.parse_file()?;
let mut collector = SymbolCollector::new(&interner); let mut collector = SymbolCollector::new(&interner);
let (type_symbols, value_symbols) = collector.collect(&ast)?; let (type_symbols, value_symbols) =
collector.collect(&parsed.arena, parsed.root)?;
// Merge only public symbols // Merge only public symbols
for symbol in type_symbols.symbols.into_values() { for symbol in type_symbols.symbols.into_values() {

View File

@ -1,7 +1,6 @@
use prometeu_bytecode::disasm::disasm; use prometeu_bytecode::disasm::disasm;
use prometeu_bytecode::BytecodeLoader; use prometeu_bytecode::BytecodeLoader;
use prometeu_compiler::compiler::compile; use prometeu_compiler::compiler::compile;
use prometeu_compiler::frontends::pbs::ast::Node;
use prometeu_compiler::frontends::pbs::parser::Parser; use prometeu_compiler::frontends::pbs::parser::Parser;
use prometeu_analysis::NameInterner; use prometeu_analysis::NameInterner;
use std::fs; use std::fs;
@ -59,9 +58,8 @@ fn generate_canonical_goldens() {
let source = fs::read_to_string(project_dir.join("src/main/modules/main.pbs")).unwrap(); let source = fs::read_to_string(project_dir.join("src/main/modules/main.pbs")).unwrap();
let mut interner = NameInterner::new(); let mut interner = NameInterner::new();
let mut parser = Parser::new(&source, 0, &mut interner); let mut parser = Parser::new(&source, 0, &mut interner);
let ast = parser.parse_file().expect("Failed to parse AST"); let parsed = parser.parse_file().expect("Failed to parse AST");
let ast_node = Node::File(ast); let ast_json = serde_json::to_string_pretty(parsed.arena.kind(parsed.root)).unwrap();
let ast_json = serde_json::to_string_pretty(&ast_node).unwrap();
fs::write(golden_dir.join("ast.json"), ast_json).unwrap(); fs::write(golden_dir.join("ast.json"), ast_json).unwrap();
println!("Golden artifacts generated in test-cartridges/canonical/golden/"); println!("Golden artifacts generated in test-cartridges/canonical/golden/");

File diff suppressed because it is too large Load Diff