Skip to content

feat: refine project constexpr generation#96

Merged
Jiu-xiao merged 3 commits into
XRobot2.0from
feat/refine-project-constexpr-generation
Apr 20, 2026
Merged

feat: refine project constexpr generation#96
Jiu-xiao merged 3 commits into
XRobot2.0from
feat/refine-project-constexpr-generation

Conversation

@Jiu-xiao

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

Copy link
Copy Markdown
Member

This PR refines the recently added project-level constexpr generation path and folds in one missing config-generation fix that is still absent from XRobot2.0.

The first problem is that auto-generated User/xrobot.yaml entries still omit stable instance ids. That breaks module-to-module references on the autogen path because downstream configs and examples expect names like BlinkLED_0, but the generated config only kept name. This PR preserves auto-generated ids in the generated config so the generated C++ instance names and config references stay aligned.

The second problem is that the current project-level constexpr path is still too rigid and slightly misleading for real use. The namespace is hard-coded, include rendering forces quoted includes, string-vs-expression intent still relies on inference, and long generated instantiations become hard to read. In addition, the generated xrobot_constexpr.hpp does not need to auto-inject module headers when it is already consumed as part of the generated entry chain.

This PR makes the constexpr generation path more explicit and easier to use:

  • keeps ProjectConstexpr as the default namespace but adds top-level constexpr_namespace override support
  • adds explicit {expr: ...} and {string: ...} forms so YAML can describe intent without relying only on parser heuristics
  • preserves raw <...> and "..." forms in constexpr_includes
  • keeps module headers in xrobot_main.hpp and limits xrobot_constexpr.hpp to explicit includes only
  • wraps long generated module instantiations across multiple lines for readability
  • bumps the package version from 0.2.9 to 0.2.10

I also updated the README so the documented config syntax matches the current generator behavior and examples.

Validation used for this branch:

  • local python3 -m compileall src/xrobot/GenerateMain.py
  • local regeneration of default and constexpr sample outputs under /tmp/xrobot_constexpr_selfcontained_local_20260419
  • Ubuntu24 real compile for the regular constexpr sample:
    • /home/xiao/runs/xrobot_cfg_refine_20260419T2358Z
  • Ubuntu24 real compile for a probe config covering custom constexpr_namespace plus {expr} / {string}:
    • /home/xiao/runs/xrobot_cfg_probe_20260420T0002Z

Summary by Sourcery

Refine project-level constexpr code generation and auto-generated module configs to make generated C++ instances, namespaces, and includes more flexible and aligned with configuration intent.

New Features:

  • Allow overriding the project constexpr namespace via a top-level constexpr_namespace setting in the config.
  • Support explicit {expr: ...} and {string: ...} markers in YAML configs to control whether values are emitted as raw C++ expressions or string literals.

Bug Fixes:

  • Preserve stable auto-generated module instance ids in generated User/xrobot.yaml so C++ instance names and config references remain consistent.

Enhancements:

  • Improve constexpr include handling to honor raw <...>/<...> or "..." forms, deduplicate includes, and keep module headers only in the main header.
  • Route all constexpr and template references through the configurable namespace and validate identifiers more robustly.
  • Reformat long generated module instantiation statements across multiple lines for better readability.

Build:

  • Bump the Python package version from 0.2.9 to 0.2.10.

Documentation:

  • Update README examples and explanations to document constexpr_namespace, {expr}/{string} usage, updated constexpr behavior, and the new include ordering.

@sourcery-ai

sourcery-ai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refines project-level constexpr generation by making the constexpr namespace configurable, adding explicit {expr}/{string} forms, preserving include and constexpr formatting consistently in generated C++, stabilizing auto-generated module instance IDs in the YAML config, improving readability of generated module instantiations, and bumping the package version and docs to match the new behavior.

Flow diagram for configurable constexpr header generation

flowchart TD
  Config["Config dict with constexpr_namespace, constexpr_includes, constexprs"]
  GenHdr["_generate_constexpr_header(config)"]
  GetNS["_get_constexpr_namespace(config)"]
  ValId["_validate_cpp_identifier(name, field_name='constexpr namespace')"]

  LoopInc["Loop over constexpr_includes"]
  FmtInc["_format_include_directive(header)"]
  Dedup["Deduplicate directives via seen_includes"]

  LoopConst["Loop over constexprs items (name, spec)"]
  ValRef["_validate_constexpr_ref(name)"]
  FmtType["Validate non-empty type"]
  FmtVal["_format_cpp_value(cpp_value, constexpr_namespace)"]

  IsDict{{"value is dict?"}}
  IsConstRef{{"_is_constexpr_ref(value)?"}}
  IsExpr{{"_is_expr_value(value)?"}}
  IsString{{"_is_string_value(value)?"}}
  DictAgg["Aggregate-init nested mapping via recursive _format_cpp_value"]

  RawExpr["_format_raw_expr(value['expr'])"]
  RawString["_format_string_literal(value['string'])"]

  IsList{{"value is list?"}}
  ListAgg["Aggregate-init list via recursive _format_cpp_value"]

  IsBool{{"value is bool?"}}
  BoolOut["Emit true/false"]

  IsStr{{"value is str?"}}
  StrInstance{{"value startswith @?"}}
  StrScope{{"Scoped name or enum?"}}
  StrNumber{{"Numeric string?"}}
  StrLit["Emit string literal via _format_string_literal"]
  StrAsIs["Emit value[1:], raw scoped name or number"]

  Other["Fallback str(value)"]

  Config --> GenHdr
  GenHdr --> GetNS --> ValId
  GetNS --> GenHdr

  GenHdr --> LoopInc --> FmtInc --> Dedup --> LoopInc

  GenHdr --> LoopConst --> ValRef --> FmtType --> FmtVal

  FmtVal --> IsDict
  IsDict -- yes --> IsConstRef
  IsConstRef -- yes --> RawConstRef["Emit constexpr_namespace::Name"] --> FmtVal
  IsConstRef -- no --> IsExpr
  IsExpr -- yes --> RawExpr --> FmtVal
  IsExpr -- no --> IsString
  IsString -- yes --> RawString --> FmtVal
  IsString -- no --> DictAgg --> FmtVal

  IsDict -- no --> IsList
  IsList -- yes --> ListAgg --> FmtVal

  IsList -- no --> IsBool
  IsBool -- yes --> BoolOut --> FmtVal

  IsBool -- no --> IsStr
  IsStr -- yes --> StrInstance
  StrInstance -- yes --> StrAsIs --> FmtVal
  StrInstance -- no --> StrScope
  StrScope -- yes --> StrAsIs --> FmtVal
  StrScope -- no --> StrNumber
  StrNumber -- yes --> StrAsIs --> FmtVal
  StrNumber -- no --> StrLit --> FmtVal

  IsStr -- no --> Other --> FmtVal

  LoopConst --> GenHdr
Loading

Flow diagram for main code generation with stable instance ids and multiline instantiation

flowchart TD
  AConf["Config dict with global_settings, modules, constexpr_namespace"]
  AMods["List of discovered module names"]

  Extract["extract_constructor_args(module_dir, modules, config)"]
  AutoIdxInit["auto_inst_index = {}"]
  ForMod["For each mod in modules"]
  BuildArgs["Build args_ordered and tmpl_ordered"]
  GenId["idx = auto_inst_index.get(mod, 0); id = f'{mod}_{idx}'"]
  BumpIdx["auto_inst_index[mod] = idx + 1"]
  MakeEntry["Create OrderedDict with id, name, constructor_args"]
  AppendEntry["Append module entry to config['modules']"]

  GenMain["generate_xrobot_main_code(hw_var, modules, config)"]
  GetNS["constexpr_namespace = _get_constexpr_namespace(config)"]
  Headers["Emit app_framework.hpp, libxr.hpp, module headers"]
  MaybeIncConst["If constexprs exists, include xrobot_constexpr.hpp"]

  BodyStart["Emit XRobotMain signature, using namespace, appmgr"]
  ForEntry["For each module entry in config['modules']"]
  MatchName{{"Entry name in modules list?"}}
  GetInstanceName["instance_name = entry['id'] (e.g. BlinkLED_0)"]

  GetCtorArgs["_require_mapping(constructor_args)"]
  FmtCtorArgs["_format_cpp_value(v, key, constexpr_namespace) for each"]

  GetTmplArgs["_require_mapping(template_args)"]
  FmtTmplArgs["_format_template_arg(v, constexpr_namespace) for each"]

  BuildStmt["_format_module_instance_statement(mod, tmpl_params, instance_name, hw_var, args_list)"]
  OneLine{{"Single-line length <= 100?"}}
  OneLineOut["Emit: static Mod<...> id(hw, appmgr, ...);"]
  NeedsWrap["Format multiline type and/or arg list"]

  LoopBody["Append statement to body"]
  MainLoop["Emit while(true) with appmgr.MonitorAll() and Thread::Sleep(monitor_sleep_ms)"]

  AConf --> Extract
  AMods --> Extract
  Extract --> AutoIdxInit --> ForMod
  ForMod --> BuildArgs --> GenId --> BumpIdx --> MakeEntry --> AppendEntry --> ForMod

  AConf --> GenMain
  AMods --> GenMain
  GenMain --> GetNS --> Headers --> MaybeIncConst --> BodyStart --> ForEntry
  ForEntry --> MatchName
  MatchName -- no --> ForEntry
  MatchName -- yes --> GetInstanceName --> GetCtorArgs --> FmtCtorArgs --> GetTmplArgs --> FmtTmplArgs --> BuildStmt

  BuildStmt --> OneLine
  OneLine -- yes --> OneLineOut --> LoopBody --> ForEntry
  OneLine -- no --> NeedsWrap --> LoopBody --> ForEntry

  ForEntry --> MainLoop
Loading

File-Level Changes

Change Details Files
Make constexpr configuration and formatting more explicit and flexible in the code generator.
  • Introduce DEFAULT_CONSTEXPR_NAMESPACE and derive the active namespace from an optional top-level constexpr_namespace key with validation of C++ identifiers.
  • Extend _format_cpp_value and _format_template_arg to accept and propagate the configured constexpr namespace and to support explicit {expr: ...} and {string: ...} YAML forms.
  • Add helpers for recognizing single-key mappings, formatting raw C++ expressions and forced string literals, and reusing formatting logic between constexpr values and template arguments.
src/xrobot/GenerateMain.py
Improve constexpr header generation and include handling.
  • Add a helper to format include directives that preserves raw <...> and "..." headers and quotes bare strings.
  • Deduplicate includes in constexpr_includes while validating that entries are non-empty strings.
  • Generate xrobot_constexpr.hpp using the configured constexpr namespace and the enhanced value formatting logic.
src/xrobot/GenerateMain.py
Stabilize and surface auto-generated module instance IDs in the generated YAML and use them in code generation.
  • Track per-module auto-instantiation indices to generate stable ids like Module_0, Module_1 when extracting constructor args.
  • Include the generated id field alongside name and constructor_args when emitting module entries.
  • Continue using the id as the C++ instance name when generating module instantiation statements.
src/xrobot/GenerateMain.py
Improve readability and layout of generated module instantiation statements in the main header/source.
  • Introduce helpers to format long template types and module instantiation statements across multiple lines with aligned arguments.
  • Refactor generate_xrobot_main_code to build argument and template argument lists using the new formatting helpers and constexpr namespace propagation.
  • Minorly normalize emitted code style (consistent spacing, comments, and while-loop braces).
src/xrobot/GenerateMain.py
Clarify README documentation for constexpr usage and include behavior.
  • Document constexpr_namespace, its default value, and how it affects {constexpr: Name} expansion.
  • Describe the new {expr: ...} and {string: ...} forms and how constexpr_includes entries are rendered, including preservation of <...>/"...".
  • Clarify that the main generated file includes module headers first and then xrobot_constexpr.hpp when constexprs are present, and update the constexpr example snippet accordingly.
README.md
Bump project version to reflect the new constexpr behavior.
  • Update the Python package version from 0.2.9 to 0.2.10 in pyproject.toml.
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 20, 2026 00:01
@Jiu-xiao Jiu-xiao merged commit e7b1d04 into XRobot2.0 Apr 20, 2026
43 checks passed
@Jiu-xiao Jiu-xiao deleted the feat/refine-project-constexpr-generation branch April 20, 2026 00:01

@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 1 issue, and left some high level feedback:

  • The _get_constexpr_namespace validation currently restricts constexpr_namespace to a single identifier (^[A-Za-z_]\w*$), which prevents using more idiomatic C++ nested namespaces like my_project::constexprs; consider relaxing this to allow namespace-qualified identifiers (e.g., permitting :: and possibly inline/anonymous namespace patterns) so users can organize constexprs in richer namespaces.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `_get_constexpr_namespace` validation currently restricts `constexpr_namespace` to a single identifier (`^[A-Za-z_]\w*$`), which prevents using more idiomatic C++ nested namespaces like `my_project::constexprs`; consider relaxing this to allow namespace-qualified identifiers (e.g., permitting `::` and possibly inline/anonymous namespace patterns) so users can organize constexprs in richer namespaces.

## Individual Comments

### Comment 1
<location path="README.md" line_range="346" />
<code_context>
+- `constexpr_namespace` 可选,用于指定生成的项目级常量命名空间;默认值为 `ProjectConstexpr`+  `constexpr_namespace` is optional and controls the generated project-level constexpr namespace; the default is `ProjectConstexpr`.
+- `{constexpr: Name}` 会展开为 `ProjectConstexpr::Name` 或你配置的 `constexpr_namespace::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`+  `{constexpr: Name}` expands to `ProjectConstexpr::Name` or your configured `constexpr_namespace::Name`; when top-level `constexprs` exists, `xrobot_constexpr.hpp` is generated alongside the main file.
+- `{expr: Code}` 会原样输出为 C++ 表达式,`{string: Text}` 会强制输出为字符串字面量。
+  `{expr: Code}` is emitted as a raw C++ expression, while `{string: Text}` forces a string literal.
</code_context>
<issue_to_address>
**nitpick (typo):** Use plural verb form with plural subject in this sentence.

Change “when top-level `constexprs` exists” to “when top-level `constexprs` exist” to agree with the plural subject.

```suggestion
  `{constexpr: Name}` expands to `ProjectConstexpr::Name` or your configured `constexpr_namespace::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.

Comment thread README.md
- `constexpr_namespace` 可选,用于指定生成的项目级常量命名空间;默认值为 `ProjectConstexpr`。
`constexpr_namespace` is optional and controls the generated project-level constexpr namespace; the default is `ProjectConstexpr`.
- `{constexpr: Name}` 会展开为 `ProjectConstexpr::Name` 或你配置的 `constexpr_namespace::Name`;若顶层存在 `constexprs`,则会额外生成 `xrobot_constexpr.hpp`。
`{constexpr: Name}` expands to `ProjectConstexpr::Name` or your configured `constexpr_namespace::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.

nitpick (typo): Use plural verb form with plural subject in this sentence.

Change “when top-level constexprs exists” to “when top-level constexprs exist” to agree with the plural subject.

Suggested change
`{constexpr: Name}` expands to `ProjectConstexpr::Name` or your configured `constexpr_namespace::Name`; when top-level `constexprs` exists, `xrobot_constexpr.hpp` is generated alongside the main file.
`{constexpr: Name}` expands to `ProjectConstexpr::Name` or your configured `constexpr_namespace::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