This commit is contained in:
bQUARKz 2026-02-05 14:56:03 +00:00
parent adb4dad14b
commit 07f986df5b
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
23 changed files with 286 additions and 237 deletions

View File

@ -6,3 +6,20 @@ pub struct Span {
pub start: u32, // byte offset
pub end: u32, // byte offset, exclusive
}
impl Span {
#[inline]
pub fn new(file: FileId, start: u32, end: u32) -> Self {
Self { file, start, end }
}
#[inline]
pub fn len(&self) -> u32 {
self.end.saturating_sub(self.start)
}
#[inline]
pub fn contains(&self, byte: u32) -> bool {
self.start <= byte && byte < self.end
}
}

View File

@ -0,0 +1,14 @@
use prometeu_analysis::{ids::FileId, span::Span};
#[test]
fn span_end_is_exclusive() {
let file = FileId(1);
let s = Span::new(file, 2, 5);
// len = end - start
assert_eq!(s.len(), 3);
// contains is [start, end)
assert!(s.contains(2));
assert!(s.contains(3));
assert!(s.contains(4));
assert!(!s.contains(5));
}

View File

@ -1,5 +1,5 @@
use crate::common::diagnostics::{Diagnostic, Severity};
use crate::common::spans::Span;
use crate::common::spans::{Span, FileId};
use crate::frontends::pbs::ast::AstArena;
use prometeu_analysis::NodeId;
use prometeu_analysis::{NameId, SymbolId, ModuleId};
@ -91,7 +91,7 @@ impl DefIndex {
code: "E_RESOLVE_DUPLICATE_SYMBOL".to_string(),
message: "Duplicate symbol in the same module and namespace".to_string(),
// Placeholder span; callers should overwrite with accurate span when known.
span: Span::new(0, 0, 0),
span: Span::new(FileId(0), 0, 0),
related: Vec::new(),
});
}
@ -177,7 +177,7 @@ mod tests {
kind: SymbolKind::Function,
exported: false,
module,
decl_span: Span::new(0, 1, 2),
decl_span: Span::new(FileId(0), 1, 2),
}
}
@ -242,16 +242,16 @@ mod tests {
#[test]
fn ref_index_records_refs_per_symbol() {
let mut index = RefIndex::new();
let span_a1 = Span::new(0, 1, 2);
let span_a2 = Span::new(0, 3, 4);
let span_b1 = Span::new(1, 10, 12);
let span_a1 = Span::new(FileId(0), 1, 2);
let span_a2 = Span::new(FileId(0), 3, 4);
let span_b1 = Span::new(FileId(1), 10, 12);
index.record_ref(SymbolId(2), span_a1);
index.record_ref(SymbolId(2), span_a2);
index.record_ref(SymbolId(5), span_b1);
index.record_ref(SymbolId(2), span_a1.clone());
index.record_ref(SymbolId(2), span_a2.clone());
index.record_ref(SymbolId(5), span_b1.clone());
assert_eq!(index.refs_of(SymbolId(2)), &[span_a1, span_a2]);
assert_eq!(index.refs_of(SymbolId(5)), &[span_b1]);
assert_eq!(index.refs_of(SymbolId(2)), &[span_a1.clone(), span_a2.clone()]);
assert_eq!(index.refs_of(SymbolId(5)), &[span_b1.clone()]);
assert!(index.refs_of(SymbolId(9)).is_empty());
}

View File

@ -1,5 +1,6 @@
use crate::analysis::symbols::{SymbolArena};
use prometeu_analysis::{NameId, NameInterner, TypeId, SymbolId, NodeId, ModuleId};
use crate::common::spans::FileId;
use serde::{Deserialize, Serialize};
// Use canonical TypeId from prometeu-analysis
@ -211,7 +212,7 @@ mod tests {
kind: SymbolKind::Struct,
exported: false,
module: ModuleId(0),
decl_span: Span::new(0, 0, 0),
decl_span: Span::new(FileId(0), 0, 0),
});
let struct_t = arena.intern_type(TypeKind::Struct { sym: sym_id });

View File

@ -95,7 +95,7 @@ pub fn emit_fragments(module: &ir_vm::Module) -> Result<EmitFragments> {
if let Some(instr) = instr_opt {
if let Some(span) = &instr.span {
pc_to_span.push((current_pc, SourceSpan {
file_id: span.file_id as u32,
file_id: span.file.as_u32(),
start: span.start,
end: span.end,
}));

View File

@ -2,7 +2,7 @@ use crate::backend::emit_fragments;
use crate::building::plan::{BuildStep, BuildTarget};
use crate::common::diagnostics::DiagnosticBundle;
use crate::common::files::FileManager;
use crate::common::spans::Span;
use crate::common::spans::{FileId, Span};
use crate::deps::resolver::ProjectId;
use crate::frontends::pbs::ast::ParsedAst;
use crate::frontends::pbs::collector::SymbolCollector;
@ -123,7 +123,7 @@ pub fn compile_project(
let source_code = std::fs::read_to_string(&source_abs)?;
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, FileId(file_id as u32), &mut interner);
let parsed = parser.parse_file()?;
let mut collector = SymbolCollector::new(&interner);
@ -155,7 +155,7 @@ pub fn compile_project(
interner.resolve(existing.name),
module_path
),
existing.span,
existing.span.clone(),
).into());
}
let _ = ms.type_symbols.insert(sym);
@ -169,7 +169,7 @@ pub fn compile_project(
interner.resolve(existing.name),
module_path
),
existing.span,
existing.span.clone(),
).into());
}
let _ = ms.value_symbols.insert(sym);
@ -209,7 +209,7 @@ pub fn compile_project(
visibility: Visibility::Pub,
ty: meta.ty.clone(),
is_host: meta.is_host,
span: Span::new(0, 0, 0),
span: Span::new(FileId::INVALID, 0, 0),
origin: Some(synthetic_module_path.clone()),
};

View File

@ -1,5 +1,5 @@
use crate::common::files::FileManager;
use crate::common::spans::Span;
use crate::common::spans::{FileId, Span};
use serde::{Serialize, Serializer};
#[derive(Debug, Clone, PartialEq)]
@ -84,21 +84,26 @@ impl DiagnosticBundle {
let mut diags = self.diagnostics.clone();
diags.sort_by(|a, b| {
(a.span.file_id, a.span.start, a.span.end, &a.code)
.cmp(&(b.span.file_id, b.span.start, b.span.end, &b.code))
(
a.span.file.as_usize(),
a.span.start,
a.span.end,
&a.code,
)
.cmp(&(b.span.file.as_usize(), b.span.start, b.span.end, &b.code))
});
let canonical_diags: Vec<CanonicalDiag> = diags
.iter()
.map(|d| {
let s = d.span;
let file = if s.file_id == usize::MAX {
let s = &d.span;
let file = if s.file == FileId::INVALID {
"<virtual>".to_string()
} else {
file_manager
.get_path(s.file_id)
.get_path(s.file.as_usize())
.and_then(|p| p.file_name().map(|n| n.to_string_lossy().to_string()))
.unwrap_or_else(|| format!("file_{}", s.file_id))
.unwrap_or_else(|| format!("file_{}", s.file.as_usize()))
};
let canonical_span = CanonicalSpan {
file,
@ -110,13 +115,13 @@ impl DiagnosticBundle {
.related
.iter()
.map(|(msg, sp)| {
let file = if sp.file_id == usize::MAX {
let file = if sp.file == FileId::INVALID {
"<virtual>".to_string()
} else {
file_manager
.get_path(sp.file_id)
.get_path(sp.file.as_usize())
.and_then(|p| p.file_name().map(|n| n.to_string_lossy().to_string()))
.unwrap_or_else(|| format!("file_{}", sp.file_id))
.unwrap_or_else(|| format!("file_{}", sp.file.as_usize()))
};
let rsp = CanonicalSpan {
file,

View File

@ -1,18 +1,3 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Span {
pub file_id: usize,
pub start: u32,
pub end: u32,
}
impl Span {
pub fn new(file_id: usize, start: u32, end: u32) -> Self {
Self {
file_id,
start,
end,
}
}
}
// Canonical Span for the whole workspace
pub use prometeu_analysis::span::Span;
pub use prometeu_analysis::ids::FileId;

View File

@ -170,14 +170,14 @@ fn convert_symbol(
// Actually, we'll just mark it exported=false if it's a function.
}
let span = sym.span;
let file_path = file_manager.get_path(span.file_id)
let span = sym.span.clone();
let file_path = file_manager.get_path(span.file.as_usize())
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| format!("unknown_file_{}", span.file_id));
.unwrap_or_else(|| format!("unknown_file_{}", span.file.as_usize()));
// Convert 1-based to 0-based
let (s_line, s_col) = file_manager.lookup_pos(span.file_id, span.start);
let (e_line, e_col) = file_manager.lookup_pos(span.file_id, span.end);
let (s_line, s_col) = file_manager.lookup_pos(span.file.as_usize(), span.start);
let (e_line, e_col) = file_manager.lookup_pos(span.file.as_usize(), span.end);
let decl_span = SpanRange {
file_uri: file_path,

View File

@ -6,7 +6,7 @@
use crate::backend;
use crate::common::config::ProjectConfig;
use crate::common::files::FileManager;
use crate::common::spans::Span;
use crate::common::spans::{FileId, Span};
use crate::common::symbols::{DebugSymbol, ProjectSymbols, RawSymbol, SymbolsFile};
use anyhow::Result;
use prometeu_bytecode::BytecodeModule;
@ -44,11 +44,11 @@ impl CompilationUnit {
pub fn export(&self, out: &Path, emit_disasm: bool, emit_symbols: bool) -> Result<()> {
let mut debug_symbols = Vec::new();
for raw in &self.raw_symbols {
let path = self.file_manager.get_path(raw.span.file_id)
let path = self.file_manager.get_path(raw.span.file.as_usize())
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| format!("file_{}", raw.span.file_id));
.unwrap_or_else(|| format!("file_{}", raw.span.file.as_usize()));
let (line, col) = self.file_manager.lookup_pos(raw.span.file_id, raw.span.start);
let (line, col) = self.file_manager.lookup_pos(raw.span.file.as_usize(), raw.span.start);
debug_symbols.push(DebugSymbol {
pc: raw.pc,
@ -116,11 +116,7 @@ pub fn compile_ext(project_dir: &Path, explain_deps: bool) -> Result<Compilation
for (pc, span) in &debug.pc_to_span {
raw_symbols.push(RawSymbol {
pc: *pc,
span: Span {
file_id: span.file_id as usize,
start: span.start,
end: span.end,
},
span: Span::new(FileId(span.file_id), span.start, span.end),
});
}
}

View File

@ -30,7 +30,7 @@ impl AstArena {
}
pub fn span(&self, id: NodeId) -> Span {
self.spans[id.0 as usize]
self.spans[id.0 as usize].clone()
}
}

View File

@ -66,7 +66,7 @@ impl<'a> SymbolCollector<'a> {
};
let span = arena.span(id);
self.check_export_eligibility(SymbolKind::Function, vis, span);
self.check_export_eligibility(SymbolKind::Function, vis, &span);
let symbol = Symbol {
name: decl.name,
@ -75,7 +75,7 @@ impl<'a> SymbolCollector<'a> {
visibility: vis,
ty: None, // Will be resolved later
is_host: false,
span,
span: span.clone(),
origin: None,
};
self.insert_value_symbol(symbol);
@ -89,7 +89,7 @@ impl<'a> SymbolCollector<'a> {
let span = arena.span(id);
self.check_export_eligibility(SymbolKind::Service, vis, span);
self.check_export_eligibility(SymbolKind::Service, vis, &span);
let symbol = Symbol {
name: decl.name,
@ -98,7 +98,7 @@ impl<'a> SymbolCollector<'a> {
visibility: vis,
ty: None,
is_host: false,
span,
span: span.clone(),
origin: None,
};
self.insert_type_symbol(symbol);
@ -119,7 +119,7 @@ impl<'a> SymbolCollector<'a> {
let span = arena.span(id);
self.check_export_eligibility(kind.clone(), vis, span);
self.check_export_eligibility(kind.clone(), vis, &span);
let symbol = Symbol {
name: decl.name,
@ -128,7 +128,7 @@ impl<'a> SymbolCollector<'a> {
visibility: vis,
ty: None,
is_host: decl.is_host,
span,
span: span.clone(),
origin: None,
};
self.insert_type_symbol(symbol);
@ -171,9 +171,9 @@ impl<'a> SymbolCollector<'a> {
message: format!(
"Duplicate symbol '{}' already defined at {:?}",
self.interner.resolve(symbol.name),
existing.span
&existing.span
),
span: symbol.span,
span: symbol.span.clone(),
related: Vec::new(),
});
}
@ -186,20 +186,20 @@ impl<'a> SymbolCollector<'a> {
"DebugSymbol '{}' collides with another symbol in the {:?} namespace defined at {:?}",
self.interner.resolve(symbol.name),
existing.namespace,
existing.span
&existing.span
),
span: symbol.span,
span: symbol.span.clone(),
related: Vec::new(),
});
}
fn check_export_eligibility(&mut self, kind: SymbolKind, vis: Visibility, span: crate::common::spans::Span) {
fn check_export_eligibility(&mut self, kind: SymbolKind, vis: Visibility, span: &crate::common::spans::Span) {
if let Err(msg) = ExportSurfaceKind::validate_visibility(kind, vis) {
self.diagnostics.push(Diagnostic {
severity: Severity::Error,
code: "E_SEMANTIC_EXPORT_RESTRICTION".to_string(),
message: msg,
span,
span: span.clone(),
related: Vec::new(),
});
}

View File

@ -1,16 +1,16 @@
use super::token::{Token, TokenKind};
use crate::common::spans::Span;
use crate::common::spans::{FileId, Span};
use std::iter::Peekable;
use std::str::Chars;
pub struct Lexer<'a> {
chars: Peekable<Chars<'a>>,
file_id: usize,
file_id: FileId,
pos: u32,
}
impl<'a> Lexer<'a> {
pub fn new(source: &'a str, file_id: usize) -> Self {
pub fn new(source: &'a str, file_id: FileId) -> Self {
Self {
chars: source.chars().peekable(),
file_id,
@ -289,7 +289,7 @@ mod tests {
#[test]
fn test_lex_basic_tokens() {
let source = "( ) { } [ ] , . : ; -> = == + - * / % ! != < > <= >= && ||";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
let expected = vec![
TokenKind::OpenParen, TokenKind::CloseParen,
@ -313,7 +313,7 @@ mod tests {
#[test]
fn test_lex_keywords() {
let source = "import pub mod service fn let mut declare struct contract host error optional result some none ok err if else when for in return handle borrow mutate peek take alloc weak as";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
let expected = vec![
TokenKind::Import, TokenKind::Pub, TokenKind::Mod, TokenKind::Service,
@ -336,7 +336,7 @@ mod tests {
#[test]
fn test_lex_identifiers() {
let source = "foo bar _baz qux123";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
let expected = vec![
TokenKind::Identifier("foo".to_string()),
@ -355,7 +355,7 @@ mod tests {
#[test]
fn test_lex_literals() {
let source = "123 3.14 255b \"hello world\"";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
let expected = vec![
TokenKind::IntLit(123),
@ -374,7 +374,7 @@ mod tests {
#[test]
fn test_lex_comments() {
let source = "let x = 10; // this is a comment\nlet y = 20;";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
let expected = vec![
TokenKind::Let,
@ -399,7 +399,7 @@ mod tests {
#[test]
fn test_lex_spans() {
let source = "let x = 10;";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
let t1 = lexer.next_token(); // let
assert_eq!(t1.span.start, 0);
@ -425,7 +425,7 @@ mod tests {
#[test]
fn test_lex_invalid_tokens() {
let source = "@ #";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
assert!(matches!(lexer.next_token().kind, TokenKind::Invalid(_)));
assert!(matches!(lexer.next_token().kind, TokenKind::Invalid(_)));
@ -435,7 +435,7 @@ mod tests {
#[test]
fn test_lex_unterminated_string() {
let source = "\"hello";
let mut lexer = Lexer::new(source, 0);
let mut lexer = Lexer::new(source, FileId(0));
assert!(matches!(lexer.next_token().kind, TokenKind::Invalid(_)));
}

View File

@ -297,7 +297,7 @@ impl<'a> Lowerer<'a> {
}
fn lower_node(&mut self, node: NodeId) -> Result<(), ()> {
let old_span = self.current_span;
let old_span = self.current_span.clone();
self.current_span = Some(self.arena.span(node));
let res = match self.arena.kind(node) {
@ -1243,7 +1243,7 @@ impl<'a> Lowerer<'a> {
fn emit(&mut self, kind: InstrKind) {
if let Some(block) = &mut self.current_block {
block.instrs.push(Instr::new(kind, self.current_span));
block.instrs.push(Instr::new(kind, self.current_span.clone()));
}
}
@ -1346,10 +1346,11 @@ mod tests {
use crate::frontends::pbs::symbols::ModuleSymbols;
use crate::ir_core;
use prometeu_analysis::NameInterner;
use crate::common::spans::FileId;
fn lower_program(code: &str) -> ir_core::Program {
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1461,7 +1462,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1695,7 +1696,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1727,7 +1728,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1772,7 +1773,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1810,7 +1811,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1841,7 +1842,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1869,7 +1870,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1896,7 +1897,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1923,7 +1924,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1959,7 +1960,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -1995,7 +1996,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -2031,7 +2032,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);
@ -2058,7 +2059,7 @@ mod tests {
}
";
let mut interner = NameInterner::new();
let mut parser = Parser::new(code, 0, &mut interner);
let mut parser = Parser::new(code, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse");
let mut collector = SymbolCollector::new(&interner);

View File

@ -25,6 +25,7 @@ use crate::frontends::Frontend;
use crate::ir_vm;
use crate::lowering::core_to_vm;
use prometeu_analysis::NameInterner;
use crate::common::spans::FileId;
use std::path::Path;
pub struct PbsFrontend;
@ -43,13 +44,13 @@ impl Frontend for PbsFrontend {
crate::common::diagnostics::DiagnosticBundle::error(
"E_FRONTEND_IO",
format!("Failed to read file: {}", e),
crate::common::spans::Span::new(usize::MAX, 0, 0),
crate::common::spans::Span::new(FileId::INVALID, 0, 0),
)
})?;
let file_id = file_manager.add(entry.to_path_buf(), source.clone());
let mut interner = NameInterner::new();
let mut parser = parser::Parser::new(&source, file_id, &mut interner);
let mut parser = parser::Parser::new(&source, FileId(file_id as u32), &mut interner);
let parsed = parser.parse_file()?;
let mut collector = SymbolCollector::new(&interner);
@ -88,7 +89,7 @@ impl Frontend for PbsFrontend {
crate::common::diagnostics::DiagnosticBundle::error(
"E_CORE_INVARIANT",
format!("Core IR Invariant Violation: {}", e),
crate::common::spans::Span::new(usize::MAX, 0, 0),
crate::common::spans::Span::new(FileId::INVALID, 0, 0),
)
})?;
@ -97,7 +98,7 @@ impl Frontend for PbsFrontend {
crate::common::diagnostics::DiagnosticBundle::error(
"E_LOWERING",
format!("Lowering error: {}", e),
crate::common::spans::Span::new(usize::MAX, 0, 0),
crate::common::spans::Span::new(FileId::INVALID, 0, 0),
)
})
}

View File

@ -1,5 +1,5 @@
use crate::common::diagnostics::{Diagnostic, DiagnosticBundle, Severity};
use crate::common::spans::Span;
use crate::common::spans::{FileId, Span};
use crate::frontends::pbs::ast::*;
use crate::frontends::pbs::lexer::Lexer;
use crate::frontends::pbs::token::{Token, TokenKind};
@ -8,7 +8,7 @@ use prometeu_analysis::{NameId, NameInterner, NodeId};
pub struct Parser<'a> {
tokens: Vec<Token>,
pos: usize,
file_id: usize,
file_id: FileId,
errors: Vec<Diagnostic>,
interner: &'a mut NameInterner,
arena: AstArena,
@ -26,7 +26,7 @@ pub struct Parser<'a> {
}
impl<'a> Parser<'a> {
pub fn new(source: &str, file_id: usize, interner: &'a mut NameInterner) -> Self {
pub fn new(source: &str, file_id: FileId, interner: &'a mut NameInterner) -> Self {
let mut lexer = Lexer::new(source, file_id);
let mut tokens = Vec::new();
loop {
@ -72,7 +72,7 @@ impl<'a> Parser<'a> {
}
pub fn parse_file(&mut self) -> Result<ParsedAst, DiagnosticBundle> {
let start_span = self.peek().span;
let start_span = self.peek().span.clone();
let mut imports = Vec::new();
let mut decls = Vec::new();
@ -90,7 +90,7 @@ impl<'a> Parser<'a> {
}
}
let end_span = self.peek().span;
let end_span = self.peek().span.clone();
if !self.errors.is_empty() {
return Err(DiagnosticBundle {
@ -152,7 +152,7 @@ impl<'a> Parser<'a> {
fn parse_import_spec(&mut self) -> Result<NodeId, DiagnosticBundle> {
let mut path = Vec::new();
let start_span = self.peek().span;
let start_span = self.peek().span.clone();
if self.peek().kind == TokenKind::OpenBrace {
self.advance(); // {
@ -190,7 +190,7 @@ impl<'a> Parser<'a> {
}
}
let end_span = self.tokens[self.pos - 1].span;
let end_span = self.tokens[self.pos - 1].span.clone();
let span = Span::new(self.file_id, start_span.start, end_span.end);
Ok(self.arena.push(NodeKind::ImportSpec(ImportSpecNodeArena { path }), span))
}
@ -554,7 +554,7 @@ impl<'a> Parser<'a> {
if let NodeKind::TypeApp(ta) = &mut self.arena.nodes[index] {
if ta.base == self.builtin_array {
ta.args.push(size_node);
self.arena.spans[index] = span;
self.arena.spans[index] = span.clone();
wrapped = false;
}
}
@ -1043,7 +1043,7 @@ impl<'a> Parser<'a> {
severity: Severity::Error,
code: code.unwrap_or("E_PARSE_ERROR").to_string(),
message: message.to_string(),
span: self.peek().span,
span: self.peek().span.clone(),
related: Vec::new(),
};
self.errors.push(diag.clone());
@ -1054,7 +1054,7 @@ impl<'a> Parser<'a> {
self.consume(TokenKind::OpenBracket)?;
let mut constructors = Vec::new();
while self.peek().kind != TokenKind::CloseBracket && self.peek().kind != TokenKind::Eof {
let start_span = self.peek().span;
let start_span = self.peek().span.clone();
let params = self.parse_param_list()?;
self.consume(TokenKind::Colon)?;
@ -1097,11 +1097,12 @@ impl<'a> Parser<'a> {
mod tests {
use super::*;
use serde_json;
use crate::common::spans::FileId;
#[test]
fn test_parse_empty_file() {
let mut interner = NameInterner::new();
let mut parser = Parser::new("", 0, &mut interner);
let mut parser = Parser::new("", FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1118,7 +1119,7 @@ import std.io from "std";
import math from "./math.pbs";
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1147,7 +1148,7 @@ fn add(a: int, b: int): int {
}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1174,7 +1175,7 @@ pub declare struct Point {
}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1200,7 +1201,7 @@ pub service Audio {
}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1226,7 +1227,7 @@ fn main() {
}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1252,7 +1253,7 @@ fn main(x: int) {
}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1272,7 +1273,7 @@ fn bad() {
fn good() {}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let result = parser.parse_file();
assert!(result.is_err());
}
@ -1281,7 +1282,7 @@ fn good() {}
fn test_parse_mod_fn() {
let source = "mod fn test() {}";
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("mod fn should be allowed");
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1298,7 +1299,7 @@ fn good() {}
fn test_parse_pub_fn() {
let source = "pub fn test() {}";
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("pub fn should be allowed in parser");
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,
@ -1319,7 +1320,7 @@ fn main() {
}
"#;
let mut interner = NameInterner::new();
let mut parser = Parser::new(source, 0, &mut interner);
let mut parser = Parser::new(source, FileId(0), &mut interner);
let parsed = parser.parse_file().unwrap();
let file = match parsed.arena.kind(parsed.root) {
NodeKind::File(file) => file,

View File

@ -48,7 +48,7 @@ pub fn build_def_index(
kind,
exported,
module,
decl_span: span,
decl_span: span.clone(),
};
let symbol_id = symbols.insert(symbol);
@ -125,7 +125,7 @@ fn walk_node(
};
if let Some(symbol_id) = index.get(key) {
ref_index.record_ref(symbol_id, span);
ref_index.record_ref(symbol_id, span.clone());
node_to_symbol.bind_node(node_id, symbol_id);
} else if let Some((import_arena, import_index)) = imports {
if let Some((_, symbol_id)) = import_index.get_by_name_any_module(ident.name, Namespace::Value) {
@ -135,18 +135,18 @@ fn walk_node(
severity: Severity::Error,
code: "E_RESOLVE_VISIBILITY".to_string(),
message: format!("Symbol is not exported from module {:?}", symbol.module),
span,
span: span.clone(),
related: Vec::new(),
});
}
ref_index.record_ref(symbol_id, span);
ref_index.record_ref(symbol_id, span.clone());
node_to_symbol.bind_node(node_id, symbol_id);
} else {
diagnostics.push(Diagnostic {
severity: Severity::Error,
code: "E_RESOLVE_UNDEFINED_IDENTIFIER".to_string(),
message: "Undefined identifier".to_string(),
span,
span: span.clone(),
related: Vec::new(),
});
}
@ -155,7 +155,7 @@ fn walk_node(
severity: Severity::Error,
code: "E_RESOLVE_UNDEFINED_IDENTIFIER".to_string(),
message: "Undefined identifier".to_string(),
span,
span: span.clone(),
related: Vec::new(),
});
}
@ -239,7 +239,7 @@ mod tests {
AstArena, BlockNodeArena, CallNodeArena, ExprStmtNodeArena, FileNodeArena, FnDeclNodeArena,
IdentNodeArena, TypeDeclNodeArena,
};
use crate::common::spans::Span;
use crate::common::spans::{Span, FileId};
#[test]
fn test_build_def_index_success() {
@ -247,7 +247,7 @@ mod tests {
let mut interner = NameInterner::new();
// Create a dummy body for the function to avoid panic/invalid access
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(0, 0, 0));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(FileId(0), 0, 0));
let fn_name = interner.intern("my_func");
let fn_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
@ -257,7 +257,7 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 10, 20));
}), Span::new(FileId(0), 10, 20));
let type_name = interner.intern("MyStruct");
let type_id = arena.push(NodeKind::TypeDecl(TypeDeclNodeArena {
@ -269,12 +269,12 @@ mod tests {
constructors: vec![],
constants: vec![],
body: None,
}), Span::new(0, 30, 40));
}), Span::new(FileId(0), 30, 40));
let file_id = arena.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![fn_id, type_id],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena.roots.push(file_id);
@ -303,7 +303,7 @@ mod tests {
let name = interner.intern("conflict");
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(0, 0, 0));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(FileId(0), 0, 0));
let fn1_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
@ -312,7 +312,7 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 10, 20));
}), Span::new(FileId(0), 10, 20));
let fn2_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
@ -321,12 +321,12 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 30, 40));
}), Span::new(FileId(0), 30, 40));
let file_id = arena.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![fn1_id, fn2_id],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena.roots.push(file_id);
@ -334,7 +334,7 @@ mod tests {
assert_eq!(diagnostics.len(), 1);
assert_eq!(diagnostics[0].code, "E_RESOLVE_DUPLICATE_SYMBOL");
assert_eq!(diagnostics[0].span, Span::new(0, 30, 40));
assert_eq!(diagnostics[0].span, Span::new(FileId(0), 30, 40));
}
#[test]
@ -343,7 +343,7 @@ mod tests {
let mut interner = NameInterner::new();
let name = interner.intern("bound_func");
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(0, 0, 0));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(FileId(0), 0, 0));
let decl_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
name,
@ -351,12 +351,12 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 10, 20));
}), Span::new(FileId(0), 10, 20));
let file_id = arena.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![decl_id],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena.roots.push(file_id);
@ -373,9 +373,9 @@ mod tests {
let mut interner = NameInterner::new();
let ident_name = interner.intern("unknown");
let ident_id = arena.push(NodeKind::Ident(IdentNodeArena { name: ident_name }), Span::new(0, 50, 60));
let expr_stmt = arena.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: ident_id }), Span::new(0, 50, 60));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(0, 40, 70));
let ident_id = arena.push(NodeKind::Ident(IdentNodeArena { name: ident_name }), Span::new(FileId(0), 50, 60));
let expr_stmt = arena.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: ident_id }), Span::new(FileId(0), 50, 60));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(FileId(0), 40, 70));
let fn_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
@ -384,12 +384,12 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 10, 80));
}), Span::new(FileId(0), 10, 80));
let file_id = arena.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![fn_id],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena.roots.push(file_id);
@ -397,7 +397,7 @@ mod tests {
assert_eq!(diagnostics.len(), 1);
assert_eq!(diagnostics[0].code, "E_RESOLVE_UNDEFINED_IDENTIFIER");
assert_eq!(diagnostics[0].span, Span::new(0, 50, 60));
assert_eq!(diagnostics[0].span, Span::new(FileId(0), 50, 60));
}
#[test]
@ -407,7 +407,7 @@ mod tests {
// fn target() {}
let target_name = interner.intern("target");
let target_body = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(0, 5, 5));
let target_body = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(FileId(0), 5, 5));
let target_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
name: target_name,
@ -415,13 +415,13 @@ mod tests {
ret: None,
else_fallback: None,
body: target_body,
}), Span::new(0, 0, 10));
}), Span::new(FileId(0), 0, 10));
// fn caller() { target(); }
let ident_id = arena.push(NodeKind::Ident(IdentNodeArena { name: target_name }), Span::new(0, 50, 56));
let call_id = arena.push(NodeKind::Call(CallNodeArena { callee: ident_id, args: vec![] }), Span::new(0, 50, 58));
let expr_stmt = arena.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: call_id }), Span::new(0, 50, 58));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(0, 40, 70));
let ident_id = arena.push(NodeKind::Ident(IdentNodeArena { name: target_name }), Span::new(FileId(0), 50, 56));
let call_id = arena.push(NodeKind::Call(CallNodeArena { callee: ident_id, args: vec![] }), Span::new(FileId(0), 50, 58));
let expr_stmt = arena.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: call_id }), Span::new(FileId(0), 50, 58));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(FileId(0), 40, 70));
let caller_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
@ -430,12 +430,12 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 30, 80));
}), Span::new(FileId(0), 30, 80));
let file_id = arena.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![target_id, caller_id],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena.roots.push(file_id);
@ -446,7 +446,7 @@ mod tests {
let target_sym_id = index.get(DefKey { module: ModuleId(1), name: target_name, namespace: Namespace::Value }).expect("target should be in index");
let refs = ref_index.refs_of(target_sym_id);
assert_eq!(refs.len(), 1);
assert_eq!(refs[0], Span::new(0, 50, 56));
assert_eq!(refs[0], Span::new(FileId(0), 50, 56));
let bound_id = node_to_symbol.get(ident_id).expect("ident should be bound to symbol");
assert_eq!(bound_id, target_sym_id);
@ -459,7 +459,7 @@ mod tests {
// Módulo 1: define função privada
let mut arena1 = AstArena::default();
let target_name = interner.intern("private_func");
let body1 = arena1.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(0, 0, 0));
let body1 = arena1.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(FileId(0), 0, 0));
let decl1 = arena1.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None, // Privado
name: target_name,
@ -467,20 +467,20 @@ mod tests {
ret: None,
else_fallback: None,
body: body1,
}), Span::new(0, 0, 10));
}), Span::new(FileId(0), 0, 10));
let file1 = arena1.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![decl1],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena1.roots.push(file1);
let (symbols1, index1, _, _, _) = build_def_index(&arena1, ModuleId(1), &interner, None);
// Módulo 2: tenta usar função privada do Módulo 1
let mut arena2 = AstArena::default();
let ident_id = arena2.push(NodeKind::Ident(IdentNodeArena { name: target_name }), Span::new(0, 50, 62));
let expr_stmt = arena2.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: ident_id }), Span::new(0, 50, 62));
let body2 = arena2.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(0, 40, 70));
let ident_id = arena2.push(NodeKind::Ident(IdentNodeArena { name: target_name }), Span::new(FileId(0), 50, 62));
let expr_stmt = arena2.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: ident_id }), Span::new(FileId(0), 50, 62));
let body2 = arena2.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(FileId(0), 40, 70));
let caller = arena2.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: Some("pub".to_string()),
name: interner.intern("caller"),
@ -488,11 +488,11 @@ mod tests {
ret: None,
else_fallback: None,
body: body2,
}), Span::new(0, 30, 80));
}), Span::new(FileId(0), 30, 80));
let file2 = arena2.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![caller],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena2.roots.push(file2);
let (_symbols2, _index2, _ref_index2, _node_to_symbol2, diagnostics) =
@ -500,7 +500,7 @@ mod tests {
assert_eq!(diagnostics.len(), 1);
assert_eq!(diagnostics[0].code, "E_RESOLVE_VISIBILITY");
assert_eq!(diagnostics[0].span, Span::new(0, 50, 62));
assert_eq!(diagnostics[0].span, Span::new(FileId(0), 50, 62));
}
#[test]
@ -509,7 +509,7 @@ mod tests {
let mut interner = NameInterner::new();
let target_name = interner.intern("target");
let target_body = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(0, 5, 5));
let target_body = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![], tail: None }), Span::new(FileId(0), 5, 5));
let target_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: Some("pub".to_string()),
name: target_name,
@ -517,13 +517,13 @@ mod tests {
ret: None,
else_fallback: None,
body: target_body,
}), Span::new(0, 0, 10));
}), Span::new(FileId(0), 0, 10));
let caller_name = interner.intern("caller");
let ident_id = arena.push(NodeKind::Ident(IdentNodeArena { name: target_name }), Span::new(0, 50, 56));
let call_id = arena.push(NodeKind::Call(CallNodeArena { callee: ident_id, args: vec![] }), Span::new(0, 50, 58));
let expr_stmt = arena.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: call_id }), Span::new(0, 50, 58));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(0, 40, 70));
let ident_id = arena.push(NodeKind::Ident(IdentNodeArena { name: target_name }), Span::new(FileId(0), 50, 56));
let call_id = arena.push(NodeKind::Call(CallNodeArena { callee: ident_id, args: vec![] }), Span::new(FileId(0), 50, 58));
let expr_stmt = arena.push(NodeKind::ExprStmt(ExprStmtNodeArena { expr: call_id }), Span::new(FileId(0), 50, 58));
let body_id = arena.push(NodeKind::Block(BlockNodeArena { stmts: vec![expr_stmt], tail: None }), Span::new(FileId(0), 40, 70));
let caller_id = arena.push(NodeKind::FnDecl(FnDeclNodeArena {
vis: None,
@ -532,12 +532,12 @@ mod tests {
ret: None,
else_fallback: None,
body: body_id,
}), Span::new(0, 30, 80));
}), Span::new(FileId(0), 30, 80));
let file_id = arena.push(NodeKind::File(FileNodeArena {
imports: vec![],
decls: vec![target_id, caller_id],
}), Span::new(0, 0, 100));
}), Span::new(FileId(0), 0, 100));
arena.roots.push(file_id);

View File

@ -81,7 +81,7 @@ impl<'a> Resolver<'a> {
},
exported: sym.visibility == Visibility::Pub,
module: ModuleId(0),
decl_span: sym.span,
decl_span: sym.span.clone(),
});
}
for (name, sym) in &self.current_module.value_symbols.symbols {
@ -97,7 +97,7 @@ impl<'a> Resolver<'a> {
},
exported: sym.visibility == Visibility::Pub,
module: ModuleId(0),
decl_span: sym.span,
decl_span: sym.span.clone(),
});
}
@ -122,7 +122,7 @@ impl<'a> Resolver<'a> {
},
exported: sym.visibility == Visibility::Pub,
module: ModuleId(0), // Should be target module
decl_span: sym.span,
decl_span: sym.span.clone(),
});
}
for (name, sym) in &self.imported_symbols.value_symbols.symbols {
@ -138,7 +138,7 @@ impl<'a> Resolver<'a> {
},
exported: sym.visibility == Visibility::Pub,
module: ModuleId(0), // Should be target module
decl_span: sym.span,
decl_span: sym.span.clone(),
});
}
@ -438,7 +438,7 @@ impl<'a> Resolver<'a> {
self.enter_scope();
for param in &n.params {
let ty_id = self.resolve_type_ref(arena, param.ty);
let sym_id = self.define_local(param.name, param.span, SymbolKind::Local);
let sym_id = self.define_local(param.name, param.span.clone(), SymbolKind::Local);
if let (Some(tid), Some(sid)) = (ty_id, sym_id) {
self.type_facts.set_symbol_type(sid, tid);
// O node do Ident do parâmetro na declaração também pode ser vinculado
@ -512,7 +512,7 @@ impl<'a> Resolver<'a> {
self.enter_scope();
for param in &n.params {
self.resolve_type_ref(arena, param.ty);
self.define_local(param.name, param.span, SymbolKind::Local);
self.define_local(param.name, param.span.clone(), SymbolKind::Local);
}
for init in &n.initializers {
self.resolve_node(arena, *init);
@ -804,7 +804,7 @@ impl<'a> Resolver<'a> {
self.interner.resolve(name)
),
span,
related: vec![("type defined here".to_string(), existing.span)],
related: vec![("type defined here".to_string(), existing.span.clone())],
});
return None;
}
@ -815,7 +815,7 @@ impl<'a> Resolver<'a> {
code: "E_RESOLVE_DUPLICATE_SYMBOL".to_string(),
message: format!("Duplicate local variable '{}'", self.interner.resolve(name)),
span,
related: vec![("previous definition here".to_string(), prev_sym.span)],
related: vec![("previous definition here".to_string(), prev_sym.span.clone())],
});
None
} else {
@ -826,7 +826,7 @@ impl<'a> Resolver<'a> {
visibility: Visibility::FilePrivate,
ty: None, // Will be set by TypeChecker
is_host: false,
span,
span: span.clone(),
origin: None,
};
@ -884,7 +884,7 @@ impl<'a> Resolver<'a> {
self.interner.resolve(sym.name)
),
span,
related: vec![("symbol defined here".to_string(), sym.span)],
related: vec![("symbol defined here".to_string(), sym.span.clone())],
});
}
}
@ -900,7 +900,7 @@ 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 parser = parser::Parser::new(source, file_id, fm.interner_mut());
let mut parser = parser::Parser::new(source, crate::common::spans::FileId(file_id as u32), fm.interner_mut());
let parsed = parser.parse_file().expect("Parsing failed");
(parsed, file_id, fm.interner().clone())
}
@ -1018,7 +1018,7 @@ mod tests {
visibility: Visibility::FilePrivate,
ty: None,
is_host: false,
span: Span::new(1, 0, 0),
span: Span::new(crate::common::spans::FileId(1), 0, 0),
origin: None,
}).unwrap();
@ -1066,7 +1066,7 @@ mod tests {
visibility: Visibility::Pub,
ty: None,
is_host: false,
span: Span::new(1, 0, 0),
span: Span::new(crate::common::spans::FileId(1), 0, 0),
origin: None,
}).unwrap();

View File

@ -81,7 +81,7 @@ pub fn lower_function(
let mut stack_types = Vec::new();
for instr in &block.instrs {
let span = instr.span;
let span = instr.span.clone();
match &instr.kind {
ir_core::InstrKind::PushConst(id) => {
let ty = if let Some(val) = program.const_pool.get(ir_core::ConstId(id.0)) {
@ -94,11 +94,11 @@ pub fn lower_function(
ir_core::Type::Void
};
stack_types.push(ty);
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushConst(ir_vm::ConstId(id.0)), span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushConst(ir_vm::ConstId(id.0)), span.clone()));
}
ir_core::InstrKind::PushBounded(val) => {
stack_types.push(ir_core::Type::Bounded);
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushBounded(*val), span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::PushBounded(*val), span.clone()));
}
ir_core::InstrKind::Call(func_id, arg_count) => {
// Pop arguments from type stack
@ -135,13 +135,13 @@ pub fn lower_function(
for _ in 0..*slots {
stack_types.push(ir_core::Type::Int);
}
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Syscall(*id), span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Syscall(*id), span.clone()));
}
ir_core::InstrKind::GetLocal(slot) => {
let ty = local_types.get(slot).cloned().unwrap_or(ir_core::Type::Void);
stack_types.push(ty.clone());
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, span.clone()));
// If it's a gate, we should retain it if we just pushed it onto stack?
// "on assigning a gate to a local/global"
@ -150,7 +150,7 @@ pub fn lower_function(
// Wait, if I Load it, I have a new handle on the stack. I should Retain it.
if is_gate_type(&ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
}
}
ir_core::InstrKind::SetLocal(slot) => {
@ -160,8 +160,8 @@ pub fn lower_function(
// 1. Release old value if it was a gate
if let Some(old_ty) = old_ty {
if is_gate_type(&old_ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: *slot }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span.clone()));
}
}
@ -174,22 +174,22 @@ pub fn lower_function(
// Actually, if we Pop it later, we Release it.
local_types.insert(*slot, new_ty);
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalStore { slot: *slot }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalStore { slot: *slot }, span.clone()));
}
ir_core::InstrKind::Pop => {
let ty = stack_types.pop().unwrap_or(ir_core::Type::Void);
if is_gate_type(&ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span.clone()));
} else {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Pop, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Pop, span.clone()));
}
}
ir_core::InstrKind::Dup => {
let ty = stack_types.last().cloned().unwrap_or(ir_core::Type::Void);
stack_types.push(ty.clone());
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Dup, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Dup, span.clone()));
if is_gate_type(&ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
}
}
ir_core::InstrKind::Add | ir_core::InstrKind::Sub | ir_core::InstrKind::Mul | ir_core::InstrKind::Div => {
@ -203,10 +203,10 @@ pub fn lower_function(
ir_core::InstrKind::Div => ir_vm::InstrKind::Div,
_ => unreachable!(),
};
vm_func.body.push(ir_vm::Instruction::new(kind, span));
vm_func.body.push(ir_vm::Instruction::new(kind, span.clone()));
}
ir_core::InstrKind::Neg => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Neg, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Neg, span.clone()));
}
ir_core::InstrKind::Eq | ir_core::InstrKind::Neq | ir_core::InstrKind::Lt | ir_core::InstrKind::Lte | ir_core::InstrKind::Gt | ir_core::InstrKind::Gte => {
stack_types.pop();
@ -221,7 +221,7 @@ pub fn lower_function(
ir_core::InstrKind::Gte => ir_vm::InstrKind::Gte,
_ => unreachable!(),
};
vm_func.body.push(ir_vm::Instruction::new(kind, span));
vm_func.body.push(ir_vm::Instruction::new(kind, span.clone()));
}
ir_core::InstrKind::And | ir_core::InstrKind::Or => {
stack_types.pop();
@ -232,12 +232,12 @@ pub fn lower_function(
ir_core::InstrKind::Or => ir_vm::InstrKind::Or,
_ => unreachable!(),
};
vm_func.body.push(ir_vm::Instruction::new(kind, span));
vm_func.body.push(ir_vm::Instruction::new(kind, span.clone()));
}
ir_core::InstrKind::Not => {
stack_types.pop();
stack_types.push(ir_core::Type::Bool);
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Not, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::Not, span.clone()));
}
ir_core::InstrKind::Alloc { ty, slots } => {
stack_types.push(ir_core::Type::Struct("".to_string())); // It's a gate
@ -247,31 +247,31 @@ pub fn lower_function(
}, None));
}
ir_core::InstrKind::BeginPeek { gate } => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginPeek, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginPeek, span.clone()));
}
ir_core::InstrKind::BeginBorrow { gate } => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginBorrow, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginBorrow, span.clone()));
}
ir_core::InstrKind::BeginMutate { gate } => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginMutate, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateBeginMutate, span.clone()));
}
ir_core::InstrKind::EndPeek => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndPeek, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndPeek, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span.clone()));
}
ir_core::InstrKind::EndBorrow => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndBorrow, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndBorrow, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span.clone()));
}
ir_core::InstrKind::EndMutate => {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndMutate, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateEndMutate, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span.clone()));
}
ir_core::InstrKind::GateLoadField { gate, field } => {
let offset = program.field_offsets.get(field)
@ -280,12 +280,12 @@ pub fn lower_function(
let field_ty = program.field_types.get(field).cloned().unwrap_or(ir_core::Type::Int);
stack_types.push(field_ty.clone());
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, span.clone()));
if is_gate_type(&field_ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
}
}
ir_core::InstrKind::GateStoreField { gate, field, value } => {
@ -296,24 +296,24 @@ pub fn lower_function(
// 1. Release old value in HIP if it was a gate
if is_gate_type(&field_ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateLoad { offset: *offset }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRelease, span.clone()));
}
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: value.0 }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: gate.0 }, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::LocalLoad { slot: value.0 }, span.clone()));
// 2. Retain new value if it's a gate
if let Some(val_ty) = local_types.get(&value.0) {
if is_gate_type(val_ty) {
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateRetain, span.clone()));
}
}
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateStore { offset: *offset }, span));
vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::GateStore { offset: *offset }, span.clone()));
}
ir_core::InstrKind::GateLoadIndex { .. } => {
anyhow::bail!("E_LOWER_UNSUPPORTED: Dynamic HIP index access not supported in v0 lowering");

View File

@ -1,6 +1,7 @@
use crate::common::diagnostics::DiagnosticBundle;
use crate::common::files::FileManager;
use crate::frontends::pbs::{collector::SymbolCollector, parser::Parser, Symbol, Visibility};
use crate::common::spans::FileId;
use crate::manifest::{load_manifest, ManifestKind};
use prometeu_analysis::NameInterner;
use serde::{Deserialize, Serialize};
@ -131,7 +132,7 @@ pub fn build_exports(module_dir: &Path, file_manager: &mut FileManager) -> Resul
let source = fs::read_to_string(&file_path)?;
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, FileId(file_id as u32), &mut interner);
let parsed = parser.parse_file()?;
let mut collector = SymbolCollector::new(&interner);

View File

@ -0,0 +1,26 @@
use prometeu_analysis::{ids::FileId, span::Span};
use prometeu_compiler::common::diagnostics::{Diagnostic, DiagnosticBundle, Severity};
#[test]
fn diagnostic_span_is_valid_for_file() {
// Fixture simples
let text = "let x = 10;"; // len = 11
let file = FileId(1);
// Cria um diagnóstico com span válido: end exclusivo e <= len
let span = Span::new(file, 0, text.len() as u32);
assert!(span.end >= span.start);
assert!(span.end <= text.len() as u32);
let diag = Diagnostic {
severity: Severity::Error,
code: "E_TEST".to_string(),
message: "testing".to_string(),
span,
related: vec![],
};
let bundle = DiagnosticBundle { diagnostics: vec![diag] };
// Serialize para garantir que o span passa pelo pipeline sem panics
let _json = serde_json::to_string(&bundle).expect("must serialize diagnostics");
}

View File

@ -2,6 +2,7 @@ use prometeu_bytecode::disasm::disasm;
use prometeu_bytecode::BytecodeLoader;
use prometeu_compiler::compiler::compile;
use prometeu_compiler::frontends::pbs::parser::Parser;
use prometeu_compiler::common::spans::FileId;
use prometeu_analysis::NameInterner;
use std::fs;
use std::path::Path;
@ -57,7 +58,7 @@ fn generate_canonical_goldens() {
// 3. AST JSON
let source = fs::read_to_string(project_dir.join("src/main/modules/main.pbs")).unwrap();
let mut interner = NameInterner::new();
let mut parser = Parser::new(&source, 0, &mut interner);
let mut parser = Parser::new(&source, FileId(0), &mut interner);
let parsed = parser.parse_file().expect("Failed to parse AST");
let ast_json = serde_json::to_string_pretty(parsed.arena.kind(parsed.root)).unwrap();
fs::write(golden_dir.join("ast.json"), ast_json).unwrap();