port symbol table from old crate

This commit is contained in:
janis 2025-10-14 13:52:39 +02:00
parent 0468f1fab3
commit 0ee6bbad61
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 181 additions and 1 deletions

View file

@ -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

View file

@ -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<T>(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<str>,
},
/// not all scopes have a name, as some are anonymous blocks or otherwise nameless
ScopeByIndex {
ast: Index,
},
Symbol {
scope: Index,
name: Intern<str>,
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<str>),
}
pub struct Symbols {
inner: BTreeMap<Key, Payload>,
}
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<Index>,
}
impl Symbols {
pub fn new() -> Symbols {
Self {
inner: BTreeMap::new(),
}
}
pub fn insert_scope(&mut self, name: Intern<str>, 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<str>, 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<str>,
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<str>, kind: SymbolKind, ast: Index) {
self.inner
.insert(Key::Symbol { scope, name, kind }, Payload::Ast(ast));
}
}