symbolique 0.1.0

Symbol table pipeline for language servers — parse, link, merge, and resolve symbols across files, built on the laburnum LSP framework.
docs.rs failed to build symbolique-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

symbolique

Generic symbol table pipeline for compilers and language servers, built on laburnum's partition system.

Pipeline

Symbols flow through 4 stages, each backed by a laburnum partition:

     Symbols (CAS)             ← Content-addressed symbol storage (shared across all stages)
         │
    FileSymbols                ← Stage 1: Parse - per-file symbol index
         │
   LinkedSymbols               ← Stage 2: Link - cross-file import resolution
         │
   MergedSymbols               ← Stage 3: Merge - combined namespace
         │
  SymbolResolution             ← Stage 4: Resolve - reference → definition mapping

Each stage writes index entries pointing to shared Symbol records in the CAS partition.

Integration with Laburnum

The pipeline stages map to laburnum's task-based incremental computation model:

Stage Partition Writer Trait Invalidation
Parse FileSymbols SymboliqueWriteExt When file content changes
Link LinkedSymbols LinkedSymboliqueWriteExt When imported file changes
Merge MergedSymbols MergedSymboliqueWriteExt When any file in package changes
Resolve SymbolResolution ResolutionWriteExt When any linked table changes

All writes go through PartitionWriteContextRef using the writer extension traits.

Type Parameters

All partition types are generic over three parameters:

Parameter Trait Purpose
V Value<I> Literal values in your language
I Ident Identifier representation
P SymbolPath Path representation (default: String)

Default implementations are provided:

  • StringIdent - String-based identifiers
  • DefaultValue - Common literal types (String, Integer, Float, Boolean)

Symbol Types

The Symbol enum represents 6 patterns:

Variant Purpose Example
Definition Named entities Functions, variables, types
Reference Names referring to other symbols Variable usage, path access
Scope Anonymous containers Blocks, namespaces
Keyword Reserved words if, let, fn
Value Literal values 42, "hello"
Import Imported symbols use math::add

Writing Symbols

Each stage has a writer extension trait on PartitionWriteContextRef. Writers store the Symbol record in the CAS partition and create a SymbolEntry index entry in the stage's partition.

use symbolique::{SymboliqueWriteExt, SymbolVisibility};

// In an on_file_version hook or similar task:
writer.write_symbol_definition(
    "math.add".to_string(),    // path
    span,                      // laburnum::Span
    ident,                     // I: Ident
    None,                      // value: Option<V>
    SymbolVisibility::Public,
);

writer.write_symbol_reference(
    "main.ref_to_add".to_string(), // path
    span,                          // laburnum::Span
    Some(ident),                   // name: Option<I>
    "math.add".to_string(),        // target_path
    false,                         // is_absolute
    true,                          // nameable
);

The linked and merged stages follow the same pattern with LinkedSymboliqueWriteExt and MergedSymboliqueWriteExt.

Resolution

The resolution stage maps references to their targets using ResolutionWriteExt:

use symbolique::ResolutionWriteExt;

writer.write_resolution(
    reference_path,   // P - the reference's path
    target_path,      // P - the resolved target's path
    target_handle,    // RecordHandle<Symbols<V, I, P>> - handle to the target symbol
);

Custom Resolution

Implement SymboliqueResolver for your language's resolution behavior:

use symbolique::{SymboliqueResolver, Resolution, SymbolEntry, Value, Ident, SymbolPath};

struct MyResolver;

impl<V, I, P> SymboliqueResolver<V, I, P> for MyResolver
where
    V: Value<I>,
    I: Ident + std::hash::Hash,
    P: SymbolPath,
{
    fn resolve(
        &self,
        path: &P,
        from_scope: SymbolEntry<V, I, P>,
    ) -> Resolution<V, I, P> {
        // Walk scopes to find the target for this path
        // Return Resolution::Resolved(target_entry) on success
        // Return Resolution::Deferred for multi-pass resolution
        // Return Resolution::Failed(msg) on error
        todo!()
    }
}

The Resolution enum has these variants:

  • Resolved(SymbolEntry) - Successfully resolved
  • Deferred - Process in next pass (for multi-pass resolution)
  • Phantom(PhantomSymbol) - Resolved to external/synthetic symbol
  • WrongKind { found, expected_kinds } - Found but wrong type
  • Failed(String) - Resolution failed with error message

Key Types

SymbolEntry

The index entry type used across all stages. Pairs a span with a content-addressed handle to the symbol record:

pub struct SymbolEntry<V, I, P> {
    pub span: laburnum::Span,
    pub symbol: RecordHandle<Symbols<V, I, P>>,
}

ResolutionEntry

The index entry for the resolution stage. Maps a reference to its resolved target:

pub struct ResolutionEntry<V, I, P> {
    pub target_path: P,
    pub target: RecordHandle<Symbols<V, I, P>>,
}