S-Expression Projection Parser Design

Purpose

The S-expression projection parser lets callers select complete KiCad source forms without first allocating a full token stream, nested list tree, or typed document model.

The parser is intended for narrow read-only scans such as BOM extraction, project health checks, asset inventories, schematic metadata inspection, and preflight counts. The existing full parser remains the path for editing, round-trip, rendering, geometry, and netlist behavior.

Layering

Selector Semantics

A selector can match by form head, exact source path, and depth bounds. Paths are tuples of form heads from the document root to the selected form. For example, a top-level PCB footprint has the path ("kicad_pcb", "footprint").

Selectors may also prune matching form heads. Pruning skips the children of a matched form while still allowing the form itself to be emitted if it otherwise matches. This is useful when a caller wants board-level forms but does not want to scan deeply through embedded model payloads.

Source Ownership

SexpFormSpan records offsets, source location, head, path, and a reference to the source text. This keeps selected forms cheap to pass around and allows callers to parse only forms that they actually need.

Callers that retain many spans should retain the original source text once, not duplicate selected substrings. File-based helpers read the file once and attach the same source text to yielded spans.

Error Handling

Projection scanning validates parenthesis balance and quoted strings well enough to trust source offsets. It raises the same family of S-expression errors as the full parser where practical, with source path and location data attached.

The scanner does not validate typed KiCad semantics. A selected form is still parsed or materialized by the existing parser or typed factories when the caller needs structured content.

Consumer Pattern

selector = SexpSelector(paths={("kicad_pcb", "footprint")})
for span in iter_sexp_file_form_spans(board_path, selector):
    footprint_sexp = span.parse()
    # Build only the summary or typed object needed by this workflow.

Typed Object Iterator

Rationale

Library extraction, project-health scans, and future targeted rewrite tools need a generic way to hydrate selected KiCad objects without each workflow maintaining its own scanner.

Purpose

iter_kicad_objects_from_text and iter_kicad_objects_from_file map a requested KiCad domain type to the projection selector that finds matching forms, then hydrate those forms through the same typed factories used by the full parser.

Test Requirements

Tests must prove board footprints, schematic placed symbols, symbol-library symbols, file-backed reads, and embedded-file filtering yield the expected typed objects without a complete document parse.

Working Definition

A typed object iterator is public when callers can request a supported KiCad object type and receive normal domain objects while still relying on projection parsing for source selection.