Search/Fix and Test a Code Generator That Wraps Native Libraries for Many Languages

Fix and Test a Code Generator That Wraps Native Libraries for Many Languages

Use when changing a compiler-style tool that turns native library declarations into wrappers for many languages. It traces bugs to the stage where they start, runs right-sized tests, adds regression tests, and updates the change log.

To use this AI rule
## Read the Task Guides First and Fix Inputs, Not Generated Files ### Start with task-specific guidance Before changing code or running specialized commands, locate the repository's short, task-specific guides. Read the guide that matches the work instead of reconstructing procedures from a broad overview. Typical guides cover: - running the full suite, one target-language suite, or one test case; - debugging the compiler, inspecting parse trees, and tracing memory faults; - editing the user manual and validating its structure; - source formatting, comments, contribution conventions, and commit messages; - reproducing failures that occur only in continuous integration. Treat these focused guides as canonical when they provide exact commands, flags, or conventions. If discovery aliases or symbolic links mirror the same guide into several tool-specific locations, maintain one source of truth and verify that the links materialize correctly on the contributor's platform. ### Understand the system before editing it The repository implements a compiler-style generator. It reads native declarations and interface descriptions, then emits wrappers that expose native libraries to many target languages. This model has three practical consequences: - generated files are outputs, not the primary place to fix behavior; - shared interface inputs should contain cross-language behavior, while target-specific runtime checks belong in the corresponding target test directory; - a change in parsing, type resolution, ownership, or wrapper emission can affect many backends even when the reported symptom appears in only one. Use the repository's own guides, build files, and tests as evidence. Do not infer a workflow solely from familiar-looking directory names or from conventions used by another project. ## Build with the CI Build System and Pick the Smallest Useful Test ### Build from the correct source form Use the primary build system used by continuous integration. A checkout from version control may require a bootstrap step to generate configuration files, while a release archive may already include them. The normal sequence is bootstrap when required, configure, then build. Preserve supported configuration switches such as installation prefix and optional dependency controls. A secondary build system may exist, but do not silently substitute it when diagnosing a failure from the primary pipeline. Tests and examples may invoke an uninstalled-tree launcher that points the runtime at the freshly built library directory; use that launcher so tests exercise the current checkout rather than an installed copy. If an auxiliary compiler-cache component is part of the default build and test graph, include it unless the canonical guide explicitly narrows the run. ### Choose the smallest meaningful test Match the command to the scope of the change: - run one generated-wrapper test while iterating on a localized behavior; - run the complete suite for the affected target language when backend behavior changes; - run shared suites when parser, type-system, ownership, or common emission logic changes; - use parallel execution only where the repository supports it; - use a keep-going mode for broad runs when collecting all failures is more useful than stopping at the first. Test targets often encode the source form, such as native-language mode, object-oriented mode, or multi-module mode. Use the suffix that matches the case and run the matching cleanup target before assuming a stale generated artifact is a new failure. ### Verify the same path used in automation When a failure occurs only in continuous integration, reproduce the runner environment with the repository's maintained container image and real installation scripts. Prefer the helper that mirrors the hosted runner over an improvised environment. Confirm the same dependency versions, environment variables, build mode, and test target before attributing the difference to source code. A bug fix or feature should normally include a regression test. Do not claim a change is verified because the compiler built successfully; wrapper generation, compilation of generated code, and target-language runtime behavior are separate checkpoints. ## Find the Pipeline Stage Where a Bug Starts and Never Re-Enter the Parser ### Follow the processing stages Trace behavior through the pipeline in order: 1. The preprocessor expands interface inputs and conditional directives. 2. The scanner converts input text into tokens. 3. The parser applies the grammar and creates a tree of attribute-bearing nodes. 4. The type system resolves names, equivalences, templates, and conversions. 5. Tree-level passes add or normalize information needed by later stages. 6. A target-language backend walks the tree and emits wrapper code. Locate the earliest stage where actual state diverges from expected state. A malformed wrapper does not prove the backend is at fault; the backend may be faithfully emitting an incorrect parse node, type, ownership flag, or conversion rule created earlier. ### Use the model's core abstractions Parse nodes behave like key-value objects and are traversed by shared passes and language backends. Inspect attributes at the point they are created and again at the point they are consumed. Type-conversion maps control how native values cross the boundary into target-language values; when conversion behavior is wrong, check selection precedence and type equivalence before patching emitted text. Template instantiation depends on the same type-equivalence machinery, so isolate specialization matching from wrapper formatting. Shared ownership and allocation analysis should be examined before adding backend-local lifetime workarounds. ### Respect non-reentrant parser boundaries Assume the parser is non-reentrant unless the implementation proves otherwise. Entry points that wrap the parser may overwrite global parser state, including current input location, semantic values, and lookahead. Never call those entry points recursively from inside a grammar action. When a grammar rule needs to construct a fresh parameter list or related subsyntax, reuse the grammar's existing productions within the active parse rather than launching a nested parse. Validate the change with a regression case for the oldest language standard that introduces the grammar feature. ### Use supported debugging hooks Use the repository's documented debug flags, textual or structured tree dumps, debugger helpers, execution wrappers, feature-selection variables, and memory-pool diagnostics. For an automation-only failure, reproduce the automation environment before escalating instrumentation. Keep diagnostic changes temporary and do not turn a local workaround into production behavior without a failing test that demonstrates the need. ## Put Each Regression Test in the Shared Input or the Language Script ### Place behavior at the right layer A test normally has a shared interface input that drives generation and an optional target-language runtime script that exercises the generated wrapper. Put language-independent grammar and wrapper requirements in the shared input. Put target-language syntax, runtime assertions, and language-specific edge cases in the corresponding runtime script. Register new cases in the suite bucket that matches their true scope. A test-name prefix tied to a language standard must represent the oldest standard that introduced the grammar feature, not a newer standard used by a convenient example. Determine the feature in isolation, then place the test in the matching standard bucket. ### Make failures observable Use assertion helpers that remain active in optimized runtime modes. If a target language can remove its built-in assertion statement during optimization, never rely on that statement for regression coverage. Use explicit equality, condition, and expected-exception helpers that report useful values on failure. Keep test comments brief and non-obvious. Explain a compiler workaround or semantic trap in one concise line; do not narrate what the code already states. A regression test should fail before the fix, pass after the fix, and exercise the public behavior rather than an incidental internal helper. ### Validate shared impact For parser or common type-system changes, test more than the originally failing backend when the affected path is shared. For backend-only behavior, avoid expanding the run without evidence. Clean generated files between materially different test configurations, and distinguish generation failure, native compilation failure, and runtime failure in the report. ## Keep Unrelated Edits Out of Commits and Log Every Change Users Can See ### Follow source and comment conventions Use the repository's formatting checks and formatter rather than hand-normalizing unrelated code. Match established native-language comment style, token quoting, line width, and function-header conventions. Grammar files may impose stricter rules for new code; follow those rules and avoid unrelated refactoring while changing a production parser. Before committing, review the diff for generated files, accidental broad replacements, and changes outside the intended subsystem. Commit text must be plain, concise, and accurate. Do not attribute an automated tool as a coauthor. If the project requires disclosure of significant automated assistance, use its approved assistance trailer without an email identity. ### Record user-visible changes Every user-visible bug fix, feature, behavior change, warning change, or deprecation must include an entry in the current change log. Describe what a user observes, not internal helper names or refactoring details. Follow the repository's established date and issue format, place new entries in the expected order, and mark compatibility risks explicitly. Purely internal changes with no observable effect do not need a user-facing entry. ### Maintain developer and user documentation When editing the manual, preserve stable, descriptive heading anchors rather than generated numeric anchors. Use the documented content classes for code, target-language examples, shell sessions, and diagrams. Keep cross-document links anchored to stable targets, then run the table-of-contents generator and documentation checks. Developer documentation should explain the internal object model, tree attributes, type system, and extension path. User documentation should focus on supported syntax and observable behavior. Verify both the rendered structure and link targets; a successful source edit alone does not prove the manual remains navigable.