Skip to content

[codex] support project-level constexpr generation#95

Merged
Jiu-xiao merged 1 commit into
XRobot2.0from
feat/project-constexprs-20260419
Apr 19, 2026
Merged

[codex] support project-level constexpr generation#95
Jiu-xiao merged 1 commit into
XRobot2.0from
feat/project-constexprs-20260419

Conversation

@Jiu-xiao

@Jiu-xiao Jiu-xiao commented Apr 19, 2026

Copy link
Copy Markdown
Member

This change adds project-level constexpr generation to xrobot_gen_main and tightens the generator's configuration parsing so invalid YAML and malformed config structures fail with clear errors instead of leaking Python tracebacks or silently degrading into incomplete output.

Before this change, project code could only pass literal values or ad-hoc string expressions through User/xrobot.yaml. That made it awkward to express strongly typed compile-time configuration shared across modules, especially for template arguments and aggregate constructor arguments. In the same area, the generator's parser had several edge cases that were unsafe in practice: nested manifest YAML could be flattened by indentation loss, top-level non-mapping YAML could reach deep code paths and crash with AttributeError, and malformed global_settings / modules entries could be silently ignored or fail unclearly.

The root cause was that GenerateMain.py only handled simple value formatting and assumed a mostly well-formed config tree. It had no project-level constexpr emission path, no dedicated config loader with structural validation, and manifest parsing stripped indentation from lines before handing them to YAML parsing.

The fix adds a project-level constexprs / constexpr_includes surface to User/xrobot.yaml. When present, xrobot_gen_main now emits xrobot_constexpr.hpp, and both constructor_args and template_args can reference generated symbols using {constexpr: Name}. The generator remains in a single GenerateMain.py file, keeps the existing CLI entrypoint, and the package version is bumped to 0.2.9. README usage was updated to match the real current behavior, including the single-file generator, the User/xrobot.yaml layout, and the xrobot_setup flow.

This PR also hardens config parsing behavior. Manifest parsing now preserves indentation so nested YAML structures survive round-tripping. Config loading validates that the top-level YAML is a mapping, and generation now validates global_settings, each modules[*] entry, and per-module constructor_args / template_args mappings explicitly. On CLI failure paths, these validation errors are surfaced as readable command-line errors instead of raw stack traces.

Validation was done in three layers. First, python3 -m compileall src/xrobot/GenerateMain.py was run on the final branch state. Second, an ad-hoc parsing regression and boundary verification matrix was executed with 22 passing checks, covering valid generation, malformed YAML, top-level type errors, malformed module entries, invalid constexpr references, and CLI error surfaces. Third, a local multi-module smoke run exercised real generator flows with mock BlinkLED, WebotsCamera, ArmorDetector, and PoseFilter modules, covering manifest-driven default config generation, nested manifest args, config-driven module discovery, @instance references, and the new constexprs / constexpr_includes emission path. Together these checks verify both the new feature and the generator's failure behavior on malformed input.

Summary by Sourcery

Add project-level constexpr header generation to xrobot_gen_main and harden configuration parsing and CLI error handling.

New Features:

  • Introduce project-level constexpr and constexpr_includes configuration in User/xrobot.yaml to generate an xrobot_constexpr.hpp header and support {constexpr: Name} references in constructor and template arguments.

Bug Fixes:

  • Tighten YAML and config loading so non-mapping top-level configs, invalid modules lists, or malformed entries raise clear errors instead of silently degrading or crashing with tracebacks.
  • Make modules extraction and main generation robust to invalid module declarations by enforcing proper types and required fields and surfacing errors via CLI exit codes.

Enhancements:

  • Preserve manifest YAML indentation during parsing to support nested structures.
  • Validate overall config structure, global_settings, modules entries, and per-module constructor_args/template_args as mappings with clearer requirements for names and ids.
  • Ensure template arguments preserve raw type-expression strings while still supporting constexpr references.
  • Improve xrobot_gen_main and xrobot_setup documentation to reflect the single-file generator, updated config layout, and constexpr workflow.
  • Update xrobot_setup behavior and README examples to describe the current workspace bootstrap flow and CLI output.

Build:

  • Bump package version to 0.2.9 in pyproject.toml to publish the new generator behavior.

Documentation:

  • Document the User/xrobot.yaml configuration schema including global_settings, modules, and project-level constexprs, plus updated usage examples for xrobot_gen_main and xrobot_setup.

@sourcery-ai

sourcery-ai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds project-level constexpr support to xrobot_gen_main, hardens YAML/config structure validation, adjusts manifest parsing to preserve indentation, wires constexpr header generation into the main flow, and updates docs and versioning to reflect the new behavior.

Sequence diagram for xrobot_gen_main generation with constexpr support

sequenceDiagram
    actor Developer
    participant CLI as xrobot_gen_main
    participant Main as GenerateMain_main
    participant FS as FileSystem
    participant YAML as YAML_loader

    Developer->>CLI: invoke with --output and optional --config/--modules
    CLI->>Main: parse args and enter main()

    Main->>FS: check config_path.exists()
    alt config file exists
        Main->>YAML: _load_config_file(config_path)
        YAML-->>Main: validated_config_dict or error
    else config path specified but missing
        Main-->>Developer: [WARN] Configuration file not found
    end

    alt no modules passed on CLI
        Main->>Main: extract_modules_from_config(config_data)
        alt modules from config
            Main->>FS: verify each Module/<name>/<name>.hpp
            FS-->>Main: header exists or [WARN]
        else no modules in config
            Main->>Main: auto_discover_modules()
        end
    end

    alt config file does not exist
        Main->>Main: extract_constructor_args(modules, Modules/, config_path)
        Main->>FS: write default User/xrobot.yaml
    end

    Main->>Main: generate_xrobot_main_code(hw_var, modules, config_data)
    Main->>FS: write User/xrobot_main.hpp

    Main->>Main: _generate_constexpr_header(config_data)
    alt constexprs present and valid
        Main->>FS: write xrobot_constexpr.hpp
    else no constexprs
        Main->>Main: skip constexpr header
    end

    Main-->>Developer: [SUCCESS] messages

    rect rgb(255,230,230)
        Main->>Main: validation helpers (_require_mapping, _validate_constexpr_ref)
        Main-->>CLI: raise TypeError/ValueError/FileNotFoundError
        CLI-->>Developer: exit(1) with readable error
    end
Loading

Entity-relationship diagram for User_xrobot_yaml configuration structure

erDiagram
    CONFIG {
        string global_settings
        string constexpr_includes
        string constexprs
        string modules
    }

    GLOBAL_SETTINGS {
        int monitor_sleep_ms
    }

    CONSTEXPR_DEF {
        string name
        string type
        any value
    }

    MODULE_ENTRY {
        string id
        string name
    }

    CONSTRUCTOR_ARGS {
        string key
        any value
    }

    TEMPLATE_ARGS {
        string key
        any value
    }

    CONFIG ||--|{ GLOBAL_SETTINGS : has
    CONFIG ||--o{ CONSTEXPR_DEF : defines
    CONFIG ||--o{ MODULE_ENTRY : configures

    MODULE_ENTRY ||--o{ CONSTRUCTOR_ARGS : has
    MODULE_ENTRY ||--o{ TEMPLATE_ARGS : has

    CONSTEXPR_DEF }o--o{ CONSTRUCTOR_ARGS : referenced_as_constexpr
    CONSTEXPR_DEF }o--o{ TEMPLATE_ARGS : referenced_as_constexpr
Loading

File-Level Changes

Change Details Files
Preserve manifest YAML indentation and add constexpr reference formatting helpers used by both constructor and template arguments.
  • Stop stripping leading whitespace when collecting manifest block lines so nested YAML is preserved.
  • Introduce CONSTEXPR_NAMESPACE and helpers to detect and validate {constexpr: Name} objects in config values.
  • Extend _format_cpp_value to render constexpr references as namespaced symbols instead of aggregate initializers.
  • Add _format_template_arg to preserve raw string template arguments while still supporting constexpr references.
src/xrobot/GenerateMain.py
Generate a project-level constexpr header from new constexprs/constexpr_includes config entries and include it when present.
  • Add _generate_constexpr_header to validate constexprs/constexpr_includes structure and emit xrobot_constexpr.hpp content.
  • Write xrobot_constexpr.hpp next to the main output when constexprs is non-empty and reference it from generated module headers.
  • Enforce mapping structure and required type/value fields for each constexpr, reusing existing C++ value formatting for initialization expressions.
src/xrobot/GenerateMain.py
Tighten configuration loading and structural validation for global_settings and modules entries, surfacing clear CLI errors instead of tracebacks.
  • Add _load_config_file wrapper around yaml.safe_load that enforces a top-level mapping and wraps YAML errors with file context.
  • Introduce _require_mapping to normalize optional mapping-like sections and raise typed errors when non-mappings are supplied.
  • Validate that config, global_settings, modules, and each module entry (name/id, constructor_args, template_args) conform to the expected types and shapes in both generate_xrobot_main_code and extract_modules_from_config.
  • Change the main() control flow to wrap configuration and generation logic in a try/except and exit via argparse with a clean error message on validation failures.
src/xrobot/GenerateMain.py
Adjust module selection and config bootstrap flow around xrobot_gen_main to rely on config modules first and keep manifest-based config generation as a fallback.
  • Use the new _load_config_file when a config file exists, retaining the default path User/xrobot.yaml when no --config is given.
  • Prefer extract_modules_from_config(config_data) when --modules is omitted, only falling back to auto_discover_modules() when the config has no modules.
  • Retain the behavior of generating a default config from module manifests when the config file is missing but modules are known.
src/xrobot/GenerateMain.py
Update README documentation to describe the new constexpr configuration surface, clarified xrobot_gen_main usage, and revised xrobot_setup flow.
  • Rewrite the xrobot_gen_main section to emphasize User/xrobot.yaml as the default instance configuration, describe modules[].name-driven selection, and explain how constexprs/constexpr_includes work.
  • Add an explicit User/xrobot.yaml configuration layout example showing global_settings, constexprs, modules, constructor_args/template_args, and constexpr references.
  • Clarify the xrobot_setup section to show that it now orchestrates module fetching and delegates main generation to xrobot_gen_main using the default config path, including updated sample CLI output.
  • Tighten terminology around instance configuration vs constructor parameters and align example code with the new constexpr-based header usage.
README.md
Bump package version to reflect the new generator behavior.
  • Update pyproject.toml project.version from 0.2.8 to 0.2.9.
pyproject.toml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Jiu-xiao Jiu-xiao marked this pull request as ready for review April 19, 2026 15:04
@Jiu-xiao Jiu-xiao merged commit 1a2cc02 into XRobot2.0 Apr 19, 2026
44 checks passed
@Jiu-xiao Jiu-xiao deleted the feat/project-constexprs-20260419 branch April 19, 2026 15:04

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The constexpr support currently hardcodes both the namespace (XRobotProject) and the header name (xrobot_constexpr.hpp); consider making these configurable (via CLI flags or top-level config fields) so projects with existing naming/namespace conventions can adopt this feature without patching the generator.
  • You now have several scattered structural validations for the config (top-level mapping checks, modules item shape, global_settings, constructor_args, template_args); it might be worth centralizing this into a single _validate_config(config) helper to keep the rules consistent between generate_xrobot_main_code, extract_modules_from_config, and future callers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The constexpr support currently hardcodes both the namespace (`XRobotProject`) and the header name (`xrobot_constexpr.hpp`); consider making these configurable (via CLI flags or top-level config fields) so projects with existing naming/namespace conventions can adopt this feature without patching the generator.
- You now have several scattered structural validations for the config (top-level mapping checks, `modules` item shape, `global_settings`, `constructor_args`, `template_args`); it might be worth centralizing this into a single `_validate_config(config)` helper to keep the rules consistent between `generate_xrobot_main_code`, `extract_modules_from_config`, and future callers.

## Individual Comments

### Comment 1
<location path="src/xrobot/GenerateMain.py" line_range="78" />
<code_context>
     return manifest_data

+def _validate_constexpr_ref(name: str) -> str:
+    if not isinstance(name, str) or not re.match(r"^[A-Za-z_]\w*$", name):
+        raise ValueError(f"[ERROR] Invalid constexpr reference: {name!r}")
+    return name
</code_context>
<issue_to_address>
**issue (bug_risk):** Using `re.match` here will raise `NameError` unless `re` is imported.

To avoid this runtime NameError, add `import re` alongside the other standard-library imports in this module.
</issue_to_address>

### Comment 2
<location path="README.md" line_range="340-341" />
<code_context>
+  `modules` is the module instance list; `id` becomes the generated C++ instance name, and `name` is the module class name.
+- `constructor_args``template_args` 会按配置顺序展开到构造参数和模板参数中。
+  `constructor_args` and `template_args` are expanded into constructor arguments and template arguments in config order.
+- `{constexpr: Name}` 会展开为 `XRobotProject::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`+  `{constexpr: Name}` expands to `XRobotProject::Name`; when top-level `constexprs` exists, `xrobot_constexpr.hpp` is generated alongside the main file.
+- `@instance_id` 会被当作已有 C++ 实例名直接引用,例如 `@cam` 会展开为 `cam`+  `@instance_id` is emitted as a direct C++ instance reference, for example `@cam` expands to `cam`.
</code_context>
<issue_to_address>
**issue (typo):** Use plural verb with plural subject in "when top-level `constexprs` exist".

Since `constexprs` is plural, this should say `when top-level constexprs exist` (not `exists`).

```suggestion
- `{constexpr: Name}` 会展开为 `XRobotProject::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`。
  `{constexpr: Name}` expands to `XRobotProject::Name`; when top-level `constexprs` exist, `xrobot_constexpr.hpp` is generated alongside the main file.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

return manifest_data

def _validate_constexpr_ref(name: str) -> str:
if not isinstance(name, str) or not re.match(r"^[A-Za-z_]\w*$", name):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Using re.match here will raise NameError unless re is imported.

To avoid this runtime NameError, add import re alongside the other standard-library imports in this module.

Comment thread README.md
Comment on lines +340 to +341
- `{constexpr: Name}` 会展开为 `XRobotProject::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`。
`{constexpr: Name}` expands to `XRobotProject::Name`; when top-level `constexprs` exists, `xrobot_constexpr.hpp` is generated alongside the main file.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (typo): Use plural verb with plural subject in "when top-level constexprs exist".

Since constexprs is plural, this should say when top-level constexprs exist (not exists).

Suggested change
- `{constexpr: Name}` 会展开为 `XRobotProject::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`
`{constexpr: Name}` expands to `XRobotProject::Name`; when top-level `constexprs` exists, `xrobot_constexpr.hpp` is generated alongside the main file.
- `{constexpr: Name}` 会展开为 `XRobotProject::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`
`{constexpr: Name}` expands to `XRobotProject::Name`; when top-level `constexprs` exist, `xrobot_constexpr.hpp` is generated alongside the main file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant