# 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:
```text
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:
| 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:
| `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:
| `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.
```rust,ignore
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`:
```rust,ignore
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:
```rust,ignore
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:
```rust,ignore
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:
```rust,ignore
pub struct ResolutionEntry<V, I, P> {
pub target_path: P,
pub target: RecordHandle<Symbols<V, I, P>>,
}
```