symbolique 0.1.0

Symbol table pipeline for language servers — parse, link, merge, and resolve symbols across files, built on the laburnum LSP framework.
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

//! File-level symbol partitions.
//!
//! Stage 1 of the symbolique pipeline. Parsing a single source file produces:
//!
//! - **FileSymbols**: Index-only partition with `SymbolEntry` index entries
//!   pointing to shapes in the shared `Symbols` partition
//!
//! This stage is parallelizable across files.

use {
  super::records::SymbolEntry,
  crate::core::{Ident, Symbol, SymbolPath, SymbolSortKey, Value},
  laburnum::{
    ContentHash, Ident as LaburnumIdent,
    database::{Partition, PartitionKey},
    record::{Record, hash_record},
  },
  std::{hash::Hash, marker::PhantomData},
};

/// File-level symbol index partition (index-only).
///
/// Stores only index entries that reference shapes in the shared `Symbols`
/// partition. Each entry contains a span and a handle to the symbol shape.
///
/// # Type Parameters
///
/// - `V`: Value type for literals
/// - `I`: Identifier type for names
/// - `P`: Symbol path type (used for index sort keys)
///
/// # Sort Key
///
/// Uses [`SymbolSortKey`] as the sort key. Sort keys are produced by
/// [`SymbolPath::sort_key`] and structured such that parent paths are
/// prefixes of child paths (for hierarchical queries to work).
#[derive(Hash)]
pub struct FileSymbols<V, I, P>(PhantomData<(V, I, P)>);

impl<V, I, P> Default for FileSymbols<V, I, P> {
  fn default() -> Self {
    Self(PhantomData)
  }
}

impl<V, I, P> Clone for FileSymbols<V, I, P> {
  fn clone(&self) -> Self {
    *self
  }
}

impl<V, I, P> Copy for FileSymbols<V, I, P> {}

impl<V, I, P> std::fmt::Debug for FileSymbols<V, I, P> {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("FileSymbols").finish()
  }
}

impl<V, I, P> PartitionKey for FileSymbols<V, I, P>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
{
  const KEY: LaburnumIdent = LaburnumIdent::new("symbolique::file_symbols");
}

impl<V, I, P> Partition for FileSymbols<V, I, P>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
{
  type Record = (); // Index-only
  type IndexEntry = SymbolEntry<V, I, P>;
  type SortKey = SymbolSortKey;
}

/// File-level symbol index partition.
///
/// Stores path-keyed index entries that link hierarchical paths to symbol
/// shapes. The path serves as the sort key, enabling `begins_with` queries
/// for scope traversal.
#[derive(Hash)]
pub struct FileSymbolIndex<V, I, P>(PhantomData<(V, I, P)>);

impl<V, I, P> Default for FileSymbolIndex<V, I, P> {
  fn default() -> Self {
    Self(PhantomData)
  }
}

impl<V, I, P> Clone for FileSymbolIndex<V, I, P> {
  fn clone(&self) -> Self {
    *self
  }
}

impl<V, I, P> Copy for FileSymbolIndex<V, I, P> {}

impl<V, I, P> std::fmt::Debug for FileSymbolIndex<V, I, P> {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("FileSymbolIndex").finish()
  }
}

impl<V, I, P> PartitionKey for FileSymbolIndex<V, I, P>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
{
  const KEY: LaburnumIdent =
    LaburnumIdent::new("symbolique::file_symbol_index");
}

impl<V, I, P> Partition for FileSymbolIndex<V, I, P>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
{
  type Record = (); // Index-only
  type IndexEntry = SymbolEntry<V, I, P>;
  type SortKey = SymbolSortKey;
}

impl<V, I, P> Record for Symbol<V, I, P>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
{
  fn content_hash(&self) -> ContentHash {
    hash_record(self)
  }
}