From 0ee6bbad6104320f49d27e39cfb04c747de527b5 Mon Sep 17 00:00:00 2001 From: janis Date: Tue, 14 Oct 2025 13:52:39 +0200 Subject: [PATCH] port symbol table from old crate --- crates/parser/src/lib.rs | 4 +- crates/parser/src/symbols.rs | 178 +++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 crates/parser/src/symbols.rs diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 3699f86..0db1abc 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -198,7 +198,7 @@ impl ControlFlowKind { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Index(pub u32); impl Index { @@ -1091,6 +1091,7 @@ fn attrs<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone { mod constants; mod pretty; +mod symbols; #[cfg(test)] mod tests { @@ -1181,6 +1182,7 @@ mod tests { print_ast( new_token_input( r#" +/// docs! fn my_function(a: i32, b: *const u8) -> i32 { x = a + 1; x diff --git a/crates/parser/src/symbols.rs b/crates/parser/src/symbols.rs new file mode 100644 index 0000000..427e874 --- /dev/null +++ b/crates/parser/src/symbols.rs @@ -0,0 +1,178 @@ +//! Coming from the ast, we have a `DeclRef` with an interned identifier `ident` +//! and want to find the symbol it refers to. +//! +//! To help, we have a struct keeping track of all accessible scopes. Now, we +//! want to look through any accessible scope `s` for a symbol with the name +//! `ident`. Thus: `Symbol {scope: `s`, name: `ident`, ..}`. +//! +//! We might also know the type of the symbol we are looking for, if we want +//! to permit fields/variables and methods/functions sharing names. +//! +//! Since I want to allow variable shadowing for local variables, some strategy +//! to differentiate between shadowed variables must be employed: +//! - keys of type SymbolKind::Local might point to a list of values with source locations +//! - keys might contain source locations. +//! +//! Any symbol pointed at from within the ast must again point at an ast +//! object. +//! Thus: `Key` -> `AstIndex` +//! Exception: `Key::ScopeByIndex` -> `InternIndex` + +use core::fmt::Debug; +use std::collections::BTreeMap; + +use internment::Intern; + +use crate::Index; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Span(u32); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Spanned(pub T, Span); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum SymbolKind { + __First, + Const, + Function, + Type, + __TypeScope, + Scope, + ParentScope, + Parameter(Span), + Local(Span), + __Last, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Key { + ScopeByName { + name: Intern, + }, + /// not all scopes have a name, as some are anonymous blocks or otherwise nameless + ScopeByIndex { + ast: Index, + }, + Symbol { + scope: Index, + name: Intern, + kind: SymbolKind, + }, +} + +impl Key { + pub fn parent(scope: Index) -> Key { + Key::Symbol { + scope, + name: Intern::from(""), + kind: SymbolKind::ParentScope, + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum Payload { + Ast(Index), + Name(Intern), +} + +pub struct Symbols { + inner: BTreeMap, +} + +impl Debug for Symbols { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Symbols [")?; + if f.alternate() { + writeln!(f, "")?; + } + let entries = self.inner.iter(); + f.debug_list().entries(entries).finish()?; + write!(f, "]")?; + if f.alternate() { + writeln!(f, "")?; + } + + Ok(()) + } +} + +// checks for each scope in scopes_in_tree Symbol { scope, kind: SymbolKind::Local, 0}..Symbol { scope, kind: SymbolKind::Scope, u32::MAX} +struct SymbolTreePos { + scopes_in_scope: Vec, +} + +impl Symbols { + pub fn new() -> Symbols { + Self { + inner: BTreeMap::new(), + } + } + pub fn insert_scope(&mut self, name: Intern, ast: Index) { + self.inner + .insert(Key::ScopeByIndex { ast }, Payload::Name(name)); + self.inner + .insert(Key::ScopeByName { name }, Payload::Ast(ast)); + } + + pub fn find_symbol(&self, scope: Index, name: Intern, loc: Span) -> Option<(Key, Index)> { + use SymbolKind::*; + let range = self.inner.range( + Key::Symbol { + scope, + name, + kind: __First, + }..=Key::Symbol { + scope, + name, + kind: Local(loc), + }, + ); + + if let Some((&key, &Payload::Ast(index))) = range.rev().next() { + Some((key, index)) + } else { + if let Some(&Payload::Ast(parent)) = self.inner.get(&Key::parent(scope)) { + self.find_symbol(parent, name, loc) + } else { + None + } + } + } + + pub fn find_type_symbol( + &self, + scope: Index, + name: Intern, + loc: Span, + ) -> Option<(Key, Index)> { + use SymbolKind::*; + let range = self.inner.range( + Key::Symbol { + scope, + name, + kind: __First, + }..=Key::Symbol { + scope, + name, + kind: __TypeScope, + }, + ); + + if let Some((&key, &Payload::Ast(index))) = range.rev().next() { + Some((key, index)) + } else { + if let Some(&Payload::Ast(parent)) = self.inner.get(&Key::parent(scope)) { + self.find_type_symbol(parent, name, loc) + } else { + None + } + } + } + + pub fn insert_symbol(&mut self, scope: Index, name: Intern, kind: SymbolKind, ast: Index) { + self.inner + .insert(Key::Symbol { scope, name, kind }, Payload::Ast(ast)); + } +}