Skip to content

0.1.8 — Tcl round-trip + LEF producer-form coverage

Latest

Choose a tag to compare

@lanserge lanserge released this 13 Jun 21:38
· 387 commits to main since this release

100% round-trip across four EDA formats on the maintainer's local production corpus: 7,217 / 7,217 files (GDSII / LEF / DEF / Tcl) parse → save → re-parse to a structurally equivalent AST.

Tcl reaches full round-trip — 3,273 / 3,273

The Tcl parser group landed in 0.1.5 as parse-only. This release wires the inverse:

  • 10 unparse overrides on every bound terminal (comment, brace_group, quoted_string, bracket_sub, bare_word, var_name, escape, literal_run, newline, expand_marker).
  • New tcl.command_sep parser — accepts \n or ; on parse, emits canonical \n.
  • tcl.bare_word now handles \X escapes (Dodekalogue rule 9): MACC_\{CONFIG\} parses as a single word.
  • Grammar restructures: WORDS gains a space postfix, SCRIPT inlines old COMMANDS with a commands[]=@ list binding so separators stay structural, VAR_INDEX becomes a non-container sequence so its :index=@ flows up into VAR_SEG, and VAR_SEG splits into bare vs. braced forms keyed by a form discriminator — eliminating the ${name}_suffix round-trip ambiguity.

LEF gains three real-world producer forms — 822 / 822

  • DATABASE MICRONS accepts <NUMBER> (asap7 emits 1000.0, not 1000).
  • New UNITS_COMPACT_CMD for the one-line UNITS DATABASE MICRONS N ; form OpenROAD's PCB writer emits.
  • BUSBITCHARS / DIVIDERCHAR / NAMESCASESENSITIVE / NOWIREEXTENSIONATPIN now compose order-free in HDR_CMD.

Engine fixes (shared infrastructure)

  • Loader drops the type="var" back-compat that silently consumed legitimate user constants. parser:type="var":field=@ now binds both fields cleanly.
  • Raw save-dispatch tolerates non-String values when #subparse is set — unblocks ?<RULE> round-trip on any grammar using the *:field=@:#subparse="<RULE>" shape.

Scope parser group

New scope.{paren,bracket,brace,angle} parsers for depth-balanced bracket capture as a #subparse source. Single ScopeParser<Start, Stop> class template with four explicit instantiations; eight unit tests.

Branch reorganisation

SystemVerilog work (grammar + parsers + tests) moved off main to a dedicated feat/sv branch. SV is comprehensive parse-side but the round-trip story isn't yet wired; keeping it on main inflated the test matrix without contributing to the shippable round-trip surface. Five existing feat/sv-* branches preserved as historical snapshots.

main retains the generic preprocessor mechanism — grammar-agnostic, works against any grammar whose directive rules carry :#role=... annotations.

Pre-release corpus harness

New local_tests/ folder (developer-local, excluded via .git/info/exclude) holds the corpus path lists and round-trip harness used to verify each release. See local_tests/README.md.

Verification

  • 250 C++ tests / 973 assertions — all green
  • 49 Python tests — all green
  • Production corpus: 7,217 / 7,217 (100%) across GDSII / LEF / DEF / Tcl