Global Symbol Table & Resolution
Relevant source files
The following files were used as context for generating this wiki page:
The Global Symbol Table is a central component of the Arbor ecosystem designed to facilitate cross-file symbol resolution and semantic linking. In large codebases, symbols like classes and functions are often defined in one file and referenced in another; the Global Symbol Table maps these Fully Qualified Names (FQNs) to specific Node IDs within the Arbor graph, transforming isolated file data into a unified Code Property Graph (CPG).
This system allows Arbor to move beyond simple text-based matching by resolving imports and references with structural certainty. It handles complex scenarios such as namespaces, re-exports, and inheritance across different files, ensuring that a symbol like User in an authentication module is correctly distinguished from a User type in a database schema.
Sources: README.md:129-132, crates/arbor-graph/src/symbol_table.rs:1-10, PR_DESCRIPTION.md:27-29
Architecture and Data Structures
The core of the resolution system resides in the arbor-graph crate, specifically within the SymbolTable struct. This structure maintains two primary mappings to support bidirectional lookup and context-aware resolution.
Core Data Structures
| Field | Type | Description |
|---|---|---|
by_fqn | HashMap<String, NodeId> | Maps a unique Fully Qualified Name (e.g., pkg.module.func) to its internal graph Node ID. |
exports_by_file | HashMap<PathBuf, Vec<String>> | Tracks all exported FQNs associated with a specific file path. |
Sources: crates/arbor-graph/src/symbol_table.rs:11-17
FQN Generation
The ArborParser generates qualified names during the symbol extraction phase. For instance, in many languages, it concatenates the file name with the symbol name (e.g., filename:symbol_name) to create a unique identifier before insertion into the graph.
Sources: crates/arbor-core/src/parser_v2.rs:253-254
Symbol Resolution Logic
The resolution process follows a hierarchical approach to ensure accuracy while allowing for flexible matching when full qualifications are missing in the source code.
Resolution Flow
When a reference is encountered, the system attempts to resolve it using the following order of operations:
- Exact Match: Checks if the provided name exists exactly as a key in the
by_fqnmap. - Suffix Match: Searches for symbols where the FQN ends with the target name (e.g.,
helpermatchingpkg.Utils.helper). - Locality Preference: If multiple suffix matches exist, the system prioritizes candidates located in the same directory as the context file.
- Ambiguity Handling: If multiple matches exist and none are local, or if multiple are local, the system returns
Noneto prevent incorrect auto-linking.
Sources: crates/arbor-graph/src/symbol_table.rs:43-61
Context-Aware Matching Diagram
The following flowchart illustrates how the SymbolTable resolves a symbol name within a specific file context.
The diagram shows the logic gate process for identifying the correct Node ID based on FQN strings and file system location.
Sources: crates/arbor-graph/src/symbol_table.rs:62-105
Cross-File Resolution Integration
The resolution system is integrated into the GraphBuilder and ArborParser to create "World Edges"—links that bridge file boundaries.
Interaction between Components
- Parsing:
ArborParserextracts symbols and relationship metadata (calls, imports) from individual files. - Registration: Extracted symbols are registered in the
SymbolTablewith their FQNs. - Linking: The
GraphBuilderuses theSymbolTableto resolve target names of relationships into specific Node IDs, creating edges in the graph.
This sequence shows how a call in one file is linked to a definition in another using the global table.
Sources: crates/arbor-core/src/parser_v2.rs:184-187, PR_DESCRIPTION.md:27-31, crates/arbor-graph/README.md:32-38
Key Implementation Methods
The SymbolTable provides several public methods to manage the resolution lifecycle:
| Method | Signature | Description |
|---|---|---|
insert | fn insert(&mut self, fqn: String, id: NodeId, file: PathBuf) | Registers a new symbol and associates it with a file. |
resolve | fn resolve(&self, fqn: &str) -> Option<NodeId> | Performs a simple exact-match lookup. |
resolve_with_context | fn resolve_with_context(&self, name: &str, context_file: &Path) -> Option<NodeId> | Performs advanced, locality-aware resolution. |
get_file_exports | fn get_file_exports(&self, file: &PathBuf) -> Option<&Vec<String>> | Retrieves all symbols defined within a specific file. |
Sources: crates/arbor-graph/src/symbol_table.rs:24-61
Suffix Matching Logic
The suffix matching implementation ensures that partial matches are valid symbol boundaries by checking for separators like . or :.
// Check if FQN ends with the name (with separator)
if fqn.ends_with(name) {
let prefix_len = fqn.len() - name.len();
if prefix_len == 0
|| fqn.chars().nth(prefix_len - 1) == Some('.')
|| fqn.chars().nth(prefix_len - 1) == Some(':')
{
// Valid suffix boundary found
}
}
Sources: crates/arbor-graph/src/symbol_table.rs:72-80
Conclusion
The Global Symbol Table is the backbone of Arbor's "Logic Forest." By maintaining a mapping of Fully Qualified Names across file boundaries and providing context-aware resolution, it enables the transformation of raw AST data into a navigable, semantic dependency graph. This system ensures that impact analysis and pathfinding can traverse the entire codebase with structural certainty, correctly identifying the relationship between callers and callees regardless of their location in the project.