SynapsesOS
Internals

Parser System

Synapses ships with 49+ language parsers built on tree-sitter grammars. Each parser extracts structural nodes and edges from source files.

Parser Interface

All parsers implement a common interface that accepts a file path and source bytes, and returns:

  • Nodes — each with a type (function, struct, interface, class, method, etc.), name, file path, line number, and exported flag
  • Edges — relationships between nodes (calls, contains, imports, implements, etc.)

This uniform interface means the graph engine is language-agnostic — it only works with nodes and edges.

Parser Registry

The registry maps file extensions to parser implementations:

  • .go → Go parser
  • .ts, .tsx → TypeScript parser
  • .py → Python parser
  • .rs → Rust parser
  • …and so on for all supported languages

When the watcher detects a changed file, it looks up the extension in the registry to find the right parser. Unknown extensions are skipped.

Tree-Sitter Grammars

Each parser uses a tree-sitter grammar to produce a concrete syntax tree (CST). The parser then walks the CST to extract nodes and edges. Tree-sitter provides:

  • Accurate parsing even for incomplete or syntactically broken files
  • Fast incremental parsing
  • Consistent API across all languages

Call Site Resolution

Call resolution happens in two passes:

  1. During parse — When a parser encounters a function call, it records an unresolved call site in the call_sites table with the callee name and context (file, line, receiver type if known).
  2. Post-parse pass — After all files are parsed, a resolution pass matches unresolved call sites to known function nodes by name, package, and receiver type. Resolved calls become edges in the graph.

This two-pass approach handles cross-file calls where the callee might not have been parsed yet when the caller was processed.

Route Heuristic

For web frameworks, parsers detect HTTP route registration patterns (e.g., router.GET("/api/users", handler)) and create route nodes. Framework-specific pattern detection covers:

  • Go: net/http, chi, gin, echo, fiber
  • Node.js: Express, Fastify
  • Python: Flask, FastAPI, Django

Route nodes connect to their handler functions, making it possible to trace from an API endpoint to the code that serves it.

Adding a New Language

To add parser support for a new language:

  1. Implement the parser interface — Create a new file in internal/parser/ that walks the tree-sitter CST and extracts nodes and edges.
  2. Add the tree-sitter grammar — Include the grammar dependency so tree-sitter can parse the language.
  3. Register in the registry — Map the file extension(s) to your new parser.
  4. Add tests — Write test cases with sample source files and verify the extracted nodes and edges are correct.
  5. Handle call sites — Implement call site extraction so function calls can be resolved to edges in the post-parse pass.