API Contract
This chapter records the intended public consumer surface of parc.
It is not a blanket promise about every future change. It is the current
guidance for how downstream tools should integrate with the crate without
depending on parser internals or accidentally turning parc into a shared ABI
owner for the rest of the pipeline.
First Principle
parc is the source-meaning layer of the pipeline: preprocessing, parsing, and
source-level semantic extraction.
The intended downstream pattern is:
- scan headers or parse source via
driver,scan, orparse - extract normalized declarations via
extract - consume the
SourcePackageIR fromir - use
visit,span, andlocto analyze AST-level details if needed
Downstream consumers that want source contracts should depend on parc::ir,
not on parc::ast directly.
More importantly for this repository:
parclibrary code must not depend onlincorgerclincandgercshould not requireparcas a library dependency in their production code paths- integration should happen through PARC-owned artifacts in tests/examples or external harnesses
- there is no shared ABI crate that all three libraries depend on
- there is no obligation to preserve discarded pipeline shapes for backward compatibility
Preferred public surface
These are the main consumer-facing modules:
| Module | Role | Current expectation |
|---|---|---|
parc::ir | source-level IR (SourcePackage) | preferred data contract |
parc::extract | declaration extraction from AST | preferred extraction entry point |
parc::scan | header scanning (preprocess + extract) | preferred high-level entry point |
parc::intake | preprocessed source intake | preferred for already-preprocessed source |
parc::driver | parse files and preprocessed source | preferred parse entry point |
parc::preprocess | built-in C preprocessor | preferred preprocessing entry point |
parc::parse | parse string fragments directly | preferred low-level entry point |
parc::ast | typed syntax tree | internal data model |
parc::visit | recursive traversal hooks | preferred traversal API |
parc::span | byte-range metadata | preferred location primitive |
parc::loc | map offsets back to files/lines | preferred diagnostics helper |
parc::print | AST debug dumping | preferred inspection helper |
Internal modules are not the contract
These modules are public only indirectly through behavior, not as a recommended downstream surface:
parserenvastutilstrings
If a downstream tool depends directly on how those modules work, it is probably coupling itself to implementation details rather than the intended library boundary.
Normative consumer rules
If you are building on top of parc, the safest current rules are:
- use
driverwhen preprocessing matters - use
parse::*for fragment parsing or already-controlled text inputs - treat
ir::SourcePackageas the primary output contract - use
visitfor traversal instead of hand-rolling recursive descent everywhere - use
spanandlocfor diagnostics rather than guessing source positions - do not rely on exact error-message strings for durable control flow
- do not treat PARC as semantic analysis, type checking, or ABI proof
- if another crate needs PARC output, serialize the PARC-owned artifact and translate it outside library code
What is part of the practical contract
Today the strongest practical contract is:
ir::SourcePackage,SourceType,SourceItem, and all IR types — the primary data contractextract::extract_from_source,extract_from_translation_unit,parse_and_extract,parse_and_extract_resilientscan::ScanConfig,scan_headers,ScanResultintake::PreprocessedInputir::SourcePackageBuilder— programmatic package constructiondriver::Config,Flavor,Parse,Error,SyntaxError,parse_builtin, andcapture_macrospreprocess::{Processor, IncludeResolver, MacroTable, Lexer, preprocess, tokens_to_text, Target, define_target_macros}parse::{constant, expression, declaration, statement, translation_unit, translation_unit_resilient}- the AST model under
ast - the traversal hooks under
visit - the span/location model under
spanandloc
Those are the surfaces the rest of the book assumes consumers will use.
The important correction is this: PARC has two practical contracts today, not one:
- a source-contract path centered on
ir,extract, andscan - a parser-facing path centered on
driver,parse,ast, andvisit
The docs should not pretend the AST side does not exist, because the crate very much exposes it.
What is intentionally weaker
The following should be treated as less stable than the core parsing surface:
- exact debug formatting of AST values
- exact
Displaywording of parse errors - internal parser file layout under
src/parser/ - incidental ordering of implementation helper functions
These details are useful for debugging and contribution work, but they are not the main consumer contract.
Explicit non-goals
The current contract does not promise:
- semantic name resolution beyond parsing decisions such as typedef handling
- type checking
- ABI compatibility guarantees
- full support for every GCC or Clang extension
- preservation of raw macro definitions beyond what
capture_macrosprovides
Those are outside the scope of PARC as a source frontend.
Downstream posture
For long-lived integrations, the safest posture is:
- use
scanorextractas your primary entry point — these produceSourcePackage - consume
ir::SourcePackagerather than raw AST types where possible - use
driverandparseonly when you need AST-level access - treat unsupported syntax and parser errors as normal outcomes
- keep tests with representative preprocessed inputs for the syntax families you depend on
- keep cross-package translation in tests/examples/harnesses rather than adding library dependencies
- see Migration From bic if you are transitioning from
bic